Skip to content

Commit

Permalink
[added] Dry run and verbose options to release process
Browse files Browse the repository at this point in the history
Add `--dry-run` and `--verbose` options to release process to facilitate
some means to test the release process. Also fixes a few bugs found in
the existing process along the way.

Closes react-bootstrap#563
  • Loading branch information
mtscout6 committed Apr 24, 2015
1 parent f7b9746 commit 7811ce2
Show file tree
Hide file tree
Showing 16 changed files with 143 additions and 34 deletions.
2 changes: 1 addition & 1 deletion docs/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import routes from './src/Routes';
import Root from './src/Root';
import fsp from 'fs-promise';
import { copy } from '../tools/fs-utils';
import { exec } from 'child-process-promise';
import { exec } from '../tools/exec';

const repoRoot = path.resolve(__dirname, '../');
const docsBuilt = path.join(repoRoot, 'docs-built');
Expand Down
2 changes: 1 addition & 1 deletion tools/amd/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import _ from 'lodash';
import path from 'path';
import fsp from 'fs-promise';
import { copy } from '../fs-utils';
import { exec } from 'child-process-promise';
import { exec } from '../exec';

const repoRoot = path.resolve(__dirname, '../../');
const amd = path.join(repoRoot, 'amd');
Expand Down
8 changes: 8 additions & 0 deletions tools/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import lib from './lib/build';
import docs from '../docs/build';
import dist from './dist/build';
import { copy } from './fs-utils';
import { setExecOptions } from './exec';

import yargs from 'yargs';

Expand All @@ -19,8 +20,15 @@ const argv = yargs
demand: false,
default: false
})
.option('verbose', {
demand: false,
default: false,
describe: 'Increased debug output'
})
.argv;

setExecOptions(argv);

export default function Build(noExitOnFailure) {
if (argv.docsOnly) {
return docs();
Expand Down
2 changes: 1 addition & 1 deletion tools/release-scripts/constants.js → tools/constants.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import path from 'path';

const repoRoot = path.resolve(__dirname, '../../');
const repoRoot = path.resolve(__dirname, '../');

const bowerRepo = '[email protected]:react-bootstrap/react-bootstrap-bower.git';
const docsRepo = '[email protected]:react-bootstrap/react-bootstrap.github.io.git';
Expand Down
2 changes: 1 addition & 1 deletion tools/dist/build.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import path from 'path';
import { exec } from 'child-process-promise';
import { exec } from '../exec';

const repoRoot = path.resolve(__dirname, '../../');
const dist = path.join(repoRoot, 'dist');
Expand Down
62 changes: 62 additions & 0 deletions tools/exec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import 'colors';
import _ from 'lodash';
import { exec } from 'child-process-promise';

let executionOptions = {
dryRun: false,
verbose: false
};

function logWithPrefix(prefix, message) {
let formattedMessage = message.trim().split('\n')
.reduce((acc, line) => `${acc}${ acc !== '' ? '\n' : '' }${prefix} ${line}`, '');

console.log(formattedMessage);
}

function execWrapper(command, options = {}) {
let proc = exec(command, options);
let title = options.title || command;
let log = message => logWithPrefix(`[${title}]`.grey, message);

if (executionOptions.verbose) {
let output = (data, type) => {
logWithPrefix(`[${title}] ${type}:`.grey, data.toString());
};
proc = proc.progress(({stdout, stderr}) => {
stdout.on('data', data => output(data, 'stdout'));
stderr.on('data', data => output(data, 'stderr'));
})
.then(result => {
log('Complete'.cyan);
return result;
})
.catch(err => {
log(`ERROR: ${err.toString()}`.red);
throw err;
});
}

return proc;
}

function safeExec(command, options = {}) {
let title = options.title || command;

if (executionOptions.dryRun) {
logWithPrefix(`[${title}]`.grey, 'DRY RUN'.magenta);
return Promise.resolve();
}

return execWrapper(command, options);
}

function setExecOptions(options) {
executionOptions = _.extend({}, executionOptions, options);
}

export default {
exec: execWrapper,
safeExec,
setExecOptions
};
2 changes: 1 addition & 1 deletion tools/lib/build.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'colors';
import path from 'path';
import { exec } from 'child-process-promise';
import { exec } from '../exec';

const repoRoot = path.resolve(__dirname, '../../');
const lib = path.join(repoRoot, 'lib');
Expand Down
32 changes: 27 additions & 5 deletions tools/release-docs-scripts/release-docs.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,33 @@
/* eslint no-process-exit: 0 */

import 'colors';
import { exec } from 'child-process-promise';
import yargs from 'yargs';
import { exec, safeExec, setExecOptions } from '../exec';

import preConditions from '../release-scripts/pre-conditions';
import versionBump from '../release-scripts/version-bump';
import repoRelease from '../release-scripts/repo-release';
import tag from '../release-scripts/tag';
import { lint } from '../release-scripts/test';

import { repoRoot, docsRoot, docsRepo, tmpDocsRepo } from '../release-scripts/constants';
import { repoRoot, docsRoot, docsRepo, tmpDocsRepo } from '../constants';

const yargsConf = yargs
.usage('Usage: $0 [-n|--dry-run] [--verbose]')
.option('dry-run', {
alias: 'n',
demand: false,
default: false,
describe: 'Execute command in dry run mode. Will not commit, tag, push, or publish anything. Userful for testing.'
})
.option('verbose', {
demand: false,
default: false,
describe: 'Increased debug output'
});

const argv = yargsConf.argv;
setExecOptions(argv);

let version;

Expand All @@ -22,7 +40,7 @@ preConditions()
.then(versionBump(repoRoot, versionBumpOptions))
.then(v => { version = v; })
.then(() => {
return exec('npm run docs-build')
return exec(`npm run docs-build${ argv.verbose ? ' -- --verbose' : '' }`)
.catch(err => {
console.log('Docs-build failed, reverting version bump'.red);
return exec('git reset HEAD .')
Expand All @@ -33,15 +51,19 @@ preConditions()
});
});
})
.then(() => exec(`git commit -m "Release v${version}"`))
.then(() => safeExec(`git commit -m "Release v${version}"`))
.then(() => Promise.all([
tag(version),
repoRelease(docsRepo, docsRoot, tmpDocsRepo, version)
]))
.then(() => console.log('Version '.cyan + `v${version}`.green + ' released!'.cyan))
.catch(err => {
if (!err.__handled) {
console.error(err.message.red);
if (argv.verbose) {
console.error(err.stack.red);
} else {
console.error(err.toString().red);
}
}

process.exit(1);
Expand Down
4 changes: 2 additions & 2 deletions tools/release-scripts/changelog.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import 'colors';
import path from 'path';
import { exec } from 'child-process-promise';
import { exec, safeExec } from '../exec';

export default (repoRoot, version) => {
return exec(`node_modules/.bin/changelog -t v${version}`)
.then(() => exec(`git add ${path.join(repoRoot, 'CHANGELOG.md')}`))
.then(() => safeExec(`git add ${path.join(repoRoot, 'CHANGELOG.md')}`))
.then(() => console.log('Generated Changelog'.cyan));
};
2 changes: 1 addition & 1 deletion tools/release-scripts/pre-conditions.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'colors';
import { exec } from 'child-process-promise';
import { exec } from '../exec';

function ensureClean() {
return exec('git diff-index --name-only HEAD --')
Expand Down
25 changes: 21 additions & 4 deletions tools/release-scripts/release.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint no-process-exit: 0 */
import yargs from 'yargs';
import { exec } from 'child-process-promise';
import { exec, safeExec, setExecOptions } from '../exec';

import preConditions from './pre-conditions';
import versionBump from './version-bump';
Expand All @@ -10,12 +10,13 @@ import tagAndPublish from './tag-and-publish';
import test from './test';
import build from '../build';

import { repoRoot, bowerRepo, bowerRoot, tmpBowerRepo, docsRoot, docsRepo, tmpDocsRepo } from './constants';
import { repoRoot, bowerRepo, bowerRoot, tmpBowerRepo, docsRoot, docsRepo, tmpDocsRepo } from '../constants';

const yargsConf = yargs
.usage('Usage: $0 <version> [--preid <identifier>]')
.example('$0 minor --preid beta', 'Release with minor version bump with pre-release tag')
.example('$0 major', 'Release with major version bump')
.example('$0 major --dry-run', 'Release dry run with patch version bump')
.example('$0 --preid beta', 'Release same version with pre-release bump')
.command('patch', 'Release patch')
.command('minor', 'Release minor')
Expand All @@ -25,9 +26,21 @@ const yargsConf = yargs
demand: false,
describe: 'pre-release identifier',
type: 'string'
})
.option('dry-run', {
alias: 'n',
demand: false,
default: false,
describe: 'Execute command in dry run mode. Will not commit, tag, push, or publish anything. Userful for testing.'
})
.option('verbose', {
demand: false,
default: false,
describe: 'Increased debug output'
});

const argv = yargsConf.argv;
setExecOptions(argv);

let version;

Expand Down Expand Up @@ -61,7 +74,7 @@ preConditions()
});
});
})
.then(() => exec(`git commit -m "Release v${version}"`))
.then(() => safeExec(`git commit -m "Release v${version}"`))
.then(() => Promise.all([
tagAndPublish(version),
repoRelease(bowerRepo, bowerRoot, tmpBowerRepo, version),
Expand All @@ -70,7 +83,11 @@ preConditions()
.then(() => console.log('Version '.cyan + `v${version}`.green + ' released!'.cyan))
.catch(err => {
if (!err.__handled) {
console.error(err.message.red);
if (argv.verbose) {
console.error(err.stack.red);
} else {
console.error(err.toString().red);
}
}

process.exit(1);
Expand Down
14 changes: 7 additions & 7 deletions tools/release-scripts/repo-release.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'colors';
import path from 'path';
import fsp from 'fs-promise';
import { exec } from 'child-process-promise';
import { exec, safeExec } from '../exec';
import { copy } from '../fs-utils';

const repoRoot = path.resolve(__dirname, '../../');
Expand All @@ -23,11 +23,11 @@ export default (repo, srcFolder, tmpFolder, version) => {
})
.then(() => copy(srcFolder, tmpFolder))
.then(() => copy(license, tmpFolder))
.then(() => exec(`cd ${tmpFolder} && git add -A .`))
.then(() => exec(`cd ${tmpFolder} && git commmit -m "Release v${version}"`))
.then(() => exec(`cd ${tmpFolder} && git tag -a --message=v${version} v${version}`))
.then(() => exec(`cd ${tmpFolder} && git push`))
.then(() => exec(`cd ${tmpFolder} && git push --tags`))
.then(() => exec(`rimraf ${tmpFolder}`))
.then(() => safeExec(`cd ${tmpFolder} && git add -A .`))
.then(() => safeExec(`cd ${tmpFolder} && git commmit -m "Release v${version}"`))
.then(() => safeExec(`cd ${tmpFolder} && git tag -a --message=v${version} v${version}`))
.then(() => safeExec(`cd ${tmpFolder} && git push`))
.then(() => safeExec(`cd ${tmpFolder} && git push --tags`))
.then(() => safeExec(`rimraf ${tmpFolder}`))
.then(() => console.log('Released: '.cyan + repo.green));
};
6 changes: 3 additions & 3 deletions tools/release-scripts/tag-and-publish.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { exec } from 'child-process-promise';
import { safeExec } from '../exec';
import tag from './tag';

export default (version) => {
console.log('Releasing: '.cyan + 'npm module'.green);

return tag()
.then(() => exec('npm publish'))
return tag(version)
.then(() => safeExec('npm publish'))
.then(() => console.log('Released: '.cyan + 'npm module'.green));
};
8 changes: 4 additions & 4 deletions tools/release-scripts/tag.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { exec } from 'child-process-promise';
import { safeExec } from '../exec';

export default (version) => {
console.log('Tagging: '.cyan + `v${version}`.green);

return exec(`git tag -a --message=v${version} v${version}`)
.then(() => exec(`git push`))
.then(() => exec(`git push --tags`))
return safeExec(`git tag -a --message=v${version} v${version}`)
.then(() => safeExec(`git push`))
.then(() => safeExec(`git push --tags`))
.then(() => console.log('Tagged: '.cyan + `v${version}`.green));
};
2 changes: 1 addition & 1 deletion tools/release-scripts/test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'colors';
import { exec } from 'child-process-promise';
import { exec } from '../exec';

function test() {
console.log('Running: '.cyan + 'tests'.green);
Expand Down
4 changes: 2 additions & 2 deletions tools/release-scripts/version-bump.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'colors';
import path from 'path';
import fsp from 'fs-promise';
import semver from 'semver';
import { exec } from 'child-process-promise';
import { safeExec } from '../exec';

export default function(repoRoot, { preid, type }) {
const packagePath = path.join(repoRoot, 'package.json');
Expand Down Expand Up @@ -35,7 +35,7 @@ export default function(repoRoot, { preid, type }) {
json.version = version;

return fsp.writeFile(packagePath, JSON.stringify(json, null, 2))
.then(() => exec(`git add ${packagePath}`))
.then(() => safeExec(`git add ${packagePath}`))
.then(() => json.version);
});
}

0 comments on commit 7811ce2

Please sign in to comment.