@datadog/datadog-ci 0.18.1 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-3rdparty.csv +1 -0
- package/README.md +28 -2
- package/dist/commands/lambda/__tests__/functions/instrument.test.js +2 -2
- package/dist/commands/lambda/__tests__/functions/uninstrument.test.js +2 -2
- package/dist/commands/lambda/__tests__/instrument.test.js +13 -8
- package/dist/commands/lambda/__tests__/prompt.test.js +0 -4
- package/dist/commands/lambda/__tests__/uninstrument.test.js +12 -7
- package/dist/commands/lambda/constants.d.ts +0 -1
- package/dist/commands/lambda/constants.js +2 -27
- package/dist/commands/lambda/functions/commons.js +1 -1
- package/dist/commands/lambda/instrument.js +4 -1
- package/dist/commands/lambda/prompt.d.ts +1 -0
- package/dist/commands/lambda/prompt.js +19 -10
- package/dist/commands/lambda/tags.js +1 -5
- package/dist/commands/lambda/uninstrument.js +1 -1
- package/dist/commands/synthetics/__tests__/cli.test.js +107 -4
- package/dist/commands/synthetics/__tests__/fixtures.d.ts +2 -1
- package/dist/commands/synthetics/__tests__/fixtures.js +4 -1
- package/dist/commands/synthetics/__tests__/reporters/default.test.js +2 -1
- package/dist/commands/synthetics/__tests__/run-test.test.js +4 -4
- package/dist/commands/synthetics/__tests__/utils.test.js +5 -1
- package/dist/commands/synthetics/api.d.ts +1 -0
- package/dist/commands/synthetics/api.js +5 -3
- package/dist/commands/synthetics/command.js +13 -5
- package/dist/commands/synthetics/errors.d.ts +7 -2
- package/dist/commands/synthetics/errors.js +6 -3
- package/dist/commands/synthetics/index.d.ts +1 -1
- package/dist/commands/synthetics/index.js +2 -1
- package/dist/commands/synthetics/interfaces.d.ts +1 -0
- package/dist/commands/synthetics/reporters/default.d.ts +1 -0
- package/dist/commands/synthetics/reporters/default.js +16 -8
- package/dist/commands/synthetics/run-test.js +9 -15
- package/dist/commands/synthetics/utils.js +21 -9
- package/dist/commands/{dependencies → version}/cli.d.ts +0 -0
- package/dist/commands/version/cli.js +27 -0
- package/package.json +15 -3
- package/dist/commands/dependencies/__tests__/helpers/context.d.ts +0 -12
- package/dist/commands/dependencies/__tests__/helpers/context.js +0 -31
- package/dist/commands/dependencies/__tests__/helpers/stream.d.ts +0 -2
- package/dist/commands/dependencies/__tests__/helpers/stream.js +0 -24
- package/dist/commands/dependencies/__tests__/helpers/upload.run.d.ts +0 -13
- package/dist/commands/dependencies/__tests__/helpers/upload.run.js +0 -40
- package/dist/commands/dependencies/__tests__/upload.test.d.ts +0 -1
- package/dist/commands/dependencies/__tests__/upload.test.js +0 -264
- package/dist/commands/dependencies/api.d.ts +0 -2
- package/dist/commands/dependencies/api.js +0 -27
- package/dist/commands/dependencies/cli.js +0 -4
- package/dist/commands/dependencies/interfaces.d.ts +0 -10
- package/dist/commands/dependencies/interfaces.js +0 -2
- package/dist/commands/dependencies/renderer.d.ts +0 -13
- package/dist/commands/dependencies/renderer.js +0 -57
- package/dist/commands/dependencies/upload.d.ts +0 -16
- package/dist/commands/dependencies/upload.js +0 -171
|
@@ -254,10 +254,10 @@ describe('run-test', () => {
|
|
|
254
254
|
});
|
|
255
255
|
test('should throw an error if API or Application key are undefined', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
256
256
|
process.env = {};
|
|
257
|
-
expect(() => runTests.getApiHelper(fixtures_1.ciConfig)).toThrow(new errors_1.
|
|
258
|
-
yield expect(runTests.executeTests(fixtures_1.mockReporter, fixtures_1.ciConfig)).rejects.toMatchError(new errors_1.
|
|
259
|
-
expect(() => runTests.getApiHelper(Object.assign(Object.assign({}, fixtures_1.ciConfig), { appKey: 'fakeappkey' }))).toThrow(new errors_1.
|
|
260
|
-
yield expect(runTests.executeTests(fixtures_1.mockReporter, Object.assign(Object.assign({}, fixtures_1.ciConfig), { appKey: 'fakeappkey' }))).rejects.toMatchError(new errors_1.
|
|
257
|
+
expect(() => runTests.getApiHelper(fixtures_1.ciConfig)).toThrow(new errors_1.CriticalError('MISSING_APP_KEY'));
|
|
258
|
+
yield expect(runTests.executeTests(fixtures_1.mockReporter, fixtures_1.ciConfig)).rejects.toMatchError(new errors_1.CriticalError('MISSING_APP_KEY'));
|
|
259
|
+
expect(() => runTests.getApiHelper(Object.assign(Object.assign({}, fixtures_1.ciConfig), { appKey: 'fakeappkey' }))).toThrow(new errors_1.CriticalError('MISSING_API_KEY'));
|
|
260
|
+
yield expect(runTests.executeTests(fixtures_1.mockReporter, Object.assign(Object.assign({}, fixtures_1.ciConfig), { appKey: 'fakeappkey' }))).rejects.toMatchError(new errors_1.CriticalError('MISSING_API_KEY'));
|
|
261
261
|
}));
|
|
262
262
|
});
|
|
263
263
|
describe('getTestsList', () => {
|
|
@@ -38,6 +38,7 @@ const axios_1 = __importDefault(require("axios"));
|
|
|
38
38
|
const glob_1 = __importDefault(require("glob"));
|
|
39
39
|
const ciHelpers = __importStar(require("../../../helpers/ci"));
|
|
40
40
|
const api_1 = require("../api");
|
|
41
|
+
const errors_1 = require("../errors");
|
|
41
42
|
const interfaces_1 = require("../interfaces");
|
|
42
43
|
const utils = __importStar(require("../utils"));
|
|
43
44
|
const fixtures_1 = require("./fixtures");
|
|
@@ -163,6 +164,9 @@ describe('utils', () => {
|
|
|
163
164
|
if (fakeTests[publicId]) {
|
|
164
165
|
return { data: fakeTests[publicId] };
|
|
165
166
|
}
|
|
167
|
+
const error = new Error('Not found');
|
|
168
|
+
error.status = 404;
|
|
169
|
+
throw error;
|
|
166
170
|
}));
|
|
167
171
|
});
|
|
168
172
|
afterAll(() => {
|
|
@@ -191,7 +195,7 @@ describe('utils', () => {
|
|
|
191
195
|
expect(summary).toEqual(expectedSummary);
|
|
192
196
|
}));
|
|
193
197
|
test('no tests triggered throws an error', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
194
|
-
yield expect(utils.getTestsToTrigger(api, [], fixtures_1.mockReporter)).rejects.toEqual(new
|
|
198
|
+
yield expect(utils.getTestsToTrigger(api, [], fixtures_1.mockReporter)).rejects.toEqual(new errors_1.CiError('NO_TESTS_TO_RUN'));
|
|
195
199
|
}));
|
|
196
200
|
});
|
|
197
201
|
describe('handleConfig', () => {
|
|
@@ -9,6 +9,7 @@ export declare class EndpointError extends Error {
|
|
|
9
9
|
constructor(message: string, status: number);
|
|
10
10
|
}
|
|
11
11
|
export declare const formatBackendErrors: (requestError: AxiosError<BackendError>) => string;
|
|
12
|
+
export declare const isNotFoundError: (error: AxiosError | EndpointError) => boolean;
|
|
12
13
|
export declare const is5xxError: (error: AxiosError | EndpointError) => boolean | 0 | undefined;
|
|
13
14
|
export declare const apiConstructor: (configuration: APIConfiguration) => {
|
|
14
15
|
getPresignedURL: (testIds: string[]) => Promise<{
|
|
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.apiConstructor = exports.is5xxError = exports.formatBackendErrors = exports.EndpointError = void 0;
|
|
12
|
+
exports.apiConstructor = exports.is5xxError = exports.isNotFoundError = exports.formatBackendErrors = exports.EndpointError = void 0;
|
|
13
13
|
const querystring_1 = require("querystring");
|
|
14
14
|
const utils_1 = require("../../helpers/utils");
|
|
15
15
|
const utils_2 = require("./utils");
|
|
@@ -87,9 +87,11 @@ const retryOn5xxErrors = (retries, error) => {
|
|
|
87
87
|
return 500;
|
|
88
88
|
}
|
|
89
89
|
};
|
|
90
|
+
const getErrorHttpStatus = (error) => { var _a; return 'status' in error ? error.status : (_a = error.response) === null || _a === void 0 ? void 0 : _a.status; };
|
|
91
|
+
const isNotFoundError = (error) => getErrorHttpStatus(error) === 404;
|
|
92
|
+
exports.isNotFoundError = isNotFoundError;
|
|
90
93
|
const is5xxError = (error) => {
|
|
91
|
-
|
|
92
|
-
const statusCode = 'status' in error ? error.status : (_a = error.response) === null || _a === void 0 ? void 0 : _a.status;
|
|
94
|
+
const statusCode = getErrorHttpStatus(error);
|
|
93
95
|
return statusCode && statusCode >= 500 && statusCode <= 599;
|
|
94
96
|
};
|
|
95
97
|
exports.is5xxError = is5xxError;
|
|
@@ -68,8 +68,14 @@ class RunTestCommand extends clipanion_1.Command {
|
|
|
68
68
|
catch (error) {
|
|
69
69
|
if (error instanceof errors_1.CiError) {
|
|
70
70
|
this.reportCiError(error, this.reporter);
|
|
71
|
-
if (error instanceof errors_1.CriticalError
|
|
72
|
-
|
|
71
|
+
if (error instanceof errors_1.CriticalError) {
|
|
72
|
+
if (this.config.failOnCriticalErrors) {
|
|
73
|
+
return 1;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
this.reporter.error(chalk_1.default.yellow('Because `failOnCriticalErrors` is not set or disabled, the command will exit with an error code 0. ' +
|
|
77
|
+
'Use `failOnCriticalErrors: true` to exit with an error code 1.\n'));
|
|
78
|
+
}
|
|
73
79
|
}
|
|
74
80
|
}
|
|
75
81
|
return 0;
|
|
@@ -128,12 +134,14 @@ class RunTestCommand extends clipanion_1.Command {
|
|
|
128
134
|
}
|
|
129
135
|
reportCiError(error, reporter) {
|
|
130
136
|
switch (error.code) {
|
|
137
|
+
// Non critical errors
|
|
131
138
|
case 'NO_RESULTS_TO_POLL':
|
|
132
139
|
reporter.log('No results to poll.\n');
|
|
133
140
|
break;
|
|
134
141
|
case 'NO_TESTS_TO_RUN':
|
|
135
142
|
reporter.log('No test to run.\n');
|
|
136
143
|
break;
|
|
144
|
+
// Critical command errors
|
|
137
145
|
case 'MISSING_APP_KEY':
|
|
138
146
|
reporter.error(`Missing ${chalk_1.default.red.bold('DATADOG_APP_KEY')} in your environment.\n`);
|
|
139
147
|
break;
|
|
@@ -144,16 +152,16 @@ class RunTestCommand extends clipanion_1.Command {
|
|
|
144
152
|
reporter.error(`\n${chalk_1.default.bgRed.bold(' ERROR: unable to poll test results ')}\n${error.message}\n\n`);
|
|
145
153
|
break;
|
|
146
154
|
case 'TUNNEL_START_FAILED':
|
|
147
|
-
reporter.error(`\n${chalk_1.default.bgRed.bold(' ERROR: unable to start tunnel')}\n${error.message}\n\n`);
|
|
155
|
+
reporter.error(`\n${chalk_1.default.bgRed.bold(' ERROR: unable to start tunnel ')}\n${error.message}\n\n`);
|
|
148
156
|
break;
|
|
149
157
|
case 'TRIGGER_TESTS_FAILED':
|
|
150
|
-
reporter.error(`\n${chalk_1.default.bgRed.bold(' ERROR: unable to trigger tests')}\n${error.message}\n\n`);
|
|
158
|
+
reporter.error(`\n${chalk_1.default.bgRed.bold(' ERROR: unable to trigger tests ')}\n${error.message}\n\n`);
|
|
151
159
|
break;
|
|
152
160
|
case 'UNAVAILABLE_TEST_CONFIG':
|
|
153
161
|
reporter.error(`\n${chalk_1.default.bgRed.bold(' ERROR: unable to obtain test configurations with search query ')}\n${error.message}\n\n`);
|
|
154
162
|
break;
|
|
155
163
|
case 'UNAVAILABLE_TUNNEL_CONFIG':
|
|
156
|
-
reporter.error(`\n${chalk_1.default.bgRed.bold(' ERROR: unable to get tunnel configuration')}\n${error.message}\n\n`);
|
|
164
|
+
reporter.error(`\n${chalk_1.default.bgRed.bold(' ERROR: unable to get tunnel configuration ')}\n${error.message}\n\n`);
|
|
157
165
|
}
|
|
158
166
|
}
|
|
159
167
|
resolveConfig() {
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
declare const
|
|
2
|
-
declare type
|
|
1
|
+
declare const nonCriticalErrorCodes: readonly ["NO_TESTS_TO_RUN", "NO_RESULTS_TO_POLL"];
|
|
2
|
+
declare type NonCriticalCiErrorCode = typeof nonCriticalErrorCodes[number];
|
|
3
|
+
declare const criticalErrorCodes: readonly ["UNAVAILABLE_TEST_CONFIG", "MISSING_API_KEY", "MISSING_APP_KEY", "UNAVAILABLE_TUNNEL_CONFIG", "TUNNEL_START_FAILED", "TRIGGER_TESTS_FAILED", "POLL_RESULTS_FAILED"];
|
|
4
|
+
declare type CriticalCiErrorCode = typeof criticalErrorCodes[number];
|
|
5
|
+
declare type CiErrorCode = NonCriticalCiErrorCode | CriticalCiErrorCode;
|
|
3
6
|
export declare class CiError extends Error {
|
|
4
7
|
code: CiErrorCode;
|
|
5
8
|
constructor(code: CiErrorCode);
|
|
6
9
|
}
|
|
7
10
|
export declare class CriticalError extends CiError {
|
|
11
|
+
code: CriticalCiErrorCode;
|
|
12
|
+
constructor(code: CriticalCiErrorCode);
|
|
8
13
|
}
|
|
9
14
|
export {};
|
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CriticalError = exports.CiError = void 0;
|
|
4
4
|
/* tslint:disable:max-classes-per-file */
|
|
5
|
-
const
|
|
5
|
+
const nonCriticalErrorCodes = ['NO_TESTS_TO_RUN', 'NO_RESULTS_TO_POLL'];
|
|
6
|
+
const criticalErrorCodes = [
|
|
6
7
|
'UNAVAILABLE_TEST_CONFIG',
|
|
7
8
|
'MISSING_API_KEY',
|
|
8
9
|
'MISSING_APP_KEY',
|
|
9
|
-
'NO_RESULTS_TO_POLL',
|
|
10
|
-
'NO_TESTS_TO_RUN',
|
|
11
10
|
'UNAVAILABLE_TUNNEL_CONFIG',
|
|
12
11
|
'TUNNEL_START_FAILED',
|
|
13
12
|
'TRIGGER_TESTS_FAILED',
|
|
@@ -21,5 +20,9 @@ class CiError extends Error {
|
|
|
21
20
|
}
|
|
22
21
|
exports.CiError = CiError;
|
|
23
22
|
class CriticalError extends CiError {
|
|
23
|
+
constructor(code) {
|
|
24
|
+
super(code);
|
|
25
|
+
this.code = code;
|
|
26
|
+
}
|
|
24
27
|
}
|
|
25
28
|
exports.CriticalError = CriticalError;
|
|
@@ -22,9 +22,10 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
return result;
|
|
23
23
|
};
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.utils = exports.executeTests = exports.DefaultReporter = exports.CiError = void 0;
|
|
25
|
+
exports.utils = exports.executeTests = exports.DefaultReporter = exports.CriticalError = exports.CiError = void 0;
|
|
26
26
|
var errors_1 = require("./errors");
|
|
27
27
|
Object.defineProperty(exports, "CiError", { enumerable: true, get: function () { return errors_1.CiError; } });
|
|
28
|
+
Object.defineProperty(exports, "CriticalError", { enumerable: true, get: function () { return errors_1.CriticalError; } });
|
|
28
29
|
__exportStar(require("./interfaces"), exports);
|
|
29
30
|
var default_1 = require("./reporters/default");
|
|
30
31
|
Object.defineProperty(exports, "DefaultReporter", { enumerable: true, get: function () { return default_1.DefaultReporter; } });
|
|
@@ -11,6 +11,7 @@ export interface MainReporter {
|
|
|
11
11
|
}): void;
|
|
12
12
|
runEnd(summary: Summary): void;
|
|
13
13
|
testEnd(test: Test, results: PollResult[], baseUrl: string, locationNames: LocationsMapping, failOnCriticalErrors: boolean, failOnTimeout: boolean): void;
|
|
14
|
+
testsWait(tests: Test[]): void;
|
|
14
15
|
testTrigger(test: Test, testId: string, executionRule: ExecutionRule, config: ConfigOverride): void;
|
|
15
16
|
testWait(test: Test): void;
|
|
16
17
|
}
|
|
@@ -13,6 +13,7 @@ export declare class DefaultReporter implements MainReporter {
|
|
|
13
13
|
}): void;
|
|
14
14
|
runEnd(summary: Summary): void;
|
|
15
15
|
testEnd(test: Test, results: PollResult[], baseUrl: string, locationNames: LocationsMapping, failOnCriticalErrors: boolean, failOnTimeout: boolean): void;
|
|
16
|
+
testsWait(tests: Test[]): void;
|
|
16
17
|
testTrigger(test: Test, testId: string, executionRule: ExecutionRule, config: ConfigOverride): void;
|
|
17
18
|
testWait(test: Test): void;
|
|
18
19
|
}
|
|
@@ -195,14 +195,14 @@ class DefaultReporter {
|
|
|
195
195
|
this.write(error);
|
|
196
196
|
}
|
|
197
197
|
initErrors(errors) {
|
|
198
|
-
this.write(errors.join('\n'));
|
|
198
|
+
this.write(errors.join('\n') + '\n');
|
|
199
199
|
}
|
|
200
200
|
log(log) {
|
|
201
201
|
this.write(log);
|
|
202
202
|
}
|
|
203
203
|
reportStart(timings) {
|
|
204
204
|
const delay = (Date.now() - timings.startTime).toString();
|
|
205
|
-
this.write(['
|
|
205
|
+
this.write(['', chalk_1.default.bold.cyan('=== REPORT ==='), `Took ${chalk_1.default.bold(delay)}ms`, '\n'].join('\n'));
|
|
206
206
|
}
|
|
207
207
|
runEnd(summary) {
|
|
208
208
|
const summaries = [
|
|
@@ -239,6 +239,15 @@ class DefaultReporter {
|
|
|
239
239
|
.concat('\n\n');
|
|
240
240
|
this.write([`${icon} ${idDisplay}${nonBlockingText} | ${nameColor(test.name)}`, testResultsText].join('\n'));
|
|
241
241
|
}
|
|
242
|
+
testsWait(tests) {
|
|
243
|
+
const testsList = tests.map((t) => t.public_id);
|
|
244
|
+
if (testsList.length > 10) {
|
|
245
|
+
testsList.splice(10);
|
|
246
|
+
testsList.push('…');
|
|
247
|
+
}
|
|
248
|
+
const testsDisplay = chalk_1.default.gray(`(${testsList.join(', ')})`);
|
|
249
|
+
this.write(`\nWaiting for ${chalk_1.default.bold.cyan(tests.length)} test result${tests.length > 1 ? 's' : ''} ${testsDisplay}…\n`);
|
|
250
|
+
}
|
|
242
251
|
testTrigger(test, testId, executionRule, config) {
|
|
243
252
|
const idDisplay = `[${chalk_1.default.bold.dim(testId)}]`;
|
|
244
253
|
const getMessage = () => {
|
|
@@ -246,22 +255,21 @@ class DefaultReporter {
|
|
|
246
255
|
// Test is either skipped from datadog-ci config or from test config
|
|
247
256
|
const isSkippedByCIConfig = config.executionRule === interfaces_1.ExecutionRule.SKIPPED;
|
|
248
257
|
if (isSkippedByCIConfig) {
|
|
249
|
-
return
|
|
258
|
+
return `Skipped test "${chalk_1.default.yellow.dim(test.name)}"`;
|
|
250
259
|
}
|
|
251
260
|
else {
|
|
252
|
-
return
|
|
261
|
+
return `Skipped test "${chalk_1.default.yellow.dim(test.name)}" because of execution rule configuration in Datadog`;
|
|
253
262
|
}
|
|
254
263
|
}
|
|
255
264
|
if (executionRule === interfaces_1.ExecutionRule.NON_BLOCKING) {
|
|
256
|
-
return `
|
|
265
|
+
return `Found test "${chalk_1.default.green.bold(test.name)}" (non-blocking)`;
|
|
257
266
|
}
|
|
258
|
-
return `
|
|
267
|
+
return `Found test "${chalk_1.default.green.bold(test.name)}"`;
|
|
259
268
|
};
|
|
260
269
|
this.write(`${idDisplay} ${getMessage()}\n`);
|
|
261
270
|
}
|
|
262
271
|
testWait(test) {
|
|
263
|
-
|
|
264
|
-
this.write(`${idDisplay} Waiting results for "${chalk_1.default.green.bold(test.name)}"\n`);
|
|
272
|
+
return;
|
|
265
273
|
}
|
|
266
274
|
}
|
|
267
275
|
exports.DefaultReporter = DefaultReporter;
|
|
@@ -32,8 +32,7 @@ const executeTests = (reporter, config) => __awaiter(void 0, void 0, void 0, fun
|
|
|
32
32
|
testsToTrigger = yield exports.getTestsList(api, config, reporter);
|
|
33
33
|
}
|
|
34
34
|
catch (error) {
|
|
35
|
-
|
|
36
|
-
throw new (isCriticalError ? errors_1.CriticalError : errors_1.CiError)('UNAVAILABLE_TEST_CONFIG');
|
|
35
|
+
throw new errors_1.CriticalError('UNAVAILABLE_TEST_CONFIG');
|
|
37
36
|
}
|
|
38
37
|
}
|
|
39
38
|
if (!testsToTrigger.length) {
|
|
@@ -44,8 +43,7 @@ const executeTests = (reporter, config) => __awaiter(void 0, void 0, void 0, fun
|
|
|
44
43
|
testsToTriggerResult = yield utils_1.getTestsToTrigger(api, testsToTrigger, reporter);
|
|
45
44
|
}
|
|
46
45
|
catch (error) {
|
|
47
|
-
|
|
48
|
-
throw new (isCriticalError ? errors_1.CriticalError : errors_1.CiError)('UNAVAILABLE_TEST_CONFIG');
|
|
46
|
+
throw error instanceof errors_1.CiError ? error : new errors_1.CriticalError('UNAVAILABLE_TEST_CONFIG');
|
|
49
47
|
}
|
|
50
48
|
const { tests, overriddenTestsToTrigger, summary } = testsToTriggerResult;
|
|
51
49
|
// All tests have been skipped or are missing.
|
|
@@ -60,8 +58,7 @@ const executeTests = (reporter, config) => __awaiter(void 0, void 0, void 0, fun
|
|
|
60
58
|
presignedURL = (yield api.getPresignedURL(publicIdsToTrigger)).url;
|
|
61
59
|
}
|
|
62
60
|
catch (error) {
|
|
63
|
-
|
|
64
|
-
throw new (isCriticalError ? errors_1.CriticalError : errors_1.CiError)('UNAVAILABLE_TUNNEL_CONFIG');
|
|
61
|
+
throw new errors_1.CriticalError('UNAVAILABLE_TUNNEL_CONFIG');
|
|
65
62
|
}
|
|
66
63
|
// Open a tunnel to Datadog
|
|
67
64
|
try {
|
|
@@ -72,9 +69,8 @@ const executeTests = (reporter, config) => __awaiter(void 0, void 0, void 0, fun
|
|
|
72
69
|
});
|
|
73
70
|
}
|
|
74
71
|
catch (error) {
|
|
75
|
-
const isCriticalError = api_1.is5xxError(error);
|
|
76
72
|
yield stopTunnel();
|
|
77
|
-
throw new
|
|
73
|
+
throw new errors_1.CriticalError('TUNNEL_START_FAILED');
|
|
78
74
|
}
|
|
79
75
|
}
|
|
80
76
|
let triggers;
|
|
@@ -82,13 +78,12 @@ const executeTests = (reporter, config) => __awaiter(void 0, void 0, void 0, fun
|
|
|
82
78
|
triggers = yield utils_1.runTests(api, overriddenTestsToTrigger);
|
|
83
79
|
}
|
|
84
80
|
catch (error) {
|
|
85
|
-
const isCriticalError = api_1.is5xxError(error);
|
|
86
81
|
yield stopTunnel();
|
|
87
|
-
throw new
|
|
82
|
+
throw new errors_1.CriticalError('TRIGGER_TESTS_FAILED');
|
|
88
83
|
}
|
|
89
84
|
if (!triggers.results) {
|
|
90
85
|
yield stopTunnel();
|
|
91
|
-
throw new errors_1.
|
|
86
|
+
throw new errors_1.CiError('NO_RESULTS_TO_POLL');
|
|
92
87
|
}
|
|
93
88
|
const results = {};
|
|
94
89
|
try {
|
|
@@ -97,8 +92,7 @@ const executeTests = (reporter, config) => __awaiter(void 0, void 0, void 0, fun
|
|
|
97
92
|
Object.assign(results, resultPolled);
|
|
98
93
|
}
|
|
99
94
|
catch (error) {
|
|
100
|
-
|
|
101
|
-
throw new (isCriticalError ? errors_1.CriticalError : errors_1.CiError)('POLL_RESULTS_FAILED');
|
|
95
|
+
throw new errors_1.CriticalError('POLL_RESULTS_FAILED');
|
|
102
96
|
}
|
|
103
97
|
finally {
|
|
104
98
|
yield stopTunnel();
|
|
@@ -132,10 +126,10 @@ const getTestsList = (api, config, reporter) => __awaiter(void 0, void 0, void 0
|
|
|
132
126
|
exports.getTestsList = getTestsList;
|
|
133
127
|
const getApiHelper = (config) => {
|
|
134
128
|
if (!config.appKey) {
|
|
135
|
-
throw new errors_1.
|
|
129
|
+
throw new errors_1.CriticalError('MISSING_APP_KEY');
|
|
136
130
|
}
|
|
137
131
|
if (!config.apiKey) {
|
|
138
|
-
throw new errors_1.
|
|
132
|
+
throw new errors_1.CriticalError('MISSING_API_KEY');
|
|
139
133
|
}
|
|
140
134
|
return api_1.apiConstructor({
|
|
141
135
|
apiKey: config.apiKey,
|
|
@@ -41,6 +41,7 @@ const glob_1 = __importDefault(require("glob"));
|
|
|
41
41
|
const ci_1 = require("../../helpers/ci");
|
|
42
42
|
const utils_1 = require("../../helpers/utils");
|
|
43
43
|
const api_1 = require("./api");
|
|
44
|
+
const errors_1 = require("./errors");
|
|
44
45
|
const interfaces_1 = require("./interfaces");
|
|
45
46
|
const POLLING_INTERVAL = 5000; // In ms
|
|
46
47
|
const PUBLIC_ID_REGEX = /^[\d\w]{3}-[\d\w]{3}-[\d\w]{3}$/;
|
|
@@ -370,6 +371,13 @@ const getReporter = (reporters) => ({
|
|
|
370
371
|
}
|
|
371
372
|
}
|
|
372
373
|
},
|
|
374
|
+
testsWait: (tests) => {
|
|
375
|
+
for (const reporter of reporters) {
|
|
376
|
+
if (typeof reporter.testsWait === 'function') {
|
|
377
|
+
reporter.testsWait(tests);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
},
|
|
373
381
|
});
|
|
374
382
|
exports.getReporter = getReporter;
|
|
375
383
|
const getTestsToTrigger = (api, triggerConfigs, reporter) => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -382,14 +390,14 @@ const getTestsToTrigger = (api, triggerConfigs, reporter) => __awaiter(void 0, v
|
|
|
382
390
|
try {
|
|
383
391
|
test = Object.assign(Object.assign({}, (yield api.getTest(id))), { suite });
|
|
384
392
|
}
|
|
385
|
-
catch (
|
|
386
|
-
if (api_1.
|
|
387
|
-
|
|
393
|
+
catch (error) {
|
|
394
|
+
if (api_1.isNotFoundError(error)) {
|
|
395
|
+
summary.testsNotFound.add(id);
|
|
396
|
+
const errorMessage = api_1.formatBackendErrors(error);
|
|
397
|
+
errorMessages.push(`[${chalk_1.default.bold.dim(id)}] ${chalk_1.default.yellow.bold('Test not found')}: ${errorMessage}`);
|
|
398
|
+
return;
|
|
388
399
|
}
|
|
389
|
-
|
|
390
|
-
const errorMessage = api_1.formatBackendErrors(e);
|
|
391
|
-
errorMessages.push(`[${chalk_1.default.bold.dim(id)}] ${chalk_1.default.yellow.bold('Test not found')}: ${errorMessage}\n`);
|
|
392
|
-
return;
|
|
400
|
+
throw error;
|
|
393
401
|
}
|
|
394
402
|
const overriddenConfig = exports.handleConfig(test, id, reporter, config);
|
|
395
403
|
overriddenTestsToTrigger.push(overriddenConfig);
|
|
@@ -405,9 +413,13 @@ const getTestsToTrigger = (api, triggerConfigs, reporter) => __awaiter(void 0, v
|
|
|
405
413
|
// Display errors at the end of all tests for better visibility.
|
|
406
414
|
reporter.initErrors(errorMessages);
|
|
407
415
|
if (!overriddenTestsToTrigger.length) {
|
|
408
|
-
throw new
|
|
416
|
+
throw new errors_1.CiError('NO_TESTS_TO_RUN');
|
|
417
|
+
}
|
|
418
|
+
const waitedTests = tests.filter(definedTypeGuard);
|
|
419
|
+
if (waitedTests.length > 0) {
|
|
420
|
+
reporter.testsWait(waitedTests);
|
|
409
421
|
}
|
|
410
|
-
return { tests:
|
|
422
|
+
return { tests: waitedTests, overriddenTestsToTrigger, summary };
|
|
411
423
|
});
|
|
412
424
|
exports.getTestsToTrigger = getTestsToTrigger;
|
|
413
425
|
const runTests = (api, testsToTrigger) => __awaiter(void 0, void 0, void 0, function* () {
|
|
File without changes
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const clipanion_1 = require("clipanion");
|
|
13
|
+
class VersionCommand extends clipanion_1.Command {
|
|
14
|
+
execute() {
|
|
15
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
16
|
+
const { version } = require('../../../package.json');
|
|
17
|
+
this.context.stdout.write(`v${version}\n`);
|
|
18
|
+
return 0;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
VersionCommand.usage = clipanion_1.Command.Usage({
|
|
23
|
+
description: 'Get the current version of datadog-ci.',
|
|
24
|
+
examples: [['Get the current version of datadog-ci', 'datadog-ci version']],
|
|
25
|
+
});
|
|
26
|
+
VersionCommand.addPath('version');
|
|
27
|
+
module.exports = [VersionCommand];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datadog/datadog-ci",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Run datadog actions from the CI.",
|
|
5
5
|
"repository": "https://github.com/DataDog/datadog-ci",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -23,10 +23,21 @@
|
|
|
23
23
|
"ini": "1.3.7",
|
|
24
24
|
"kind-of@^6.0.0": "6.0.3"
|
|
25
25
|
},
|
|
26
|
+
"pkg": {
|
|
27
|
+
"scripts": [
|
|
28
|
+
"dist/commands/*/*.js",
|
|
29
|
+
"node_modules/vm2/lib/contextify.js",
|
|
30
|
+
"node_modules/vm2/lib/setup-sandbox.js"
|
|
31
|
+
]
|
|
32
|
+
},
|
|
26
33
|
"scripts": {
|
|
27
34
|
"build": "yarn clean; tsc",
|
|
35
|
+
"build:win": "tsc",
|
|
28
36
|
"check-licenses": "node bin/check-licenses.js",
|
|
37
|
+
"clean:win": "rm dist -r",
|
|
29
38
|
"clean": "rm -rf dist/*",
|
|
39
|
+
"dist-standalone": "pkg --compress GZip .",
|
|
40
|
+
"dist-standalone:test": "jest --config ./jest.config-standalone.js",
|
|
30
41
|
"format": "yarn tslint --fix && yarn prettier --write",
|
|
31
42
|
"launch": "ts-node --transpile-only src/cli.ts",
|
|
32
43
|
"launch:debug": "node -r ts-node/register/transpile-only --inspect-brk src/cli.ts",
|
|
@@ -40,6 +51,7 @@
|
|
|
40
51
|
"watch": "tsc -w"
|
|
41
52
|
},
|
|
42
53
|
"dependencies": {
|
|
54
|
+
"@types/datadog-metrics": "0.6.1",
|
|
43
55
|
"async-retry": "1.3.1",
|
|
44
56
|
"aws-sdk": "2.1012.0",
|
|
45
57
|
"axios": "0.21.2",
|
|
@@ -52,7 +64,7 @@
|
|
|
52
64
|
"glob": "7.1.4",
|
|
53
65
|
"inquirer": "8.2.0",
|
|
54
66
|
"proxy-agent": "5.0.0",
|
|
55
|
-
"simple-git": "
|
|
67
|
+
"simple-git": "3.3.0",
|
|
56
68
|
"ssh2": "1.4.0",
|
|
57
69
|
"ssh2-streams": "0.4.10",
|
|
58
70
|
"sshpk": "1.16.1",
|
|
@@ -66,7 +78,6 @@
|
|
|
66
78
|
"@babel/preset-env": "7.4.5",
|
|
67
79
|
"@babel/preset-typescript": "7.3.3",
|
|
68
80
|
"@types/async-retry": "1.4.2",
|
|
69
|
-
"@types/datadog-metrics": "0.6.1",
|
|
70
81
|
"@types/deep-extend": "0.4.31",
|
|
71
82
|
"@types/glob": "7.1.1",
|
|
72
83
|
"@types/inquirer": "8.1.3",
|
|
@@ -82,6 +93,7 @@
|
|
|
82
93
|
"jest": "27.0.5",
|
|
83
94
|
"jest-environment-node": "27.0.5",
|
|
84
95
|
"jest-matcher-specific-error": "1.0.0",
|
|
96
|
+
"pkg": "5.5.2",
|
|
85
97
|
"prettier": "2.0.5",
|
|
86
98
|
"proxy": "1.0.2",
|
|
87
99
|
"ts-jest": "27.0.3",
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
import { BaseContext } from 'clipanion/lib/advanced';
|
|
3
|
-
import { Writable } from 'stream';
|
|
4
|
-
interface WritableToString extends Writable {
|
|
5
|
-
toString(): string;
|
|
6
|
-
}
|
|
7
|
-
export interface MockContext extends BaseContext {
|
|
8
|
-
stderr: WritableToString;
|
|
9
|
-
stdout: WritableToString;
|
|
10
|
-
}
|
|
11
|
-
export declare const createMockContext: () => MockContext;
|
|
12
|
-
export {};
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createMockContext = void 0;
|
|
4
|
-
const stream_1 = require("stream");
|
|
5
|
-
const createMockContext = () => {
|
|
6
|
-
const buffer = {
|
|
7
|
-
stderr: [],
|
|
8
|
-
stdout: [],
|
|
9
|
-
};
|
|
10
|
-
const stderr = new stream_1.Writable({
|
|
11
|
-
write(chunk, encoding, callback) {
|
|
12
|
-
buffer.stderr.push(chunk);
|
|
13
|
-
callback();
|
|
14
|
-
},
|
|
15
|
-
});
|
|
16
|
-
const stdout = new stream_1.Writable({
|
|
17
|
-
write(chunk, encoding, callback) {
|
|
18
|
-
buffer.stdout.push(chunk);
|
|
19
|
-
callback();
|
|
20
|
-
},
|
|
21
|
-
});
|
|
22
|
-
const stdin = new stream_1.Readable();
|
|
23
|
-
Object.assign(stderr, { toString: () => buffer.stderr.join('') });
|
|
24
|
-
Object.assign(stdout, { toString: () => buffer.stdout.join('') });
|
|
25
|
-
return {
|
|
26
|
-
stderr,
|
|
27
|
-
stdin,
|
|
28
|
-
stdout,
|
|
29
|
-
};
|
|
30
|
-
};
|
|
31
|
-
exports.createMockContext = createMockContext;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.streamToString = void 0;
|
|
4
|
-
const streamToString = (stream) => {
|
|
5
|
-
const chunks = [];
|
|
6
|
-
return new Promise((resolve, reject) => {
|
|
7
|
-
const handleData = (chunk) => chunks.push(chunk);
|
|
8
|
-
const handleError = (error) => {
|
|
9
|
-
stream.off('data', handleData);
|
|
10
|
-
stream.off('end', handleEnd);
|
|
11
|
-
reject(error);
|
|
12
|
-
};
|
|
13
|
-
const handleEnd = () => {
|
|
14
|
-
stream.off('data', handleData);
|
|
15
|
-
stream.off('error', handleError);
|
|
16
|
-
resolve(chunks.join(''));
|
|
17
|
-
};
|
|
18
|
-
stream.on('data', handleData);
|
|
19
|
-
stream.once('error', handleError);
|
|
20
|
-
stream.once('end', handleEnd);
|
|
21
|
-
stream.resume();
|
|
22
|
-
});
|
|
23
|
-
};
|
|
24
|
-
exports.streamToString = streamToString;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
interface RunUploadInput {
|
|
2
|
-
apiKey?: string;
|
|
3
|
-
appKey?: string;
|
|
4
|
-
dryRun?: boolean;
|
|
5
|
-
releaseVersion?: string;
|
|
6
|
-
service?: string;
|
|
7
|
-
source?: string;
|
|
8
|
-
}
|
|
9
|
-
export declare const runUploadCommand: (filePath: string, input: RunUploadInput) => Promise<{
|
|
10
|
-
context: import("./context").MockContext;
|
|
11
|
-
code: number;
|
|
12
|
-
}>;
|
|
13
|
-
export {};
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.runUploadCommand = void 0;
|
|
13
|
-
const advanced_1 = require("clipanion/lib/advanced");
|
|
14
|
-
const upload_1 = require("../../upload");
|
|
15
|
-
const context_1 = require("./context");
|
|
16
|
-
const runUploadCommand = (filePath, input) => __awaiter(void 0, void 0, void 0, function* () {
|
|
17
|
-
const cli = new advanced_1.Cli();
|
|
18
|
-
cli.register(upload_1.UploadCommand);
|
|
19
|
-
const context = context_1.createMockContext();
|
|
20
|
-
process.env = {
|
|
21
|
-
DATADOG_API_KEY: input.apiKey,
|
|
22
|
-
DATADOG_APP_KEY: input.appKey,
|
|
23
|
-
};
|
|
24
|
-
const params = ['dependencies', 'upload', filePath];
|
|
25
|
-
if (input.releaseVersion) {
|
|
26
|
-
params.push('--release-version', input.releaseVersion);
|
|
27
|
-
}
|
|
28
|
-
if (input.service) {
|
|
29
|
-
params.push('--service', input.service);
|
|
30
|
-
}
|
|
31
|
-
if (input.source) {
|
|
32
|
-
params.push('--source', input.source);
|
|
33
|
-
}
|
|
34
|
-
if (input.dryRun) {
|
|
35
|
-
params.push('--dry-run');
|
|
36
|
-
}
|
|
37
|
-
const code = yield cli.run(params, context);
|
|
38
|
-
return { context, code };
|
|
39
|
-
});
|
|
40
|
-
exports.runUploadCommand = runUploadCommand;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|