1 | "use strict";
|
2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3 | if (k2 === undefined) k2 = k;
|
4 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
5 | }) : (function(o, m, k, k2) {
|
6 | if (k2 === undefined) k2 = k;
|
7 | o[k2] = m[k];
|
8 | }));
|
9 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
10 | Object.defineProperty(o, "default", { enumerable: true, value: v });
|
11 | }) : function(o, v) {
|
12 | o["default"] = v;
|
13 | });
|
14 | var __importStar = (this && this.__importStar) || function (mod) {
|
15 | if (mod && mod.__esModule) return mod;
|
16 | var result = {};
|
17 | if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
18 | __setModuleDefault(result, mod);
|
19 | return result;
|
20 | };
|
21 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
22 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
23 | };
|
24 | Object.defineProperty(exports, "__esModule", { value: true });
|
25 | exports.yarnPublish = exports.mapToArgs = exports.getChangedFiles = exports.gitDiff = exports.getCommitHash = exports.pgrep = exports.dockerPush = exports.dockerBuild = exports.dockerContainerReady = exports.dockerRun = exports.remoteDockerImageExists = exports.dockerNetworkExists = exports.getContainerInfo = exports.dockerTag = exports.dockerStop = exports.dockerPull = exports.runJest = exports.yarnRun = exports.setup = exports.build = exports.runTSScript = exports.fork = exports.exec = void 0;
|
26 | const ms_1 = __importDefault(require("ms"));
|
27 | const path_1 = __importDefault(require("path"));
|
28 | const execa_1 = __importDefault(require("execa"));
|
29 | const fs_extra_1 = __importDefault(require("fs-extra"));
|
30 | const utils_1 = require("@terascope/utils");
|
31 | const misc_1 = require("./misc");
|
32 | const signale_1 = __importDefault(require("./signale"));
|
33 | const config = __importStar(require("./config"));
|
34 | const logger = utils_1.debugLogger('ts-scripts:cmd');
|
35 | function _exec(opts) {
|
36 | let subprocess;
|
37 | const options = {
|
38 | cwd: opts.cwd || misc_1.getRootDir(),
|
39 | env: opts.env,
|
40 | preferLocal: true,
|
41 | detached: opts.detached,
|
42 | timeout: opts.timeout,
|
43 | stdio: opts.stdio,
|
44 | };
|
45 | logger.debug('executing command', opts);
|
46 | if (opts.args && opts.args.length) {
|
47 | subprocess = execa_1.default(opts.cmd, opts.args, options);
|
48 | }
|
49 | else {
|
50 | subprocess = execa_1.default(opts.cmd, options);
|
51 | }
|
52 | if (!subprocess) {
|
53 | throw new Error(`Failed to execution ${opts.cmd}`);
|
54 | }
|
55 | if (!opts.stdio) {
|
56 | if (!subprocess.stderr || !subprocess.stdout) {
|
57 | throw new Error(`Command ${opts.cmd} failed, stderr or stdout is not available`);
|
58 | }
|
59 | subprocess.stderr.pipe(process.stderr);
|
60 | }
|
61 | return subprocess;
|
62 | }
|
63 | async function exec(opts, log = true) {
|
64 | try {
|
65 | const env = { FORCE_COLOR: '0', ...opts.env };
|
66 | const _opts = { ...opts };
|
67 | _opts.env = env;
|
68 | const subprocess = _exec(_opts);
|
69 | const { stdout } = await subprocess;
|
70 | const result = stdout.trim();
|
71 | logger.debug(`exec result: ${opts.cmd} ${(opts.args || []).join(' ')}`, log && result);
|
72 | return result;
|
73 | }
|
74 | catch (err) {
|
75 | if (!err.command) {
|
76 | throw err;
|
77 | }
|
78 | process.exitCode = err.exitCode || 1;
|
79 | throw new Error(err.message);
|
80 | }
|
81 | }
|
82 | exports.exec = exec;
|
83 | async function fork(opts) {
|
84 | try {
|
85 | const env = {
|
86 | FORCE_COLOR: config.FORCE_COLOR,
|
87 | ...opts.env
|
88 | };
|
89 | const _opts = { stdio: 'inherit', ...opts };
|
90 | _opts.env = env;
|
91 | await _exec(_opts);
|
92 | }
|
93 | catch (err) {
|
94 | if (!err.command) {
|
95 | throw err;
|
96 | }
|
97 | process.exitCode = err.exitCode || 1;
|
98 | throw new Error(err.message);
|
99 | }
|
100 | }
|
101 | exports.fork = fork;
|
102 | async function runTSScript(cmd, args) {
|
103 | const scriptName = process.argv[1];
|
104 | return fork({
|
105 | cmd: scriptName,
|
106 | args: [cmd, ...args],
|
107 | });
|
108 | }
|
109 | exports.runTSScript = runTSScript;
|
110 | async function build(pkgInfo) {
|
111 | if (pkgInfo) {
|
112 | const distDir = path_1.default.join(pkgInfo.dir, 'dist');
|
113 | if (fs_extra_1.default.existsSync(distDir)) {
|
114 | await fs_extra_1.default.emptyDir(distDir);
|
115 | }
|
116 | await yarnRun('build', [], pkgInfo.dir);
|
117 | return;
|
118 | }
|
119 | await yarnRun('build');
|
120 | }
|
121 | exports.build = build;
|
122 | async function setup() {
|
123 | await yarnRun('setup');
|
124 | }
|
125 | exports.setup = setup;
|
126 | async function yarnRun(script, args = [], cwd, env, log) {
|
127 | const dir = cwd || misc_1.getRootDir();
|
128 | const pkgJSON = await fs_extra_1.default.readJSON(path_1.default.join(dir, 'package.json'));
|
129 | const hasScript = Boolean(utils_1.get(pkgJSON, ['scripts', script]));
|
130 | if (!hasScript)
|
131 | return;
|
132 | const _args = ['run', script, ...args];
|
133 | if (log) {
|
134 | signale_1.default.info(`running yarn ${_args.join(' ')}...`);
|
135 | }
|
136 | await fork({
|
137 | cmd: 'yarn', args: _args, cwd: dir, env
|
138 | });
|
139 | }
|
140 | exports.yarnRun = yarnRun;
|
141 | async function runJest(cwd, argsMap, env, extraArgs, debug) {
|
142 | const args = mapToArgs(argsMap);
|
143 | if (extraArgs) {
|
144 | extraArgs.forEach((extraArg) => {
|
145 | if (extraArg.startsWith('-') && args.includes(extraArg)) {
|
146 | if (debug) {
|
147 | logger.debug(`* skipping duplicate jest arg ${extraArg}`);
|
148 | }
|
149 | return;
|
150 | }
|
151 | args.push(extraArg);
|
152 | });
|
153 | }
|
154 | if (debug) {
|
155 | signale_1.default.debug(`executing: jest ${args.join(' ')}`);
|
156 | }
|
157 | await fork({
|
158 | cmd: 'jest',
|
159 | cwd,
|
160 | args,
|
161 | env,
|
162 | });
|
163 | }
|
164 | exports.runJest = runJest;
|
165 | async function dockerPull(image, timeout = 0) {
|
166 | try {
|
167 | await exec({
|
168 | cmd: 'docker',
|
169 | args: ['pull', image],
|
170 | timeout,
|
171 | });
|
172 | }
|
173 | catch (err) {
|
174 | process.exitCode = 0;
|
175 | throw err;
|
176 | }
|
177 | }
|
178 | exports.dockerPull = dockerPull;
|
179 | async function dockerStop(name) {
|
180 | await exec({
|
181 | cmd: 'docker',
|
182 | args: ['stop', name],
|
183 | });
|
184 | }
|
185 | exports.dockerStop = dockerStop;
|
186 | async function dockerTag(from, to) {
|
187 | await exec({
|
188 | cmd: 'docker',
|
189 | args: ['tag', from, to],
|
190 | });
|
191 | }
|
192 | exports.dockerTag = dockerTag;
|
193 | async function getContainerInfo(name) {
|
194 | const result = await exec({
|
195 | cmd: 'docker',
|
196 | args: ['ps', '--format={{json .}}', `--filter=name=${name}`],
|
197 | });
|
198 | if (!result)
|
199 | return null;
|
200 | return JSON.parse(result);
|
201 | }
|
202 | exports.getContainerInfo = getContainerInfo;
|
203 | async function dockerNetworkExists(name) {
|
204 | const subprocess = await execa_1.default.command(`docker network ls --format='{{json .Name}}' | grep '"${name}"'`, { reject: false });
|
205 | return subprocess.exitCode > 0;
|
206 | }
|
207 | exports.dockerNetworkExists = dockerNetworkExists;
|
208 | async function remoteDockerImageExists(image) {
|
209 | try {
|
210 | await dockerPull(image, ms_1.default('30s'));
|
211 | return true;
|
212 | }
|
213 | catch (err) {
|
214 | return false;
|
215 | }
|
216 | }
|
217 | exports.remoteDockerImageExists = remoteDockerImageExists;
|
218 | async function dockerRun(opt, tag = 'latest', debug) {
|
219 | const args = ['run', '--rm'];
|
220 | if (!opt.image) {
|
221 | throw new Error('Missing required image option');
|
222 | }
|
223 | if (!opt.name) {
|
224 | throw new Error('Missing required name option');
|
225 | }
|
226 | if (opt.ports && opt.ports.length) {
|
227 | opt.ports.forEach((port) => {
|
228 | if (utils_1.isString(port)) {
|
229 | args.push('--publish', port);
|
230 | }
|
231 | else {
|
232 | args.push('--publish', `${port}:${port}`);
|
233 | }
|
234 | });
|
235 | }
|
236 | if (opt.env) {
|
237 | Object.entries(opt.env).forEach(([key, val]) => {
|
238 | args.push('--env', `${key}=${val}`);
|
239 | });
|
240 | }
|
241 | if (opt.tmpfs && opt.tmpfs.length) {
|
242 | args.push('--tmpfs', opt.tmpfs.join(','));
|
243 | }
|
244 | if (opt.network) {
|
245 | const exists = await dockerNetworkExists(opt.network);
|
246 | if (!exists) {
|
247 | throw new Error(`Docker network ${opt.network} does not exist`);
|
248 | }
|
249 | args.push('--network', opt.network);
|
250 | }
|
251 | args.push('--name', opt.name);
|
252 | args.push(`${opt.image}:${tag}`);
|
253 | let error;
|
254 | let stderr;
|
255 | let done = true;
|
256 | if (debug) {
|
257 | signale_1.default.debug(`executing: docker ${args.join(' ')}`);
|
258 | }
|
259 | const subprocess = execa_1.default('docker', args);
|
260 | if (!subprocess || !subprocess.stderr) {
|
261 | throw new Error('Failed to execute docker run');
|
262 | }
|
263 | (async () => {
|
264 | done = false;
|
265 | try {
|
266 | const result = await subprocess;
|
267 | if (result.exitCode > 0) {
|
268 | stderr = result.all;
|
269 | error = new Error(`${result.command} failed`);
|
270 | }
|
271 | }
|
272 | catch (err) {
|
273 | error = err.stack;
|
274 | stderr = err.all;
|
275 | }
|
276 | finally {
|
277 | done = true;
|
278 | }
|
279 | })();
|
280 | const upFor = ms_1.default('5s');
|
281 | await utils_1.pWhile(() => dockerContainerReady(opt.name, upFor), {
|
282 | timeoutMs: ms_1.default('1m')
|
283 | });
|
284 | if (error) {
|
285 | if (stderr) {
|
286 | process.stderr.write(stderr);
|
287 | }
|
288 | throw error;
|
289 | }
|
290 | if (done) {
|
291 | throw new Error('Service ended early');
|
292 | }
|
293 | return () => {
|
294 | if (error) {
|
295 | if (stderr) {
|
296 | process.stderr.write(stderr);
|
297 | }
|
298 | signale_1.default.error(error);
|
299 | }
|
300 | if (done && !subprocess.killed)
|
301 | return;
|
302 | subprocess.kill();
|
303 | };
|
304 | }
|
305 | exports.dockerRun = dockerRun;
|
306 | async function dockerContainerReady(name, upFor) {
|
307 | try {
|
308 | const result = await exec({
|
309 | cmd: 'docker',
|
310 | args: [
|
311 | 'ps', '--format', '"{{json .Status}}"', '--filter', `name=${name}`
|
312 | ]
|
313 | });
|
314 | const timeup = ms_1.default(result.replace(/[(Up)\s"]+|/ig, ''));
|
315 | if (!timeup)
|
316 | return false;
|
317 | return timeup >= upFor;
|
318 | }
|
319 | catch (err) {
|
320 | await utils_1.pDelay(1000);
|
321 | return false;
|
322 | }
|
323 | }
|
324 | exports.dockerContainerReady = dockerContainerReady;
|
325 | async function dockerBuild(tag, cacheFrom = [], target, buildArg) {
|
326 | const cacheFromArgs = [];
|
327 | cacheFrom.forEach((image) => {
|
328 | cacheFromArgs.push('--cache-from', image);
|
329 | });
|
330 | const targetArgs = target ? ['--target', target] : [];
|
331 | const buildsArgs = buildArg ? ['--build-arg', buildArg] : [];
|
332 | await fork({
|
333 | cmd: 'docker',
|
334 | args: ['build', ...cacheFromArgs, ...targetArgs, ...buildsArgs, '--tag', tag, '.'],
|
335 | });
|
336 | }
|
337 | exports.dockerBuild = dockerBuild;
|
338 | async function dockerPush(image) {
|
339 | const subprocess = await execa_1.default.command(`docker push ${image}`, { reject: false });
|
340 | if (subprocess.exitCode !== 0) {
|
341 | throw new Error(`Unable to push docker image ${image}, ${subprocess.stderr}`);
|
342 | }
|
343 | }
|
344 | exports.dockerPush = dockerPush;
|
345 | async function pgrep(name) {
|
346 | const result = await exec({ cmd: 'ps', args: ['aux'] }, false);
|
347 | if (!result) {
|
348 | throw new Error('Invalid result from ps aux');
|
349 | }
|
350 | const found = result.split('\n').find((line) => {
|
351 | if (!line)
|
352 | return false;
|
353 | return line.toLowerCase().includes(name.toLowerCase());
|
354 | });
|
355 | if (found) {
|
356 | logger.trace('found process', found);
|
357 | return found;
|
358 | }
|
359 | return '';
|
360 | }
|
361 | exports.pgrep = pgrep;
|
362 | async function getCommitHash() {
|
363 | if (process.env.GIT_COMMIT_HASH)
|
364 | return process.env.GIT_COMMIT_HASH;
|
365 | return exec({ cmd: 'git', args: ['rev-parse', '--short', 'HEAD'] });
|
366 | }
|
367 | exports.getCommitHash = getCommitHash;
|
368 | async function gitDiff(files = []) {
|
369 | try {
|
370 | await fork({ cmd: 'git', args: ['diff', ...files] });
|
371 | }
|
372 | catch (e) {
|
373 | process.exitCode = 0;
|
374 | logger.warn(e);
|
375 | }
|
376 | }
|
377 | exports.gitDiff = gitDiff;
|
378 | async function getChangedFiles(...files) {
|
379 | try {
|
380 | const result = await exec({
|
381 | cmd: 'git', args: ['diff', '--name-only', ...files]
|
382 | });
|
383 | return result
|
384 | .split('\n')
|
385 | .map((str) => str.trim())
|
386 | .filter(Boolean);
|
387 | }
|
388 | catch (e) {
|
389 |
|
390 |
|
391 | if (e.toString().includes('ENOENT')) {
|
392 | process.exitCode = 0;
|
393 | logger.warn(e);
|
394 | return [];
|
395 | }
|
396 | throw e;
|
397 | }
|
398 | }
|
399 | exports.getChangedFiles = getChangedFiles;
|
400 | function mapToArgs(input) {
|
401 | const args = [];
|
402 | for (const [key, value] of Object.entries(input)) {
|
403 | const vals = Array.isArray(value) ? value : [value];
|
404 | if (key.length > 1) {
|
405 | args.push(`--${key}`, ...vals);
|
406 | }
|
407 | else {
|
408 | args.push(`-${key}`, ...vals);
|
409 | }
|
410 | }
|
411 | return args.filter((str) => str != null && str !== '');
|
412 | }
|
413 | exports.mapToArgs = mapToArgs;
|
414 | async function yarnPublish(pkgInfo, tag = 'latest', registry = config.NPM_DEFAULT_REGISTRY) {
|
415 | await fork({
|
416 | cmd: 'yarn',
|
417 | args: [
|
418 | 'publish',
|
419 | '--non-interactive',
|
420 | '--new-version',
|
421 | pkgInfo.version,
|
422 | '--no-git-tag-version',
|
423 | '--registry',
|
424 | registry,
|
425 | '--tag',
|
426 | tag
|
427 | ],
|
428 | cwd: pkgInfo.dir,
|
429 | env: {
|
430 | NODE_ENV: 'production'
|
431 | }
|
432 | });
|
433 | }
|
434 | exports.yarnPublish = yarnPublish;
|
435 |
|
\ | No newline at end of file |