UNPKG

5.02 kBJavaScriptView Raw
1'use strict';
2const execa = require('execa');
3const ora = require('ora');
4const chalk = require('chalk');
5
6const allowedGlobalVariables = [
7 'full', 'except', 'all', 'verbose', 'break', 'interactive', 'warnings', 'list'
8];
9
10module.exports = async (stage, input, options = {}, config) => {
11 const configMicroservices = Object.keys(config.microservices);
12 let microservices;
13
14 microservices = input;
15
16 assertStageIsValid(config, stage);
17 assertMicroservicesAreValid(microservices, configMicroservices);
18 setDefaults(config, options);
19 assertVariablesAreValid(config, options);
20
21 if (options.except === true) {
22 microservices = getArrayDifference(configMicroservices, microservices);
23 } else if (options.all === true) {
24 microservices = configMicroservices;
25 }
26
27 const {variables} = config.stages[stage];
28 if (variables && !isSubset(variables, Object.keys(options))) {
29 throw new Error(`Not enough variables provided for stage "${stage}". Needed:
30 "${variables}".`);
31 }
32
33 console.log(chalk`Beginning to work on stage {green.bold ${stage}}`);
34 const originalStageScript = config.stages[stage].run;
35 for (const microservice of microservices) {
36 let spinner = ora(chalk`Working on stage {green.bold ${stage}} on microservice {red.bold ${microservice}}...`).start();
37 if (!isStageAllowed(config, microservice, stage)) {
38 spinner.warn(chalk`Working on stage {green.bold ${stage}} on microservice {red.bold ${microservice}}... {yellow.bold Skipped}: Stage not allowed`);
39 continue;
40 }
41
42 const stageScript = interpolateVariables(originalStageScript, microservice, options);
43 let {cwd} = config.stages[stage];
44 if (cwd) {
45 cwd = interpolateVariables(cwd, microservice, options);
46 }
47
48 try {
49 /* eslint-disable-next-line no-await-in-loop */
50 const {stdout, stderr} = await processStage(stageScript, cwd);
51 if (stderr) {
52 if (options.warnings === false) {
53 throw new Error(stderr);
54 }
55 }
56
57 spinner = setSpinnerStatus(stderr, options, spinner);
58
59 if (stdout) {
60 if (options.verbose === true) {
61 console.log(stdout);
62 }
63 }
64
65 if (stderr) {
66 console.error(stderr);
67 }
68 } catch (error) {
69 spinner.fail();
70
71 logError(error, options);
72
73 if (options.break === true) {
74 throw new Error('Aborting execution: --break set to true');
75 }
76 }
77 }
78
79 console.log('');
80};
81
82function logError(error, options) {
83 const {stdout, stderr} = error;
84 if (stdout && options.verbose === true) {
85 console.log(stdout);
86 }
87
88 if (stderr) {
89 console.error(stderr);
90 }
91
92 if (!stderr && !stdout && error) {
93 console.error(error);
94 }
95}
96
97function setSpinnerStatus(stderr, options, spinner) {
98 if (stderr) {
99 if (options.warnings === false) {
100 return spinner.fail();
101 }
102
103 return spinner.warn();
104 }
105
106 return spinner.succeed();
107}
108
109function assertStageIsValid(config, stage) {
110 const stages = Object.keys(config.stages);
111 if (!stages.includes(stage)) {
112 throw new Error(`Stage "${stage}" not included in the ones specified in the config file:
113 "${Object.keys(config.stages)}".`);
114 }
115}
116
117function isStageAllowed(config, microservice, stage) {
118 const microserviceObject = config.microservices[microservice];
119 return !(microserviceObject && microserviceObject.allowedStages && !microserviceObject.allowedStages.includes(stage));
120}
121
122function assertMicroservicesAreValid(microservices, configMicroservices) {
123 if (!isSubset(microservices, configMicroservices)) {
124 throw new Error(`Microservices "${microservices}" don't match with the ones specified in the config file:
125 "${configMicroservices}".`);
126 }
127}
128
129function assertVariablesAreValid(config, options) {
130 const confVariables = Object.keys(config.variables);
131 const currentVariables = Object.keys(options);
132 const allVariables = confVariables.concat(allowedGlobalVariables);
133 if (!isSubset(currentVariables, allVariables)) {
134 throw new Error(`Variables "${currentVariables}" don't match with the ones specified in the config file:
135 "${allVariables}".`);
136 }
137
138 for (const vari of currentVariables) {
139 const allowedValues = config.variables[vari];
140 if (allowedValues && !allowedValues.includes(`${options[vari]}`)) {
141 throw new Error(`Value "${options[vari]}" of variable "${vari}" not allowed. Allowed:
142 "${allowedValues}".`);
143 }
144 }
145}
146
147function setDefaults(config, options) {
148 if (!config.variables.defaults) {
149 return;
150 }
151
152 const defaults = Object.keys(config.variables.defaults);
153
154 for (const vari of defaults) {
155 if (options[vari]) {
156 continue;
157 }
158
159 options[vari] = config.variables.defaults[vari];
160 }
161}
162
163function interpolateVariables(string, microservice, options) {
164 string = string.replace('$MICROSERVICE', microservice);
165 for (const key of Object.keys(options)) {
166 string = string.replace('$' + key, options[key]);
167 }
168
169 return string;
170}
171
172function isSubset(subset, set) {
173 return subset.every(val => set.includes(val));
174}
175
176function getArrayDifference(minuend, substrahend) {
177 return minuend.filter(x => !substrahend.includes(x));
178}
179
180function processStage(stageScript, cwd) {
181 return execa('/bin/sh', ['-c', stageScript], {cwd});
182}