Skip to content

Commit

Permalink
Import shelljs as object for easier stubbing in tests
Browse files Browse the repository at this point in the history
  • Loading branch information
webpro committed Dec 20, 2018
1 parent 9380a1c commit a28c23b
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 32 deletions.
39 changes: 21 additions & 18 deletions lib/git.js
Expand Up @@ -2,7 +2,7 @@ const path = require('path');
const { EOL } = require('os');
const _ = require('lodash');
const { format } = require('./util');
const { run, runTemplateCommand } = require('./shell');
const shell = require('./shell');
const { config } = require('./config');
const { warn, logError } = require('./log');
const { GitCloneError, GitCommitError, CreateChangelogError } = require('./errors');
Expand All @@ -12,63 +12,65 @@ const noop = Promise.resolve();
const commitRefRe = /#.+$/;
const invalidPushRepoRe = /^\S+@/;

const isGitRepo = () => run('git rev-parse --git-dir', { isReadOnly: true }).then(() => true, () => false);
const isGitRepo = () => shell.run('git rev-parse --git-dir', { isReadOnly: true }).then(() => true, () => false);

const getRootDir = () => run('git rev-parse --show-toplevel', { isReadOnly: true });
const getRootDir = () => shell.run('git rev-parse --show-toplevel', { isReadOnly: true });

const isInGitRootDir = async () => path.relative(process.cwd(), await getRootDir()) === '';

const hasUpstream = () =>
run('git rev-parse --abbrev-ref --symbolic-full-name @{u}', { isReadOnly: true }).then(() => true, () => false);
shell.run('git rev-parse --abbrev-ref --symbolic-full-name @{u}', { isReadOnly: true }).then(() => true, () => false);

const getBranchName = () => run('git rev-parse --abbrev-ref HEAD', { isReadOnly: true }).catch(() => null);
const getBranchName = () => shell.run('git rev-parse --abbrev-ref HEAD', { isReadOnly: true }).catch(() => null);

const tagExists = tag =>
run(`git show-ref --tags --quiet --verify -- "refs/tags/${tag}"`, { isReadOnly: true }).then(() => true, () => false);
shell
.run(`git show-ref --tags --quiet --verify -- "refs/tags/${tag}"`, { isReadOnly: true })
.then(() => true, () => false);

const isRemoteName = remoteUrlOrName => !_.includes(remoteUrlOrName, '/');

const getRemoteUrl = (remoteUrlOrName = 'origin') =>
isRemoteName(remoteUrlOrName)
? run(`git config --get remote.${remoteUrlOrName}.url`, { isReadOnly: true }).catch(() => null)
? shell.run(`git config --get remote.${remoteUrlOrName}.url`, { isReadOnly: true }).catch(() => null)
: Promise.resolve(remoteUrlOrName);

const isWorkingDirClean = () =>
run('git diff-index --name-only HEAD --exit-code', { isReadOnly: true }).then(() => true, () => false);
shell.run('git diff-index --name-only HEAD --exit-code', { isReadOnly: true }).then(() => true, () => false);

const clone = (repo, dir) => {
const commitRef = repo.match(commitRefRe);
const branch = commitRef && commitRef[0] ? `-b ${commitRef[0].replace(/^#/, '')}` : '';
const cleanRepo = repo.replace(commitRef, '');
return run(`git clone ${cleanRepo} ${branch} --single-branch ${dir}`).catch(err => {
return shell.run(`git clone ${cleanRepo} ${branch} --single-branch ${dir}`).catch(err => {
logError(`Unable to clone ${repo}`);
throw new GitCloneError(err);
});
};

const stage = file => {
const files = _.castArray(file).join(' ');
return run(`git add ${files}`).catch(err => {
return shell.run(`git add ${files}`).catch(err => {
debugGit(err);
warn(`Could not stage ${files}`);
});
};

const stageDir = ({ baseDir = '.', addUntrackedFiles }) =>
run(`git add ${baseDir} ${addUntrackedFiles ? '--all' : '--update'}`);
shell.run(`git add ${baseDir} ${addUntrackedFiles ? '--all' : '--update'}`);

const reset = file => {
const files = _.castArray(file).join(' ');
return run(`git checkout HEAD -- ${files}`).catch(err => {
return shell.run(`git checkout HEAD -- ${files}`).catch(err => {
debugGit(err);
warn(`Could not reset ${files}`);
});
};

const status = () => run('git status --short --untracked-files=no', { isReadOnly: true });
const status = () => shell.run('git status --short --untracked-files=no', { isReadOnly: true });

const commit = ({ path = '.', message, args = '' }) =>
runTemplateCommand(`git commit --message="${message}" ${args}`, path).catch(err => {
shell.runTemplateCommand(`git commit --message="${message}" ${args}`, path).catch(err => {
debugGit(err);
if (/nothing (added )?to commit/.test(err)) {
warn('No changes to commit. The latest commit will be tagged.');
Expand All @@ -78,14 +80,14 @@ const commit = ({ path = '.', message, args = '' }) =>
});

const tag = ({ name, annotation, args = '' }) => {
return runTemplateCommand(`git tag --annotate --message="${annotation}" ${args} ${name}`).catch(err => {
return shell.runTemplateCommand(`git tag --annotate --message="${annotation}" ${args} ${name}`).catch(err => {
debugGit(err);
warn(`Could not tag. Does tag "${format(name)}" already exist?`);
});
};

const getLatestTag = () =>
run('git describe --tags --abbrev=0', { isReadOnly: true }).then(
shell.run('git describe --tags --abbrev=0', { isReadOnly: true }).then(
stdout => {
return stdout ? stdout.replace(/^v/, '') : null;
},
Expand All @@ -96,11 +98,12 @@ const push = async ({ pushRepo = '', hasUpstreamBranch, args = '' } = {}) => {
const remoteName = pushRepo && isRemoteName(pushRepo) ? pushRepo : 'origin';
const setUpstream = hasUpstreamBranch === false ? `-u ${remoteName} ${await getBranchName()}` : '';
const repository = setUpstream ? '' : invalidPushRepoRe.test(pushRepo) ? 'origin' : pushRepo;
return run(`git push --follow-tags ${args} ${repository} ${setUpstream}`);
return shell.run(`git push --follow-tags ${args} ${repository} ${setUpstream}`);
};

const runChangelogCommand = command =>
run(command, { isReadOnly: true })
shell
.run(command, { isReadOnly: true })
.then(stdout => {
if (config.isVerbose) {
process.stdout.write(EOL);
Expand Down
30 changes: 16 additions & 14 deletions lib/npm.js
@@ -1,6 +1,6 @@
const semver = require('semver');
const _ = require('lodash');
const { run } = require('./shell');
const shell = require('./shell');
const { warn } = require('./log');
const { config } = require('./config');

Expand All @@ -19,20 +19,22 @@ const publish = (options, pkgName = '', otpPrompt) => {
const accessArg = isScopedPkg && access ? `--access ${access}` : '';
const otpArg = otp ? `--otp ${otp}` : '';
const dryRunArg = config.isDryRun ? '--dry-run' : '';
return run(`npm publish ${publishPath} --tag ${tag} ${accessArg} ${otpArg} ${dryRunArg}`, {
isReadOnly: true,
verbose: config.isVerbose || config.isDryRun
}).catch(err => {
if (/one-time pass/.test(err)) {
if (otp != null) {
warn('The provided OTP is incorrect or has expired.');
return shell
.run(`npm publish ${publishPath} --tag ${tag} ${accessArg} ${otpArg} ${dryRunArg}`, {
isReadOnly: true,
verbose: config.isVerbose || config.isDryRun
})
.catch(err => {
if (/one-time pass/.test(err)) {
if (otp != null) {
warn('The provided OTP is incorrect or has expired.');
}
if (otpPrompt) {
return otpPrompt(otp => publish(Object.assign(options, { otp }), otpPrompt));
}
}
if (otpPrompt) {
return otpPrompt(otp => publish(Object.assign(options, { otp }), pkgName, otpPrompt));
}
}
throw err;
});
throw err;
});
};

module.exports = {
Expand Down

0 comments on commit a28c23b

Please sign in to comment.