UNPKG

git-branch-is

Version:

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

171 lines (150 loc) 5.22 kB
/** * @copyright Copyright 2016 Kevin Locke <kevin@kevinlocke.name> * @license MIT */ 'use strict'; const { execFile } = require('child_process'); /** Options for {@link gitBranchIs}. * * @typedef {{ * cwd: (?string|undefined), * gitArgs: (Array|undefined), * gitDir: (?string|undefined), * gitPath: (string|undefined) * }} GitBranchIsOptions * @property {?string=} cwd Current working directory where the branch name is * tested. * @property {Array=} gitArgs Extra arguments to pass to git. * @property {?string=} gitDir Path to the repository (i.e. * <code>--git-dir=</code> option to <code>git</code>). * @property {string=} gitPath Git binary name or path to use (default: * <code>'git'</code>). */ const GitBranchIsOptions = { cwd: '', gitArgs: [], gitDir: '', gitPath: 'git', }; /** Checks that the current branch of a git repository has a given name. * * @param {string|function(string)} branchNameOrTest Expected name of * current branch or a test function to apply to the branch name. * @param {?GitBranchIsOptions=} options Options. * @param {?function(Error, boolean=)=} callback Callback function called * with the return value of <code>branchNameOrTest</code> if it is a function, * or the result of identity checking <code>branchNameOrTest</code> to the * current branch name. * @returns {Promise|undefined} If <code>callback</code> is not given, a * <code>Promise</code> with the return value of <code>branchNameOrTest</code> * if it is a function, or the result of identity checking * <code>branchNameOrTest</code> to the current branch name. */ function gitBranchIs(branchNameOrTest, options, callback) { if (!callback && typeof options === 'function') { callback = options; options = undefined; } if (!callback) { return new Promise((resolve, reject) => { gitBranchIs(branchNameOrTest, options, (err, result) => { if (err) { reject(err); } else { resolve(result); } }); }); } if (typeof callback !== 'function') { throw new TypeError('callback must be a function'); } if (options !== undefined && typeof options !== 'object') { process.nextTick(callback, new TypeError('options must be an object')); return undefined; } gitBranchIs.getBranch(options, (err, currentBranch) => { if (err) { callback(err); return; } let result; try { result = currentBranch === branchNameOrTest || (typeof branchNameOrTest === 'function' && branchNameOrTest(currentBranch)); } catch (errTest) { callback(errTest); return; } callback(null, result); // eslint-disable-line unicorn/no-null }); return undefined; } /** Gets the name of the current (i.e. checked out) branch of a git repository. * * @param {?GitBranchIsOptions=} options Options. * @param {?function(Error, string=)=} callback Callback function called * with the current branch name, empty string if not on a branch, or * <code>Error</code> if there was an error determining the branch name. * @returns {Promise|undefined} If <code>callback</code> is not given, a * <code>Promise</code> with the current branch name, empty string if not on a * branch, or <code>Error</code> if there was an error determining the branch * name. */ gitBranchIs.getBranch = function getBranch(options, callback) { if (!callback && typeof options === 'function') { callback = options; options = undefined; } if (!callback) { return new Promise((resolve, reject) => { getBranch(options, (err, result) => { if (err) { reject(err); } else { resolve(result); } }); }); } if (typeof callback !== 'function') { throw new TypeError('callback must be a function'); } if (options && typeof options !== 'object') { process.nextTick(callback, new TypeError('options must be an Object')); return undefined; } const combinedOpts = { ...GitBranchIsOptions, ...options, }; const gitArgs = combinedOpts.gitArgs ? Array.prototype.slice.call(combinedOpts.gitArgs, 0) : []; if (combinedOpts.gitDir) { gitArgs.unshift(`--git-dir=${combinedOpts.gitDir}`); } // Note: --quiet causes symbolic-ref to exit with code 1 and no error // instead of code 128 and "ref %s is not a symbolic ref" when not on a // branch. gitArgs.push('symbolic-ref', '--quiet', '--short', 'HEAD'); try { execFile( combinedOpts.gitPath, gitArgs, { cwd: combinedOpts.cwd }, (errExec, stdout, stderr) => { if (errExec) { if (errExec.code === 1 && !stdout && !stderr) { // Not on a branch callback(null, ''); // eslint-disable-line unicorn/no-null } else { callback(errExec); } return; } // Note: ASCII space and control characters are forbidden in names // https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html callback(null, stdout.trimEnd()); // eslint-disable-line unicorn/no-null }, ); } catch (errExec) { process.nextTick(callback, errExec); return undefined; } return undefined; }; module.exports = gitBranchIs;