UNPKG

git-branch-is

Version:

Assert that the name of the current branch of a git repository has a particular value.

175 lines (152 loc) 5.52 kB
#!/usr/bin/env node /** * @copyright Copyright 2016 Kevin Locke <kevin@kevinlocke.name> * @license MIT */ 'use strict'; const { Command } = require('commander'); const gitBranchIs = require('..'); const packageJson = require('../package.json'); function collect(arg, args) { args.push(arg); return args; } /** Result from command entry points. * * @typedef {{ * code: (?number|undefined), * stdout: (?string|undefined), * stderr: (?string|undefined) * }} CommandResult * @property {?number=} code Exit code for the command. * @property {?string=} stdout Content to write to stdout. * @property {?string=} stderr Content to write to stderr. */ /** * Entry point for this command. * * @param {!Array<string>} args Command-line arguments. * @param {?function(Error, ?CommandResult=)=} callback Callback for the * command result or error. Required if <code>global.Promise</code> is not * defined. * @returns {Promise|undefined} If <code>callback</code> is not given and * <code>global.Promise</code> is defined, a <code>Promise</code> which will * resolve on completion. */ function gitBranchIsCmd(args, callback) { if (!callback && typeof Promise === 'function') { return new Promise((resolve, reject) => { gitBranchIsCmd(args, (err, result) => { if (err) { reject(err); } else { resolve(result); } }); }); } if (typeof callback !== 'function') { throw new TypeError('callback must be a function'); } // TODO: Proxy console.{error,log} and process.exit so we can return result const command = new Command() .arguments('<branch_name>') .option('-C <path>', 'run as if started in <path>') .option( '--git-arg <arg>', 'additional argument to git (can be repeated)', collect, [], ) .option('--git-dir <dir>', 'set the path to the repository') .option('--git-path <path>', 'set the path to the git binary') .option('-i, --ignore-case', 'compare/match branch_name case-insensitively') .option('-I, --invert-match', 'inverts/negates comparison') // Note: Commander.js only supports one long option per option call // https://github.com/tj/commander.js/issues/430 .option('--not', 'inverts/negates comparison (same as --invert-match)') .option('-q, --quiet', 'suppress warning message if branch differs') .option('-r, --regex', 'match branch_name as a regular expression') .option('-v, --verbose', 'print a message if the branch matches') .version(packageJson.version) .parse(args); if (command.args.length !== 1) { callback(new Error(`Exactly one argument is required.\n${ command.helpInformation()}`)); return undefined; } // -C option is cmd in options Object command.cwd = command.C; // pluralize --git-arg to cover multiple uses command.gitArgs = command.gitArg; // treat --not as an alias for --invert-match command.invertMatch = command.invertMatch || command.not; const expectedBranch = command.args[0]; let expectedBranchRegExp; if (command.regex) { try { expectedBranchRegExp = new RegExp( expectedBranch, command.ignoreCase ? 'i' : undefined, ); } catch (errRegExp) { // Benefit of avoiding unnecessary API changes outweighs style concerns // eslint-disable-next-line unicorn/no-null callback(null, { code: 2, stderr: `Error: Invalid RegExp "${expectedBranch}": ${ errRegExp}\n`, }); return undefined; } } gitBranchIs.getBranch(command, (err, currentBranch) => { if (err) { callback(err); return; } let errMsg, isMatch; if (expectedBranchRegExp) { isMatch = expectedBranchRegExp.test(currentBranch); if (command.invertMatch) { isMatch = !isMatch; } if (!isMatch && !command.quiet) { errMsg = command.invertMatch ? `Current branch "${currentBranch}" matches "${expectedBranch}".\n` : `Current branch "${currentBranch}" does not match "${ expectedBranch}".\n`; } } else { isMatch = currentBranch === expectedBranch || (command.ignoreCase && currentBranch.toUpperCase() === expectedBranch.toUpperCase()); if (command.invertMatch) { isMatch = !isMatch; } if (!isMatch && !command.quiet) { errMsg = command.invertMatch ? `Current branch is "${currentBranch}".\n` : `Current branch is "${currentBranch}", not "${expectedBranch}".\n`; } } // Benefit of avoiding unnecessary API changes outweighs style concerns // eslint-disable-next-line unicorn/no-null callback(null, { code: isMatch ? 0 : 1, stderr: errMsg && `Error: ${errMsg}`, stdout: isMatch && command.verbose ? `Current branch is "${currentBranch}".\n` : null, // eslint-disable-line unicorn/no-null }); }); return undefined; } module.exports = gitBranchIsCmd; if (require.main === module) { // This file was invoked directly. /* eslint-disable no-process-exit */ gitBranchIsCmd(process.argv, (err, result) => { const errOrResult = err || result; if (errOrResult.stdout) { process.stdout.write(errOrResult.stdout); } if (errOrResult.stderr) { process.stderr.write(errOrResult.stderr); } if (err) { process.stderr.write(`${err.name}: ${err.message}\n`); } const code = typeof errOrResult.code === 'number' ? errOrResult.code : err ? 1 : 0; process.exit(code); }); }