UNPKG

4.47 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, verbosityLevel, isDryRun, isDebug } = config;
22 const global = { isCI, isVerbose, verbosityLevel, 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 const external = true;
45 for (const script of _.castArray(scripts)) {
46 const task = () => shell.exec(script, { external }, context);
47 await spinner.show({ task, label: script, context, external });
48 }
49 };
50
51 const runHook = (prefix, namespace, hook) => runScript(hooks[`${prefix}:${namespace}:${hook}`]);
52
53 const runLifeCycleHook = async (plugin, name, ...args) => {
54 if (plugin === _.first(plugins)) await runScript(hooks[`before:${name}`]);
55 await runHook('before', plugin.namespace, name);
56 await plugin[name](...args);
57 await runHook('after', plugin.namespace, name);
58 if (plugin === _.last(plugins)) await runScript(hooks[`after:${name}`]);
59 };
60
61 const plugins = await Factory.getPlugins(config, global, { config, log, shell, spinner, prompt });
62
63 for (const plugin of plugins) {
64 await runLifeCycleHook(plugin, 'init');
65 }
66
67 const { increment, isPreRelease, preReleaseId } = options.version;
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 const suffix = version ? `${latestVersion}...${version}` : `currently at ${latestVersion}`;
82
83 log.obtrusive(`🚀 Let's release ${name} (${suffix})`);
84
85 log.preview({ title: 'changelog', text: changelog });
86
87 version = version || (await reduceUntil(plugins, plugin => plugin.getIncrementedVersion(incrementBase)));
88 config.setContext(parseVersion(version));
89
90 for (const hook of ['beforeBump', 'bump', 'beforeRelease']) {
91 for (const plugin of plugins) {
92 const args = hook === 'bump' ? [version] : [];
93 await runLifeCycleHook(plugin, hook, ...args);
94 }
95 }
96
97 plugins.reverse();
98
99 for (const hook of ['release', 'afterRelease']) {
100 for (const plugin of plugins) {
101 await runLifeCycleHook(plugin, hook);
102 }
103 }
104
105 await metrics.trackEvent('end');
106
107 log.log(`🏁 Done (in ${Math.floor(process.uptime())}s.)`);
108
109 return {
110 name,
111 changelog,
112 latestVersion,
113 version
114 };
115 } catch (err) {
116 const { log, metrics } = container;
117 if (metrics) {
118 await metrics.trackException(err);
119 }
120 log ? log.error(err.message || err) : console.error(err); // eslint-disable-line no-console
121 throw err;
122 }
123};
124
125module.exports = runTasks;