diff --git a/bin/sake.js b/bin/sake.js index b8e856d..4911af4 100755 --- a/bin/sake.js +++ b/bin/sake.js @@ -27,5 +27,9 @@ const args = [ '--cwd', process.cwd() ])) -// fire up gulp -spawn('node', args, { cwd: process.cwd(), stdio: 'inherit' }) +const child = spawn('node', args, { cwd: process.cwd(), stdio: 'inherit' }) + +// we need the exit code of the child process to propagate up to the main process +child.on('exit', function(code) { + process.exitCode = code +}) diff --git a/helpers/arguments.js b/helpers/arguments.js new file mode 100644 index 0000000..4d85486 --- /dev/null +++ b/helpers/arguments.js @@ -0,0 +1,33 @@ +import minimist from 'minimist' + +/** + * Determines if the command is being run in "non-interactive mode". If true, we should never present with prompts. + * @returns {boolean} + */ +export function isNonInteractive() +{ + return process.argv.includes('--non-interactive'); +} + +/** + * Whether this is a dry run deployment. If true, the deploy to WooCommerce will not actually happen. + * @returns {boolean} + */ +export const isDryRunDeploy = () =>{ + return process.argv.includes('--dry-run'); +} + +/** + * The new version of the plugin to deploy. This can be provided via arguments instead of using the prompt. + * This will likely be supplied when using non-interactive mode (e.g. CI/CD). + * @returns {string|null} The version of the plugin to be deployed, if provided. + */ +export const newPluginVersion = () => { + const argv = minimist(process.argv.slice(2)) + + return argv['new-version'] || null; +} + +export const skipLinting = () => { + return process.argv.includes('--skip-linting'); +} diff --git a/tasks/compile.js b/tasks/compile.js index 1fb1de0..87569f8 100644 --- a/tasks/compile.js +++ b/tasks/compile.js @@ -18,6 +18,7 @@ import { lintPhpTask } from './lint.js' import { minifyImagesTask } from './imagemin.js' import { makepotTask } from './makepot.js' import { stylesTask } from './styles.js' +import { skipLinting } from '../helpers/arguments.js'; const sass = gulpSaas(dartSaas); /************************** Scripts */ @@ -152,7 +153,12 @@ compileStyles.displayName = 'compile:styles' // Compile all plugin assets const compile = (done) => { // default compile tasks - let tasks = [lintPhpTask, 'scripts', stylesTask, minifyImagesTask] // NOTE: do not import the `scripts` constant here, otherwise it creates a circular dependency + let tasks = ['scripts', stylesTask, minifyImagesTask] // NOTE: do not import the `scripts` constant here, otherwise it creates a circular dependency + + // lint PHP unless told not to + if (! skipLinting) { + tasks.push(lintPhpTask) + } // unless exclusively told not to, generate the POT file as well if (!sake.options.skip_pot) { diff --git a/tasks/deploy.js b/tasks/deploy.js index a7d8fd4..0a6d9fd 100644 --- a/tasks/deploy.js +++ b/tasks/deploy.js @@ -33,6 +33,7 @@ import { zipTask } from './zip.js' import { validateReadmeHeadersTask } from './validate.js' import { lintScriptsTask, lintStylesTask } from './lint.js' import { copyWcRepoTask, copyWpAssetsTask, copyWpTagTask, copyWpTrunkTask } from './copy.js' +import { isDryRunDeploy, isNonInteractive } from '../helpers/arguments.js'; let validatedEnvVariables = false @@ -44,7 +45,7 @@ function validateEnvVariables () { let variables = ['GITHUB_API_KEY', 'GITHUB_USERNAME', 'SAKE_PRE_RELEASE_PATH'] if (sake.config.deploy.type === 'wc') { - variables = variables.concat(['WC_CONSUMER_KEY', 'WC_CONSUMER_SECRET']) + variables = variables.concat(['WC_USERNAME', 'WC_APPLICATION_PASSWORD']) } if (sake.config.deploy.type === 'wp') { @@ -110,16 +111,28 @@ const deployTask = (done) => { deployCreateReleasesTask, ] - if (sake.config.deploy.wooId && sake.config.deploy.type === 'wc') { - tasks.push(promptWcUploadTask) - } + if (isDryRunDeploy()) { + tasks.push(function(cb) { + log.info('Dry run deployment successful') - if (sake.config.deploy.type === 'wp') { - tasks.push(deployToWpRepoTask) + return cb() + }) + } else { + if (sake.config.deploy.wooId && sake.config.deploy.type === 'wc') { + tasks.push(promptWcUploadTask) + } + + if (sake.config.deploy.type === 'wp') { + tasks.push(deployToWpRepoTask) + } } - // finally, create a docs issue, if necessary - tasks.push(gitHubCreateDocsIssueTask) + // finally, create a docs issue, if necessary, but only in interactive mode + if (!isNonInteractive()) { + tasks.push(gitHubCreateDocsIssueTask) + } else { + log.info('Running in non-interactive mode, skipping docs issue creation') + } return gulp.series(tasks)(done) } diff --git a/tasks/prompt.js b/tasks/prompt.js index 94f4392..eb8266b 100644 --- a/tasks/prompt.js +++ b/tasks/prompt.js @@ -6,6 +6,7 @@ import _ from 'lodash' import sake from '../lib/sake.js' import gulp from 'gulp' import { wcDeployTask } from './wc.js' +import { isNonInteractive, newPluginVersion } from '../helpers/arguments.js' function filterIncrement (value) { if (value[1] === 'custom') { @@ -39,6 +40,12 @@ function getDefault () { * Internal task for prompting the deploy action */ const promptDeployTask = (done) => { + if (newPluginVersion()) { + log.info(`Using new version from arguments: ${newPluginVersion()}`) + sake.options = _.merge(sake.options, {version: newPluginVersion()}) + return done() + } + let currentVersion = sake.getPluginVersion() inquirer.prompt([ @@ -102,13 +109,21 @@ promptDeployTask.displayName = 'prompt:deploy' * Internal task for prompting whether to upload the plugin to WooCommerce */ const promptWcUploadTask = (done) => { + const runWcDeployTask = () => gulp.series(wcDeployTask)(done); + + // Skip the prompt if in non-interactive mode + if (isNonInteractive()) { + log.info('Running in non-interactive mode, automatically uploading to WooCommerce.com') + return runWcDeployTask(); + } + inquirer.prompt([{ type: 'confirm', name: 'upload_to_wc', message: 'Upload plugin to WooCommerce.com?' }]).then((answers) => { if (answers.upload_to_wc) { - gulp.series(wcDeployTask)(done) + runWcDeployTask(); } else { log.error(chalk.red('Skipped uploading to WooCommerce.com')) done() @@ -121,6 +136,12 @@ promptWcUploadTask.displayName = 'prompt:wc_upload' * Internal task for prompting whether the release has been tested */ const promptTestedReleaseZipTask = (done) => { + // Skip the prompt if in non-interactive mode + if (isNonInteractive()) { + log.info('Running in non-interactive mode, skipping release zip testing confirmation') + return done() + } + inquirer.prompt([{ type: 'confirm', name: 'tested_release_zip',