UNPKG

4.77 kBJavaScriptView Raw
1const _ = require('lodash');
2const Factory = require('./plugin/factory');
3const Logger = require('./log');
4const Config = require('./config');
5const Shell = require('./shell');
6const Prompt = require('./prompt');
7const Spinner = require('./spinner');
8const Metrics = require('./metrics');
9const { reduceUntil, parseVersion } = require('./util');
10const handleDeprecated = require('./deprecated');
11const throwOnBreakingOptions = require('./breaking');
12
13const 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 // Helper for user scripts
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 // TODO: what's the best way to get (and store) this information?
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 if (metrics) {
134 await metrics.trackException(err);
135 }
136 log ? log.error(err.message || err) : console.error(err); // eslint-disable-line no-console
137 throw err;
138 }
139};
140
141module.exports = runTasks;