1 | const _ = require('lodash');
|
2 | const Factory = require('./plugin/factory');
|
3 | const Logger = require('./log');
|
4 | const Config = require('./config');
|
5 | const Shell = require('./shell');
|
6 | const Prompt = require('./prompt');
|
7 | const Spinner = require('./spinner');
|
8 | const Metrics = require('./metrics');
|
9 | const { reduceUntil, parseVersion } = require('./util');
|
10 | const handleDeprecated = require('./deprecated');
|
11 | const throwOnBreakingOptions = require('./breaking');
|
12 |
|
13 | const runTasks = async (opts, di) => {
|
14 | let container = {};
|
15 |
|
16 | try {
|
17 | Object.assign(container, di);
|
18 | container.config = container.config || new Config(opts);
|
19 |
|
20 | const { config } = container;
|
21 | const { isCI, isVerbose, isDryRun, isDebug } = config;
|
22 | const global = { isCI, isVerbose, isDryRun, isDebug };
|
23 |
|
24 | container.log = container.log || new Logger(global);
|
25 | container.spinner = container.spinner || new Spinner({ global, container, config });
|
26 | container.prompt = new Prompt({ container: { config } });
|
27 | container.metrics = new Metrics({ isEnabled: config.isCollectMetrics });
|
28 | container.shell = container.shell || new Shell({ global, container });
|
29 |
|
30 | const { log, metrics, shell, spinner, prompt } = container;
|
31 |
|
32 | const options = handleDeprecated(config.getContext(), log);
|
33 |
|
34 | metrics.trackEvent('start', options);
|
35 |
|
36 | await throwOnBreakingOptions(options);
|
37 |
|
38 | const { hooks } = options;
|
39 |
|
40 |
|
41 | const runScript = async scripts => {
|
42 | if (!scripts || !scripts.length) return;
|
43 | const context = config.getContext();
|
44 | for (const script of _.castArray(scripts)) {
|
45 | const task = () => shell.exec(script, {}, context);
|
46 | await spinner.show({ task, label: script, context, forced: true });
|
47 | }
|
48 | };
|
49 |
|
50 | const runHook = (prefix, namespace, hook) => runScript(hooks[`${prefix}:${namespace}:${hook}`]);
|
51 |
|
52 | const runLifeCycleHook = async (plugin, name, ...args) => {
|
53 | if (plugin === _.first(plugins)) await runScript(hooks[`before:${name}`]);
|
54 | await runHook('before', plugin.namespace, name);
|
55 | await plugin[name](...args);
|
56 | await runHook('after', plugin.namespace, name);
|
57 | if (plugin === _.last(plugins)) await runScript(hooks[`after:${name}`]);
|
58 | };
|
59 |
|
60 | const plugins = await Factory.getPlugins(config, global, { config, log, shell, spinner, prompt });
|
61 |
|
62 | for (const plugin of plugins) {
|
63 | await runLifeCycleHook(plugin, 'init');
|
64 | }
|
65 |
|
66 | const { increment, isPreRelease, preReleaseId } = options.version;
|
67 | const { beforeStart, beforeBump, afterBump, beforeStage, afterRelease } = options.scripts || {};
|
68 |
|
69 | const name = await reduceUntil(plugins, plugin => plugin.getName());
|
70 | const latestVersion = await reduceUntil(plugins, plugin => plugin.getLatestVersion());
|
71 |
|
72 |
|
73 | const repo = await reduceUntil(plugins, plugin => plugin.getContext('repo'));
|
74 | const changelog = await reduceUntil(plugins, plugin => plugin.getContext('changelog'));
|
75 |
|
76 | const incrementBase = { latestVersion, increment, isPreRelease, preReleaseId };
|
77 | let version = await reduceUntil(plugins, plugin => plugin.getIncrementedVersionCI(incrementBase));
|
78 |
|
79 | config.setContext({ name, latestVersion, version, repo, changelog });
|
80 |
|
81 | await runScript(beforeStart);
|
82 |
|
83 | const suffix = version ? `${latestVersion}...${version}` : `currently at ${latestVersion}`;
|
84 |
|
85 | log.obtrusive(`🚀 Let's release ${name} (${suffix})`);
|
86 |
|
87 | log.preview({ title: 'changelog', text: changelog });
|
88 |
|
89 | version = version || (await reduceUntil(plugins, plugin => plugin.getIncrementedVersion(incrementBase)));
|
90 | config.setContext(parseVersion(version));
|
91 |
|
92 | for (const plugin of plugins) {
|
93 | await runLifeCycleHook(plugin, 'beforeBump');
|
94 | }
|
95 |
|
96 | await runScript(beforeBump);
|
97 |
|
98 | for (const plugin of plugins) {
|
99 | await runLifeCycleHook(plugin, 'bump', version);
|
100 | }
|
101 |
|
102 | await runScript(afterBump);
|
103 | await runScript(beforeStage);
|
104 |
|
105 | for (const plugin of plugins) {
|
106 | await runLifeCycleHook(plugin, 'beforeRelease');
|
107 | }
|
108 |
|
109 | plugins.reverse();
|
110 |
|
111 | for (const plugin of plugins) {
|
112 | await runLifeCycleHook(plugin, 'release');
|
113 | }
|
114 |
|
115 | await runScript(afterRelease);
|
116 |
|
117 | for (const plugin of plugins) {
|
118 | await runLifeCycleHook(plugin, 'afterRelease');
|
119 | }
|
120 |
|
121 | await metrics.trackEvent('end');
|
122 |
|
123 | log.log(`🏁 Done (in ${Math.floor(process.uptime())}s.)`);
|
124 |
|
125 | return {
|
126 | name,
|
127 | changelog,
|
128 | latestVersion,
|
129 | version
|
130 | };
|
131 | } catch (err) {
|
132 | const { log, metrics } = container;
|
133 | metrics && (await metrics.trackException(err));
|
134 | log ? log.error(err.message || err) : console.error(err);
|
135 | throw err;
|
136 | }
|
137 | };
|
138 |
|
139 | module.exports = runTasks;
|