UNPKG

3.96 kBJavaScriptView Raw
1#! /usr/bin/env node
2
3const childProcess = require('child_process');
4const c = require('chalk');
5const _ = require('lodash/fp');
6const {headClean, headMessage, pushFiles} = require('./core/git');
7const {makeError} = require('./core/utils');
8const executeScript = require('./core/script');
9
10const MAJOR = 'major';
11const MINOR = 'minor';
12const PATCH = 'patch';
13
14const builtInSelectReleaseType = message => {
15 const firstLine = message.split('\n')[0];
16 const containsPatchKeyWords = /bug|fix|tweak|plugging/i.test(firstLine);
17 const tooShortMessage = firstLine.split(' ').length < 5; // 4 word + PR tag
18 const hashtagMinor = /#minor\b/i.test(firstLine);
19 const hashtagBug = /#bug\b/i.test(firstLine);
20 const containsMinorKeyWords = /release|feature/i.test(firstLine);
21 const isSquashOrMerge = /Merge pull request #\d+|\(#\D+\)/.test(firstLine);
22
23 if (hashtagBug || containsPatchKeyWords) return PATCH;
24 if (hashtagMinor || containsMinorKeyWords) return MINOR;
25 if (!isSquashOrMerge) return MINOR;
26 if (tooShortMessage) return PATCH;
27 return MINOR;
28};
29
30const getCustomSelection = cmd => {
31 try {
32 return childProcess.execSync(cmd, {encoding: 'utf-8'}).trim();
33 } catch (err) {
34 throw makeError('Failed to get release type', {
35 details: `Exit code of selection command '${cmd}' was ${err.status}`,
36 exitCode: 5
37 });
38 }
39};
40
41const getReleaseType = async selectionCommand => {
42 const releaseType = selectionCommand
43 ? getCustomSelection(selectionCommand)
44 : await builtInSelectReleaseType(await headMessage());
45 if (!_.includes(releaseType, [MAJOR, MINOR, PATCH]))
46 throw makeError(`Invalid release type ${releaseType}`);
47 return releaseType;
48};
49
50module.exports = async config => {
51 if (!(await headClean())) throw makeError('Not a clean state', {exitCode: 4});
52 const autoBumpConfig = config['auto-bump'];
53 if (_.isBoolean(autoBumpConfig)) {
54 if (!autoBumpConfig) {
55 process.stdout.write(c.bold.yellow('Auto-bump is deactivated in config'));
56 return;
57 }
58 } else if (_.isEmpty(autoBumpConfig)) throw makeError('No Config for autobump', {exitCode: 3});
59 const releaseSelector = autoBumpConfig['release-type-command'];
60 const releaseType = await getReleaseType(releaseSelector);
61
62 process.stdout.write(`About to make a ${c.bold.blue(releaseType)} release\n`);
63 const bumpVersionCommand = autoBumpConfig['bump-command'] || 'npm version -m "v%s"';
64 await executeScript([`${bumpVersionCommand} ${releaseType}`]);
65 if (!config.local) await pushFiles('master', config.token, config.repoSlug, true);
66 process.stdout.write(c.bold.green(`Successfully made a ${releaseType} release\n`));
67 if (autoBumpConfig.publish || autoBumpConfig['publish-command']) {
68 await executeScript([autoBumpConfig['publish-command'] || 'npm publish']);
69 process.stdout.write(c.bold.green(`Successfully publish the ${releaseType} release\n`));
70 }
71 if (autoBumpConfig['sync-branch']) {
72 const branch = autoBumpConfig['sync-branch'];
73 await executeScript([
74 `git config remote.gh.url >/dev/null || git remote add gh https://${config.token}@github.com/${config.repoSlug}.git`,
75 `git pull gh ${branch} && git checkout ${branch} && git reset --hard master`,
76 `git push gh ${branch}:refs/heads/${branch} --force || (git remote remove gh && exit 12)`,
77 'git remote remove gh'
78 ]);
79 process.stdout.write(c.bold.green(`Successfully sync branch ${branch}\n`));
80 }
81 if (autoBumpConfig['merge-branch']) {
82 const branch = autoBumpConfig['merge-branch'];
83 await executeScript([
84 `git config remote.gh.url >/dev/null || git remote add gh https://${config.token}@github.com/${config.repoSlug}.git`,
85 `git pull gh ${branch} && git checkout ${branch} && git merge master`,
86 `git push gh ${branch}:refs/heads/${branch} || (git remote remove gh && exit 12)`,
87 'git remote remove gh'
88 ]);
89 process.stdout.write(c.bold.green(`Successfully merged branch ${branch}\n`));
90 }
91};