Skip to content

Commit 7811ce2

Browse files
committed
[added] Dry run and verbose options to release process
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
1 parent f7b9746 commit 7811ce2

16 files changed

+143
-34
lines changed

docs/build.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import routes from './src/Routes';
55
import Root from './src/Root';
66
import fsp from 'fs-promise';
77
import { copy } from '../tools/fs-utils';
8-
import { exec } from 'child-process-promise';
8+
import { exec } from '../tools/exec';
99

1010
const repoRoot = path.resolve(__dirname, '../');
1111
const docsBuilt = path.join(repoRoot, 'docs-built');

tools/amd/build.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import _ from 'lodash';
22
import path from 'path';
33
import fsp from 'fs-promise';
44
import { copy } from '../fs-utils';
5-
import { exec } from 'child-process-promise';
5+
import { exec } from '../exec';
66

77
const repoRoot = path.resolve(__dirname, '../../');
88
const amd = path.join(repoRoot, 'amd');

tools/build.js

+8
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import lib from './lib/build';
77
import docs from '../docs/build';
88
import dist from './dist/build';
99
import { copy } from './fs-utils';
10+
import { setExecOptions } from './exec';
1011

1112
import yargs from 'yargs';
1213

@@ -19,8 +20,15 @@ const argv = yargs
1920
demand: false,
2021
default: false
2122
})
23+
.option('verbose', {
24+
demand: false,
25+
default: false,
26+
describe: 'Increased debug output'
27+
})
2228
.argv;
2329

30+
setExecOptions(argv);
31+
2432
export default function Build(noExitOnFailure) {
2533
if (argv.docsOnly) {
2634
return docs();

tools/release-scripts/constants.js tools/constants.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import path from 'path';
22

3-
const repoRoot = path.resolve(__dirname, '../../');
3+
const repoRoot = path.resolve(__dirname, '../');
44

55
const bowerRepo = '[email protected]:react-bootstrap/react-bootstrap-bower.git';
66
const docsRepo = '[email protected]:react-bootstrap/react-bootstrap.github.io.git';

tools/dist/build.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import path from 'path';
2-
import { exec } from 'child-process-promise';
2+
import { exec } from '../exec';
33

44
const repoRoot = path.resolve(__dirname, '../../');
55
const dist = path.join(repoRoot, 'dist');

tools/exec.js

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import 'colors';
2+
import _ from 'lodash';
3+
import { exec } from 'child-process-promise';
4+
5+
let executionOptions = {
6+
dryRun: false,
7+
verbose: false
8+
};
9+
10+
function logWithPrefix(prefix, message) {
11+
let formattedMessage = message.trim().split('\n')
12+
.reduce((acc, line) => `${acc}${ acc !== '' ? '\n' : '' }${prefix} ${line}`, '');
13+
14+
console.log(formattedMessage);
15+
}
16+
17+
function execWrapper(command, options = {}) {
18+
let proc = exec(command, options);
19+
let title = options.title || command;
20+
let log = message => logWithPrefix(`[${title}]`.grey, message);
21+
22+
if (executionOptions.verbose) {
23+
let output = (data, type) => {
24+
logWithPrefix(`[${title}] ${type}:`.grey, data.toString());
25+
};
26+
proc = proc.progress(({stdout, stderr}) => {
27+
stdout.on('data', data => output(data, 'stdout'));
28+
stderr.on('data', data => output(data, 'stderr'));
29+
})
30+
.then(result => {
31+
log('Complete'.cyan);
32+
return result;
33+
})
34+
.catch(err => {
35+
log(`ERROR: ${err.toString()}`.red);
36+
throw err;
37+
});
38+
}
39+
40+
return proc;
41+
}
42+
43+
function safeExec(command, options = {}) {
44+
let title = options.title || command;
45+
46+
if (executionOptions.dryRun) {
47+
logWithPrefix(`[${title}]`.grey, 'DRY RUN'.magenta);
48+
return Promise.resolve();
49+
}
50+
51+
return execWrapper(command, options);
52+
}
53+
54+
function setExecOptions(options) {
55+
executionOptions = _.extend({}, executionOptions, options);
56+
}
57+
58+
export default {
59+
exec: execWrapper,
60+
safeExec,
61+
setExecOptions
62+
};

tools/lib/build.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'colors';
22
import path from 'path';
3-
import { exec } from 'child-process-promise';
3+
import { exec } from '../exec';
44

55
const repoRoot = path.resolve(__dirname, '../../');
66
const lib = path.join(repoRoot, 'lib');

tools/release-docs-scripts/release-docs.js

+27-5
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,33 @@
11
/* eslint no-process-exit: 0 */
22

33
import 'colors';
4-
import { exec } from 'child-process-promise';
4+
import yargs from 'yargs';
5+
import { exec, safeExec, setExecOptions } from '../exec';
56

67
import preConditions from '../release-scripts/pre-conditions';
78
import versionBump from '../release-scripts/version-bump';
89
import repoRelease from '../release-scripts/repo-release';
910
import tag from '../release-scripts/tag';
1011
import { lint } from '../release-scripts/test';
1112

12-
import { repoRoot, docsRoot, docsRepo, tmpDocsRepo } from '../release-scripts/constants';
13+
import { repoRoot, docsRoot, docsRepo, tmpDocsRepo } from '../constants';
14+
15+
const yargsConf = yargs
16+
.usage('Usage: $0 [-n|--dry-run] [--verbose]')
17+
.option('dry-run', {
18+
alias: 'n',
19+
demand: false,
20+
default: false,
21+
describe: 'Execute command in dry run mode. Will not commit, tag, push, or publish anything. Userful for testing.'
22+
})
23+
.option('verbose', {
24+
demand: false,
25+
default: false,
26+
describe: 'Increased debug output'
27+
});
28+
29+
const argv = yargsConf.argv;
30+
setExecOptions(argv);
1331

1432
let version;
1533

@@ -22,7 +40,7 @@ preConditions()
2240
.then(versionBump(repoRoot, versionBumpOptions))
2341
.then(v => { version = v; })
2442
.then(() => {
25-
return exec('npm run docs-build')
43+
return exec(`npm run docs-build${ argv.verbose ? ' -- --verbose' : '' }`)
2644
.catch(err => {
2745
console.log('Docs-build failed, reverting version bump'.red);
2846
return exec('git reset HEAD .')
@@ -33,15 +51,19 @@ preConditions()
3351
});
3452
});
3553
})
36-
.then(() => exec(`git commit -m "Release v${version}"`))
54+
.then(() => safeExec(`git commit -m "Release v${version}"`))
3755
.then(() => Promise.all([
3856
tag(version),
3957
repoRelease(docsRepo, docsRoot, tmpDocsRepo, version)
4058
]))
4159
.then(() => console.log('Version '.cyan + `v${version}`.green + ' released!'.cyan))
4260
.catch(err => {
4361
if (!err.__handled) {
44-
console.error(err.message.red);
62+
if (argv.verbose) {
63+
console.error(err.stack.red);
64+
} else {
65+
console.error(err.toString().red);
66+
}
4567
}
4668

4769
process.exit(1);

tools/release-scripts/changelog.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import 'colors';
22
import path from 'path';
3-
import { exec } from 'child-process-promise';
3+
import { exec, safeExec } from '../exec';
44

55
export default (repoRoot, version) => {
66
return exec(`node_modules/.bin/changelog -t v${version}`)
7-
.then(() => exec(`git add ${path.join(repoRoot, 'CHANGELOG.md')}`))
7+
.then(() => safeExec(`git add ${path.join(repoRoot, 'CHANGELOG.md')}`))
88
.then(() => console.log('Generated Changelog'.cyan));
99
};

tools/release-scripts/pre-conditions.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import 'colors';
2-
import { exec } from 'child-process-promise';
2+
import { exec } from '../exec';
33

44
function ensureClean() {
55
return exec('git diff-index --name-only HEAD --')

tools/release-scripts/release.js

+21-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint no-process-exit: 0 */
22
import yargs from 'yargs';
3-
import { exec } from 'child-process-promise';
3+
import { exec, safeExec, setExecOptions } from '../exec';
44

55
import preConditions from './pre-conditions';
66
import versionBump from './version-bump';
@@ -10,12 +10,13 @@ import tagAndPublish from './tag-and-publish';
1010
import test from './test';
1111
import build from '../build';
1212

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

1515
const yargsConf = yargs
1616
.usage('Usage: $0 <version> [--preid <identifier>]')
1717
.example('$0 minor --preid beta', 'Release with minor version bump with pre-release tag')
1818
.example('$0 major', 'Release with major version bump')
19+
.example('$0 major --dry-run', 'Release dry run with patch version bump')
1920
.example('$0 --preid beta', 'Release same version with pre-release bump')
2021
.command('patch', 'Release patch')
2122
.command('minor', 'Release minor')
@@ -25,9 +26,21 @@ const yargsConf = yargs
2526
demand: false,
2627
describe: 'pre-release identifier',
2728
type: 'string'
29+
})
30+
.option('dry-run', {
31+
alias: 'n',
32+
demand: false,
33+
default: false,
34+
describe: 'Execute command in dry run mode. Will not commit, tag, push, or publish anything. Userful for testing.'
35+
})
36+
.option('verbose', {
37+
demand: false,
38+
default: false,
39+
describe: 'Increased debug output'
2840
});
2941

3042
const argv = yargsConf.argv;
43+
setExecOptions(argv);
3144

3245
let version;
3346

@@ -61,7 +74,7 @@ preConditions()
6174
});
6275
});
6376
})
64-
.then(() => exec(`git commit -m "Release v${version}"`))
77+
.then(() => safeExec(`git commit -m "Release v${version}"`))
6578
.then(() => Promise.all([
6679
tagAndPublish(version),
6780
repoRelease(bowerRepo, bowerRoot, tmpBowerRepo, version),
@@ -70,7 +83,11 @@ preConditions()
7083
.then(() => console.log('Version '.cyan + `v${version}`.green + ' released!'.cyan))
7184
.catch(err => {
7285
if (!err.__handled) {
73-
console.error(err.message.red);
86+
if (argv.verbose) {
87+
console.error(err.stack.red);
88+
} else {
89+
console.error(err.toString().red);
90+
}
7491
}
7592

7693
process.exit(1);

tools/release-scripts/repo-release.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import 'colors';
22
import path from 'path';
33
import fsp from 'fs-promise';
4-
import { exec } from 'child-process-promise';
4+
import { exec, safeExec } from '../exec';
55
import { copy } from '../fs-utils';
66

77
const repoRoot = path.resolve(__dirname, '../../');
@@ -23,11 +23,11 @@ export default (repo, srcFolder, tmpFolder, version) => {
2323
})
2424
.then(() => copy(srcFolder, tmpFolder))
2525
.then(() => copy(license, tmpFolder))
26-
.then(() => exec(`cd ${tmpFolder} && git add -A .`))
27-
.then(() => exec(`cd ${tmpFolder} && git commmit -m "Release v${version}"`))
28-
.then(() => exec(`cd ${tmpFolder} && git tag -a --message=v${version} v${version}`))
29-
.then(() => exec(`cd ${tmpFolder} && git push`))
30-
.then(() => exec(`cd ${tmpFolder} && git push --tags`))
31-
.then(() => exec(`rimraf ${tmpFolder}`))
26+
.then(() => safeExec(`cd ${tmpFolder} && git add -A .`))
27+
.then(() => safeExec(`cd ${tmpFolder} && git commmit -m "Release v${version}"`))
28+
.then(() => safeExec(`cd ${tmpFolder} && git tag -a --message=v${version} v${version}`))
29+
.then(() => safeExec(`cd ${tmpFolder} && git push`))
30+
.then(() => safeExec(`cd ${tmpFolder} && git push --tags`))
31+
.then(() => safeExec(`rimraf ${tmpFolder}`))
3232
.then(() => console.log('Released: '.cyan + repo.green));
3333
};
+3-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { exec } from 'child-process-promise';
1+
import { safeExec } from '../exec';
22
import tag from './tag';
33

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

7-
return tag()
8-
.then(() => exec('npm publish'))
7+
return tag(version)
8+
.then(() => safeExec('npm publish'))
99
.then(() => console.log('Released: '.cyan + 'npm module'.green));
1010
};

tools/release-scripts/tag.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { exec } from 'child-process-promise';
1+
import { safeExec } from '../exec';
22

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

6-
return exec(`git tag -a --message=v${version} v${version}`)
7-
.then(() => exec(`git push`))
8-
.then(() => exec(`git push --tags`))
6+
return safeExec(`git tag -a --message=v${version} v${version}`)
7+
.then(() => safeExec(`git push`))
8+
.then(() => safeExec(`git push --tags`))
99
.then(() => console.log('Tagged: '.cyan + `v${version}`.green));
1010
};

tools/release-scripts/test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import 'colors';
2-
import { exec } from 'child-process-promise';
2+
import { exec } from '../exec';
33

44
function test() {
55
console.log('Running: '.cyan + 'tests'.green);

tools/release-scripts/version-bump.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import 'colors';
22
import path from 'path';
33
import fsp from 'fs-promise';
44
import semver from 'semver';
5-
import { exec } from 'child-process-promise';
5+
import { safeExec } from '../exec';
66

77
export default function(repoRoot, { preid, type }) {
88
const packagePath = path.join(repoRoot, 'package.json');
@@ -35,7 +35,7 @@ export default function(repoRoot, { preid, type }) {
3535
json.version = version;
3636

3737
return fsp.writeFile(packagePath, JSON.stringify(json, null, 2))
38-
.then(() => exec(`git add ${packagePath}`))
38+
.then(() => safeExec(`git add ${packagePath}`))
3939
.then(() => json.version);
4040
});
4141
}

0 commit comments

Comments
 (0)