UNPKG

5.44 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const color_1 = require("@heroku-cli/color");
4const https_1 = require("https");
5const cli_ux_1 = require("cli-ux");
6function logStream(url, fn) {
7 return https_1.get(url, fn);
8}
9function stream(url) {
10 return new Promise((resolve, reject) => {
11 const request = logStream(url, output => {
12 output.on('data', data => {
13 if (data.toString() === Buffer.from('').toString()) {
14 request.abort();
15 resolve();
16 }
17 });
18 output.on('end', () => resolve());
19 output.on('error', e => reject(e));
20 output.pipe(process.stdout);
21 });
22 });
23}
24function statusIcon({ status }) {
25 if (!status) {
26 return color_1.default.yellow('-');
27 }
28 switch (status) {
29 case 'pending':
30 case 'creating':
31 case 'building':
32 case 'running':
33 case 'debugging':
34 return color_1.default.yellow('-');
35 case 'errored':
36 return color_1.default.red('!');
37 case 'failed':
38 return color_1.default.red('✗');
39 case 'succeeded':
40 return color_1.default.green('✓');
41 case 'cancelled':
42 return color_1.default.yellow('!');
43 default:
44 return color_1.default.yellow('?');
45 }
46}
47function printLine(testRun) {
48 return `${statusIcon(testRun)} #${testRun.number} ${testRun.commit_branch}:${testRun.commit_sha.slice(0, 7)} ${testRun.status}`;
49}
50function printLineTestNode(testNode) {
51 return `${statusIcon(testNode)} #${testNode.index} ${testNode.status}`;
52}
53function processExitCode(command, testNode) {
54 if (testNode.exit_code && testNode.exit_code !== 0) {
55 command.exit(testNode.exit_code);
56 }
57}
58async function renderNodeOutput(command, testRun, testNode) {
59 await stream(testNode.setup_stream_url);
60 await stream(testNode.output_stream_url);
61 command.log();
62 command.log(printLine(testRun));
63}
64const BUILDING = 'building';
65const RUNNING = 'running';
66const ERRORED = 'errored';
67const FAILED = 'failed';
68const SUCCEEDED = 'succeeded';
69const CANCELLED = 'cancelled';
70const TERMINAL_STATES = [SUCCEEDED, FAILED, ERRORED, CANCELLED];
71const RUNNING_STATES = [RUNNING].concat(TERMINAL_STATES);
72const BUILDING_STATES = [BUILDING, RUNNING].concat(TERMINAL_STATES);
73async function waitForStates(states, testRun, command) {
74 let newTestRun = testRun;
75 while (!states.includes(newTestRun.status.toString())) {
76 let { body: bodyTestRun } = await command.heroku.get(`/pipelines/${testRun.pipeline.id}/test-runs/${testRun.number}`);
77 newTestRun = bodyTestRun;
78 }
79 return newTestRun;
80}
81async function display(pipeline, number, command) {
82 let { body: testRun } = await command.heroku.get(`/pipelines/${pipeline.id}/test-runs/${number}`);
83 if (testRun) {
84 cli_ux_1.default.action.start('Waiting for build to start');
85 testRun = await waitForStates(BUILDING_STATES, testRun, command);
86 cli_ux_1.default.done();
87 let { body: testNodes } = await command.heroku.get(`/test-runs/${testRun.id}/test-nodes`);
88 let firstTestNode = testNodes[0];
89 if (firstTestNode) {
90 await stream(firstTestNode.setup_stream_url);
91 }
92 if (testRun) {
93 testRun = await waitForStates(RUNNING_STATES, testRun, command);
94 }
95 if (firstTestNode) {
96 await stream(firstTestNode.output_stream_url);
97 }
98 if (testRun) {
99 testRun = await waitForStates(TERMINAL_STATES, testRun, command);
100 }
101 // At this point, we know that testRun has a finished status,
102 // and we can check for exit_code from firstTestNode
103 if (testRun) {
104 let { body: newTestNodes } = await command.heroku.get(`/test-runs/${testRun.id}/test-nodes`);
105 firstTestNode = newTestNodes[0];
106 command.log();
107 command.log(printLine(testRun));
108 }
109 return firstTestNode;
110 }
111}
112async function displayAndExit(pipeline, number, command) {
113 let testNode = await display(pipeline, number, command);
114 testNode ? processExitCode(command, testNode) : command.exit(1);
115}
116exports.displayAndExit = displayAndExit;
117async function displayTestRunInfo(command, testRun, testNodes, nodeArg) {
118 let testNode;
119 if (nodeArg) {
120 const nodeIndex = parseInt(nodeArg, 2);
121 testNode = testNodes.length > 1 ? testNodes[nodeIndex] : testNodes[0];
122 await renderNodeOutput(command, testRun, testNode);
123 if (testNodes.length === 1) {
124 command.log();
125 command.warn('This pipeline doesn\'t have parallel test runs, but you specified a node');
126 command.warn('See https://devcenter.heroku.com/articles/heroku-ci-parallel-test-runs for more info');
127 }
128 processExitCode(command, testNode);
129 }
130 else {
131 if (testNodes.length > 1) {
132 command.log(printLine(testRun));
133 command.log();
134 testNodes.forEach(testNode => {
135 command.log(printLineTestNode(testNode));
136 });
137 }
138 else {
139 testNode = testNodes[0];
140 await renderNodeOutput(command, testRun, testNode);
141 processExitCode(command, testNode);
142 }
143 }
144}
145exports.displayTestRunInfo = displayTestRunInfo;