diff --git a/USAGE.md b/USAGE.md index 12826a7..b0dda2b 100644 --- a/USAGE.md +++ b/USAGE.md @@ -22,6 +22,27 @@ Options: ``` +## `wiby github-workflow install` + + + +Install the bundled versions of the wiby workflows. Will overwrite existing +`.github/workflows/wiby.yaml`, if any. + + + + +## `wiby github-workflow outdated` + + + +Check if you have the bundled version of wiby Github workflow installed. Will +exit with zero if .github/workflows/wiby.yaml is up to date, and non-zero if it +is outdated. + + + + ## `wiby result` diff --git a/bin/commands/github-workflow.js b/bin/commands/github-workflow.js new file mode 100644 index 0000000..22eae2d --- /dev/null +++ b/bin/commands/github-workflow.js @@ -0,0 +1,8 @@ +'use strict' + +exports.desc = 'wiby Github Workflow maintenance tools' + +exports.builder = (yargs) => yargs + .commandDir('./github-workflow') + .demandCommand() + .help() diff --git a/bin/commands/github-workflow/install.js b/bin/commands/github-workflow/install.js new file mode 100644 index 0000000..69165d5 --- /dev/null +++ b/bin/commands/github-workflow/install.js @@ -0,0 +1,23 @@ +'use strict' + +const fs = require('fs') +const path = require('path') + +exports.desc = 'Install the bundled versions of the wiby workflows. Will overwrite existing `.github/workflows/wiby.yaml`, if any.' + +exports.handler = async (params) => { + const packageRoot = process.env.INIT_CWD || process.cwd() + + const workflowsPath = path.join(packageRoot, '.github', 'workflows') + const sourceWibyYaml = path.join(__dirname, '..', '..', '..', '.github', 'workflows', 'wiby.yaml') + const destWibyYaml = path.join(workflowsPath, 'wiby.yaml') + + console.log(`Copying ${sourceWibyYaml} to ${workflowsPath}`) + + if (!fs.existsSync(workflowsPath)) { + console.error(`${workflowsPath} folder does not exist.`) + process.exit(1) + } + + fs.copyFileSync(sourceWibyYaml, destWibyYaml) +} diff --git a/bin/commands/github-workflow/outdated.js b/bin/commands/github-workflow/outdated.js new file mode 100644 index 0000000..27525aa --- /dev/null +++ b/bin/commands/github-workflow/outdated.js @@ -0,0 +1,29 @@ +'use strict' + +const fs = require('fs') +const path = require('path') + +exports.desc = 'Check if you have the bundled version of wiby Github workflow installed. Will exit with zero if .github/workflows/wiby.yaml is up to date, and non-zero if it is outdated.' + +exports.handler = async (params) => { + const packageRoot = process.env.INIT_CWD || process.cwd() + + const workflowsPath = path.join(packageRoot, '.github', 'workflows') + const sourceWibyYaml = path.join(__dirname, '..', '..', '..', '.github', 'workflows', 'wiby.yaml') + const destWibyYaml = path.join(workflowsPath, 'wiby.yaml') + + if (!fs.existsSync(destWibyYaml)) { + console.error(`${destWibyYaml} not found. Use \`wiby github-workflow install\` to install it.`) + process.exit(1) + } + + const expectedContents = fs.readFileSync(sourceWibyYaml) + const actualContents = fs.readFileSync(destWibyYaml) + + if (Buffer.compare(expectedContents, actualContents) !== 0) { + console.error(`${destWibyYaml} is not the same as the bundled version at ${sourceWibyYaml}. Use \`wiby github-workflow install\` to install it.`) + process.exit(1) + } + + console.log(`${destWibyYaml} is the same as the bundled version.`) +} diff --git a/bin/generate-usage.js b/bin/generate-usage.js index 93d0536..6b7d441 100755 --- a/bin/generate-usage.js +++ b/bin/generate-usage.js @@ -15,8 +15,8 @@ const fs = require('fs') /** * Parses wiby --help output and returns block with commands list */ -const getGeneralHelpOutput = () => { - const helpOutput = execSync(`${wibyCommand} --help`, { cwd: cwd }).toString() +const getGeneralHelpOutput = (commandWithSubCommands = '') => { + const helpOutput = execSync(`${wibyCommand} ${commandWithSubCommands}--help`, { cwd: cwd }).toString() const helpParseResult = /(Commands:\n)([\S\s]+)(Options:)/.exec(helpOutput) if (helpParseResult !== null) { @@ -29,13 +29,20 @@ const getGeneralHelpOutput = () => { /** * Parses commands list block ands returns array of commands names */ -const parseCommandsListOutput = (commandsOutput) => { +const parseCommandsListOutput = (commandsOutput, commandWithSubCommands = '') => { // parse commands list - const re = /^ {2}wiby ([\w]+)/gm + const re = new RegExp(`^ {2}wiby ${commandWithSubCommands}([\\w-]+)`, 'gm') const commandsList = [] let commandsParseResult while ((commandsParseResult = re.exec(commandsOutput)) !== null) { - commandsList.push(commandsParseResult[1]) + const [, command] = commandsParseResult + if (command === 'github-workflow') { + const subCommandsOutput = getGeneralHelpOutput(`${command} `) + const subCommandList = parseCommandsListOutput(subCommandsOutput, `${command} `) + commandsList.push(...subCommandList.map((subCommand) => `${command} ${subCommand}`)) + } else { + commandsList.push(command) + } } return commandsList @@ -66,7 +73,7 @@ const renderCommand = (command) => { return ` ## \`wiby ${command.get('commandName')}\` -${command.get('help').replace(/^wiby.*$/m, '').replace(/Options:(.+)$/s, '```\n$&\n```')} +${command.get('help').replace(/^wiby.*$/m, '').replace(/Options:\s+$/, '').replace(/Options:(.+)$/s, '```\n$&\n```')} ` } diff --git a/test/cli/github-workflow-install.js b/test/cli/github-workflow-install.js new file mode 100644 index 0000000..8805744 --- /dev/null +++ b/test/cli/github-workflow-install.js @@ -0,0 +1,67 @@ +'use strict' + +const childProcess = require('child_process') +const fs = require('fs') +const path = require('path') +const tap = require('tap') + +const gitFixture = require('../fixtures/git') + +const wibyCommand = path.join(__dirname, '..', '..', 'bin', 'wiby') + +tap.test('github-workflow install command', async (tap) => { + tap.beforeEach(async () => { + gitFixture.init() + }) + + tap.test('should copy wiby.yaml to the .github/workflows folder', async (tap) => { + const workflowsPath = path.join(process.cwd(), '.github', 'workflows') + const wibyYamlPath = path.join(workflowsPath, 'wiby.yaml') + const contentsBefore = 'should be overwritten with new version' + + fs.mkdirSync(workflowsPath, { recursive: true }) + fs.writeFileSync(wibyYamlPath, contentsBefore) + + childProcess.execSync(`${wibyCommand} github-workflow install`, { + env: { + ...process.env, + INIT_CWD: '' + } + }) + + tap.notEqual(fs.readFileSync(wibyYamlPath).toString(), contentsBefore) + }) + + tap.test('should copy wiby.yaml to the $INIT_CWD/.github/workflows folder', async (tap) => { + const initCwd = path.join(process.cwd(), 'some-other-place') + const workflowsPath = path.join(initCwd, '.github', 'workflows') + const wibyYamlPath = path.join(workflowsPath, 'wiby.yaml') + const contentsBefore = 'should be overwritten with new version' + + fs.mkdirSync(workflowsPath, { recursive: true }) + fs.writeFileSync(wibyYamlPath, contentsBefore) + + childProcess.execSync(`${wibyCommand} github-workflow install`, { + env: { + ...process.env, + INIT_CWD: initCwd + } + }) + + tap.notEqual(fs.readFileSync(wibyYamlPath).toString(), contentsBefore) + }) + + tap.test('should throw when the workflows path does not exist', async (tap) => { + try { + childProcess.execSync(`${wibyCommand} github-workflow install`, { + env: { + ...process.env, + INIT_CWD: '' + } + }) + tap.fail('Should fail before reaching here') + } catch (err) { + tap.include(err.message, '/.github/workflows folder does not exist.') + } + }) +}) diff --git a/test/cli/github-workflow-outdated.js b/test/cli/github-workflow-outdated.js new file mode 100644 index 0000000..2d8849c --- /dev/null +++ b/test/cli/github-workflow-outdated.js @@ -0,0 +1,88 @@ +'use strict' + +const childProcess = require('child_process') +const fs = require('fs') +const path = require('path') +const tap = require('tap') + +const gitFixture = require('../fixtures/git') + +const wibyCommand = path.join(__dirname, '..', '..', 'bin', 'wiby') + +tap.test('github-workflow outdated command', async (tap) => { + tap.beforeEach(async () => { + gitFixture.init() + }) + + tap.test('should fail when wiby.yaml is missing', async (tap) => { + try { + childProcess.execSync(`${wibyCommand} github-workflow outdated`, { + env: { + ...process.env, + INIT_CWD: '' + } + }) + tap.fail('Should fail before reaching here') + } catch (err) { + tap.include(err.message, '/.github/workflows/wiby.yaml not found. Use `wiby github-workflow install` to install it.') + } + }) + + tap.test('should fail when wiby.yaml has the wrong contents', async (tap) => { + const workflowsPath = path.join(process.cwd(), '.github', 'workflows') + const wibyYamlPath = path.join(workflowsPath, 'wiby.yaml') + const contentsBefore = 'should be overwritten with new version' + + fs.mkdirSync(workflowsPath, { recursive: true }) + fs.writeFileSync(wibyYamlPath, contentsBefore) + + try { + childProcess.execSync(`${wibyCommand} github-workflow outdated`, { + env: { + ...process.env, + INIT_CWD: '' + } + }) + tap.fail('Should fail before reaching here') + } catch (err) { + tap.include(err.message, '/.github/workflows/wiby.yaml is not the same as the bundled version') + } + }) + + tap.test('should pass when wiby.yaml has the same contents', async (tap) => { + const originalContents = fs.readFileSync(path.join(__dirname, '..', '..', '.github', 'workflows', 'wiby.yaml')) + const workflowsPath = path.join(process.cwd(), '.github', 'workflows') + const wibyYamlPath = path.join(workflowsPath, 'wiby.yaml') + + fs.mkdirSync(workflowsPath, { recursive: true }) + fs.writeFileSync(wibyYamlPath, originalContents) + + const result = childProcess.execSync(`${wibyCommand} github-workflow outdated`, { + env: { + ...process.env, + INIT_CWD: '' + } + }).toString() + + tap.include(result, 'wiby.yaml is the same as the bundled version.') + }) + + tap.test('should pass when wiby.yaml has the same contents in $INIT_CWD', async (tap) => { + const originalContents = fs.readFileSync(path.join(__dirname, '..', '..', '.github', 'workflows', 'wiby.yaml')) + const initCwd = path.join(process.cwd(), 'some-other-place') + const workflowsPath = path.join(initCwd, '.github', 'workflows') + const wibyYamlPath = path.join(workflowsPath, 'wiby.yaml') + + fs.mkdirSync(workflowsPath, { recursive: true }) + fs.writeFileSync(wibyYamlPath, originalContents) + + const result = childProcess.execSync(`${wibyCommand} github-workflow outdated`, { + env: { + ...process.env, + INIT_CWD: initCwd + } + }).toString() + + tap.include(result, 'wiby.yaml is the same as the bundled version.') + }) +}) diff --git a/test/cli/result.js b/test/cli/result.js index 8afabb7..afff27c 100644 --- a/test/cli/result.js +++ b/test/cli/result.js @@ -19,7 +19,7 @@ tap.test('result command', async (tap) => { tap.test('result command should fail when config and dependent provided', async (tap) => { try { - childProcess.execSync(`${wibyCommand} result --config=.wiby.json --dependent="https://github.com/wiby-test/fakeRepo"`).toString() + childProcess.execSync(`${wibyCommand} result --config=.wiby.json --dependent="https://github.com/wiby-test/fakeRepo"`) tap.fail() } catch (err) { tap.equal(true, err.message.includes('Arguments dependent and config are mutually exclusive'))