function fromCli(args) { return execute(config.parseArgs(args)); }
...
const release = require('../lib/release'),
args = [].slice.call(process.argv, 2),
isDebug = args.indexOf('--debug') !== -1;
var exitCode = 0;
release.cli(args).then(function() {
process.exit(exitCode);
}).catch(function(err) {
exitCode = 1;
if(!isDebug) {
console.error(err);
} else {
throw new Error(err);
...
function execute(opts) { config.mergeOptions(opts); if(config.isShowVersion) { cli.version(); } else if(config.isShowHelp) { cli.help(); } else { if(config.isForce) { log.warn('Using --force, I sure hope you know what you are doing.'); } if(config.isDebug) { require('when/monitor/console'); } log.debugDir(config.options); return tasks.run(config.options).catch(error => { log.error(error); if(config.isDebug) { throw error; } }); } return noop; }
n/a
help = function () { log.log(helpText); }
n/a
version = function () { log.log(`v${version}`); }
n/a
function clone(repo, dir) { const commitRef = repo.match(commitRefRe), branch = commitRef && commitRef[0] ? commitRef[0].replace(/^\#/, '') : 'master'; repo = repo.replace(commitRef, ''); return sequence([ run.bind(null, 'rm', '-rf', dir), run.bind(null, 'git', 'clone', repo, '-b', branch, '--single-branch', dir) ]); }
n/a
function commit(path, message, version) { return run( 'git', 'commit', config.isForce ? '--allow-empty' : '', `--message="${util.format(message, version)}"`, path ).catch(err => { log.debug(err); log.warn('Nothing to commit. The latest commit will be tagged.'); }); }
n/a
function getChangelog(options) { function runChangelogCommand(command) { return run(command).then(result => { process.stdout.write('\n'); config.setRuntimeOption('changelog', result.output); return options; }); } if(options.changelogCommand) { if(options.changelogCommand.match(/\[REV_RANGE\]/)) { const previousVersion = config.getRuntimeOption('previousVersion'); const previousTag = util.format(options.src.tagName, previousVersion); return tagExists(previousTag).then(hasTag => { const command = options.changelogCommand.replace(/\[REV_RANGE\]/, hasTag ? `${previousTag}...HEAD` : ''); return runChangelogCommand(command); }).catch(err => { log.warn('Probably the current version in package.json is not a known tag in the repository.'); throw new Error(`Could not create changelog from latest tag (${previousTag}) to HEAD.`); }); } else { return runChangelogCommand(options.changelogCommand); } } else { return noop; } }
...
throw new Error('Unable to get remote Git url.')
});
}
function getChangelog() {
const options = config.options;
if(options.github.release) {
return git.getChangelog(options);
}
}
function checkGithubToken() {
const options = config.options;
if(options.github.release) {
const token = git.getGithubToken(options.github.tokenRef);
...
function getGithubToken(tokenRef) { const token = process.env[tokenRef]; config.setRuntimeOption('github_token', token); return token; }
...
return git.getChangelog(options);
}
}
function checkGithubToken() {
const options = config.options;
if(options.github.release) {
const token = git.getGithubToken(options.github.tokenRef);
if(!token) {
throw new Error(`About to release to GitHub, but ${options.github.tokenRef} environment variable not set`);
}
}
}
function releaseSourceRepo() {
...
function getLatestTag() { return run('!git', 'describe --tags --abbrev=0').then(result => { const latestTag = result && result.output ? result.output.trim() : null; return latestTag; }); }
...
function parseVersion() {
const options = config.options;
const version = util.isValidVersion(options.increment) ? options.increment : options.npm.version;
if(!version) {
return git.getLatestTag().then(tag => {
if(tag) {
const nextVersion = util.increment(tag, options.increment, options.prereleaseId);
log.bold(util.format('Latest tag: %s. Next version: %s', tag, nextVersion));
config.setRuntimeOption('previousVersion', tag);
config.setRuntimeOption('version', nextVersion);
} else {
throw new Error('Error detecting current version from latest tag.');
...
function getRemoteUrl() { return run('!git', 'config --get remote.origin.url').then(result => { if(result && result.output) { return result.output.trim(); } throw new Error('Could not get remote Git url.'); }); }
...
} else {
config.setRuntimeOption('previousVersion', version);
config.setRuntimeOption('version', util.increment(version, options.increment, options.prereleaseId));
}
}
function setRemoteGitUrl() {
return git.getRemoteUrl().then(remoteUrl => {
config.setRuntimeOption('remoteUrl', remoteUrl);
}).catch(err => {
throw new Error('Unable to get remote Git url.')
});
}
function getChangelog() {
...
function hasChanges(repo) { // Inverted: reject if run promise is resolved (i.e. `git diff-index` returns exit code 0) return when.promise(resolve => { run('!git', 'diff-index --name-only HEAD --exit-code').then(() => { if(!config.isDryRun) { config.setRuntimeOption(`${repo}_has_changes`, false); log.warn(`Nothing to commit in ${repo} repo. The latest commit will be tagged.`); } resolve(); }).catch(resolve); }); }
n/a
function isGitRepo() { return run('!git', 'rev-parse --git-dir'); }
n/a
function isWorkingDirClean(requireCleanWorkingDir) { return requireCleanWorkingDir ? run('!git', 'diff-index --name-only HEAD --exit-code').catch(() => { throw new Error('Working dir must be clean.'); }) : noop; }
n/a
function push(remoteUrl, pushUrl) { const repository = pushUrl || ''; return run('git', 'push', repository).catch(err => { log.error('Please make sure an upstream remote repository is configured for the current branch. Example commands:\n' + `git remote add origin ${remoteUrl}\n` + 'git push --set-upstream origin master'); throw new Error(err); }); }
...
repo.stageDir,
repo.hasChanges
];
if(options.dist.repo) {
// Before committing to src repo, do some potentially problematic dist repo tasks.
const distRepoTasks = getDistRepoTasks(options);
executeTasks.push(distRepoTasks.clone);
executeTasks.push(distRepoTasks.copy);
executeTasks.push(distRepoTasks.pushd);
executeTasks.push(distRepoTasks.bump);
executeTasks.push(distRepoTasks.beforeStageCommand);
executeTasks.push(distRepoTasks.stageDir);
executeTasks.push(distRepoTasks.hasChanges);
executeTasks.push(distRepoTasks.popd);
...
function pushTags(version, pushUrl) { const repository = pushUrl || ''; return run( 'git', 'push', '--follow-tags', config.isForce ? '--force' : '', repository ).catch(() => { log.error(`Could not push tag(s). Does tag "${version}" already exist? Use --force to move a tag.`); }); }
n/a
function release(options, remoteUrl, tagName) { const repo = repoPathParse(remoteUrl); const version = config.getRuntimeOption('version'); log.execution('node-github releases#createRelease', repo.repository); const githubClient = initGithubClient(repo), attempts = 3; var success = false; if(!config.isDryRun) { return when.iterate( attempt => attempt + 1, attempt => success || attempt === attempts, attempt => when.promise(resolve => { githubClient.repos.createRelease({ owner: repo.owner, repo: repo.project, tag_name: util.format(tagName, version), name: util.format(options.github.releaseName, version), body: config.getRuntimeOption('changelog'), prerelease: options.github.preRelease }, (err, response) => { if(err) { log[attempt + 1 < attempts ? 'warn' : 'error'](`${err.defaultMessage} (Attempt ${attempt + 1} of ${attempts})`); log[attempt + 1 < attempts ? 'warn' : 'error'](err.message); } else { log.execution('node-github', response.meta.location, response.tag_name, response.name); log.verbose(response.body); success = true; } resolve(); }); }), 0 ); } else { return noop; } }
n/a
function stage(file) { if(file) { const files = typeof file === 'string' ? file : file.join(' '); return run('git', 'add', files).catch(error => { log.warn(`Could not stage ${file}`); }); } else { return noop; } }
n/a
function stageDir(baseDir) { baseDir = baseDir || '.'; return run('git', util.format('add %s --all', baseDir)); }
n/a
function status() { return run( '!git', 'status --short --untracked-files=no' ).then(result => { // Output also when not verbose !config.isVerbose && log.log(result.output); }); }
n/a
function tag(version, tag, annotation) { return run( 'git', 'tag', config.isForce ? '--force' : '', '--annotate', `--message="${util.format(annotation, version)}"`, util.format(tag, version) ).then(() => { config.setRuntimeOption('tag_set', true); }).catch(() => { log.warn(`Could not tag. Does tag "${version}" already exist? Use --force to move a tag.`); }); }
n/a
function build(command) { return command ? runTemplateCommand(command) : noop.then(() => { log.verbose('No build command was provided.'); }); }
n/a
function bump(file, version) { if(file) { log.execution('bump', file, version); } if (!config.isDryRun && file !== false) { const files = typeof file === 'string' ? [file] : file; return when.map(files, file => fn.call(fs.readFile, path.resolve(file)).then(data => { const pkg = JSON.parse(data.toString()); pkg.version = version; return pkg; }, err => { log.warn(`Could not read ${err.path || file}`); log.debug(err); }).then(data => { if(data){ return fn.call(fs.writeFile, file, `${JSON.stringify(data, null, 2)}\n`); } }).catch(err => { log.warn(`Could not bump version in ${file}`); log.debug(err); })); } else { return noop; } }
n/a
function copy(files, options, target) { log.execution('copy', files, options, target); return !config.isDryRun ? globcp(files, options, target) : noop; }
n/a
function mkCleanDir(dir) { return sequence([ run.bind(null, 'rm', '-rf', dir), run.bind(null, 'mkdir', '-p', dir) ]); }
n/a
function npmPublish(path, tag) { const publishPath = path || '.'; return run('npm', 'publish', publishPath, '--tag', tag); }
n/a
function popd() { return run('popd'); }
n/a
function pushd(path) { return run('pushd', path); }
n/a
function run(command, commandArgs) { const shellCommand = getShellCommand(command.replace(forcedCmdRe, '')), cmd = [].slice.call(arguments).join(' '), normalizedCmd = cmd.replace(forcedCmdRe, ''), args = [].slice.call(arguments, 1), silentState = shell.config.silent; shell.config.silent = !config.isVerbose; log.execution(normalizedCmd); if (normalizedCmd === cmd && config.isDryRun) { return noop; } return when.promise((resolve, reject) => { if(shellCommand === 'exec') { shell.exec(normalizedCmd, (code, output) => { if (code === 0) { resolve({ code, output }); } else { reject(output); } }); } else if(shellCommand) { resolve(shell[shellCommand].apply(shell, args)); } else { resolve(command.apply(null, args)); } shell.config.silent = silentState; }); }
n/a
function runTemplateCommand(command) { return run(util.template(command, config.context)); }
n/a
run = function (options) { return sequence([ parseVersion, setRemoteGitUrl, getChangelog, checkGithubToken, releaseSourceRepo, releaseDistRepo ], options) }
n/a
function format(template, replacements) { if(template.indexOf('%') === -1) { return template; } else { return util.format.apply(null, arguments); } }
...
},
changelogCommand: 'githubReleaseBodyCommand'
};
function fixAndWarn(options, deprecatedOption, cat, opt) {
const log = require('./log'); // TODO: Fix circular ref
if(deprecatedOption in options) {
log.warn(util.format(`Deprecation notice: the option %s will be removed soon. Please
use %s${opt ? '.' + opt : ''} instead.`, deprecatedOption, cat));
if(opt) {
options[cat][opt] = options[deprecatedOption];
} else {
options[cat] = options[deprecatedOption];
}
delete options[deprecatedOption];
}
...
function increment(version, increment, identifier) { increment = increment || 'patch'; if (releaseTypes.indexOf(increment) === -1) { return increment; } else { return semver.inc(version, increment, identifier); } }
...
const options = config.options;
const version = util.isValidVersion(options.increment) ? options.increment : options.npm.version;
if(!version) {
return git.getLatestTag().then(tag => {
if(tag) {
const nextVersion = util.increment(tag, options.increment, options.prereleaseId);
log.bold(util.format('Latest tag: %s. Next version: %s', tag, nextVersion));
config.setRuntimeOption('previousVersion', tag);
config.setRuntimeOption('version', nextVersion);
} else {
throw new Error('Error detecting current version from latest tag.');
}
}).catch(err => {
...
function isValidVersion(value) { return semver.valid(value); }
...
config = require('./config'),
sequence = require('when/sequence'),
noop = when.resolve.bind(when, true);
function parseVersion() {
const options = config.options;
const version = util.isValidVersion(options.increment) ? options.increment : options
.npm.version;
if(!version) {
return git.getLatestTag().then(tag => {
if(tag) {
const nextVersion = util.increment(tag, options.increment, options.prereleaseId);
log.bold(util.format('Latest tag: %s. Next version: %s', tag, nextVersion));
...
function template(input, context) { return _.template(input)(context); }
...
shell.config.silent = silentState;
});
}
function runTemplateCommand(command) {
return run(util.template(command, config.context));
}
function getShellCommand(command) {
return command && command in shell && typeof shell[command] === 'function' ? command : 'exec
';
}
function pushd(path) {
...