@datadog/datadog-ci 0.17.9 → 0.17.13

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.
Files changed (81) hide show
  1. package/LICENSE-3rdparty.csv +2 -0
  2. package/README.md +9 -2
  3. package/dist/{commands/dependencies/index.d.ts → cli.d.ts} +0 -0
  4. package/dist/cli.js +34 -0
  5. package/dist/commands/{dsyms/index.d.ts → dependencies/cli.d.ts} +0 -0
  6. package/dist/commands/dependencies/{index.js → cli.js} +0 -0
  7. package/dist/commands/dependencies/upload.d.ts +1 -1
  8. package/dist/commands/{git-metadata/index.d.ts → dsyms/cli.d.ts} +0 -0
  9. package/dist/commands/dsyms/{index.js → cli.js} +0 -0
  10. package/dist/commands/dsyms/upload.d.ts +1 -1
  11. package/dist/commands/{junit/index.d.ts → git-metadata/cli.d.ts} +0 -0
  12. package/dist/commands/git-metadata/{index.js → cli.js} +0 -0
  13. package/dist/commands/git-metadata/upload.d.ts +1 -1
  14. package/dist/commands/git-metadata/upload.js +6 -1
  15. package/dist/commands/{lambda/index.d.ts → junit/cli.d.ts} +0 -0
  16. package/dist/commands/junit/{index.js → cli.js} +0 -0
  17. package/dist/commands/junit/upload.d.ts +1 -1
  18. package/dist/commands/junit/upload.js +1 -1
  19. package/dist/commands/lambda/__tests__/fixtures.d.ts +5 -1
  20. package/dist/commands/lambda/__tests__/fixtures.js +13 -2
  21. package/dist/commands/lambda/__tests__/functions/commons.test.js +400 -0
  22. package/dist/commands/lambda/__tests__/functions/instrument.test.js +229 -117
  23. package/dist/commands/lambda/__tests__/functions/uninstrument.test.js +80 -7
  24. package/dist/commands/lambda/__tests__/instrument.test.js +542 -111
  25. package/dist/commands/{sourcemaps/index.d.ts → lambda/__tests__/prompt.test.d.ts} +0 -0
  26. package/dist/commands/lambda/__tests__/prompt.test.js +216 -0
  27. package/dist/commands/lambda/__tests__/uninstrument.test.js +381 -17
  28. package/dist/commands/{trace/index.d.ts → lambda/cli.d.ts} +0 -0
  29. package/dist/commands/lambda/{index.js → cli.js} +0 -0
  30. package/dist/commands/lambda/constants.d.ts +27 -6
  31. package/dist/commands/lambda/constants.js +63 -6
  32. package/dist/commands/lambda/functions/commons.d.ts +49 -4
  33. package/dist/commands/lambda/functions/commons.js +198 -7
  34. package/dist/commands/lambda/functions/instrument.d.ts +5 -14
  35. package/dist/commands/lambda/functions/instrument.js +63 -80
  36. package/dist/commands/lambda/functions/uninstrument.d.ts +3 -2
  37. package/dist/commands/lambda/functions/uninstrument.js +23 -11
  38. package/dist/commands/lambda/instrument.d.ts +2 -1
  39. package/dist/commands/lambda/instrument.js +112 -58
  40. package/dist/commands/lambda/interfaces.d.ts +4 -1
  41. package/dist/commands/lambda/loggroup.js +3 -1
  42. package/dist/commands/lambda/prompt.d.ts +9 -0
  43. package/dist/commands/lambda/prompt.js +187 -0
  44. package/dist/commands/lambda/uninstrument.d.ts +2 -0
  45. package/dist/commands/lambda/uninstrument.js +107 -30
  46. package/dist/commands/sourcemaps/cli.d.ts +1 -0
  47. package/dist/commands/sourcemaps/{index.js → cli.js} +0 -0
  48. package/dist/commands/sourcemaps/upload.d.ts +1 -1
  49. package/dist/commands/synthetics/__tests__/cli.test.js +36 -13
  50. package/dist/commands/synthetics/__tests__/fixtures.js +1 -0
  51. package/dist/commands/synthetics/__tests__/run-test.test.js +48 -2
  52. package/dist/commands/synthetics/__tests__/utils.test.js +11 -4
  53. package/dist/commands/synthetics/__tests__/websocket.test.js +3 -3
  54. package/dist/commands/synthetics/cli.d.ts +1 -26
  55. package/dist/commands/synthetics/cli.js +2 -227
  56. package/dist/commands/synthetics/command.d.ts +27 -0
  57. package/dist/commands/synthetics/command.js +236 -0
  58. package/dist/commands/synthetics/index.d.ts +5 -1
  59. package/dist/commands/synthetics/index.js +31 -2
  60. package/dist/commands/synthetics/interfaces.d.ts +8 -3
  61. package/dist/commands/synthetics/interfaces.js +7 -3
  62. package/dist/commands/synthetics/reporters/default.js +5 -1
  63. package/dist/commands/synthetics/run-test.js +3 -1
  64. package/dist/commands/synthetics/utils.d.ts +3 -3
  65. package/dist/commands/synthetics/utils.js +17 -8
  66. package/dist/commands/trace/api.js +1 -1
  67. package/dist/commands/trace/cli.d.ts +1 -0
  68. package/dist/commands/trace/{index.js → cli.js} +0 -0
  69. package/dist/commands/trace/trace.d.ts +1 -1
  70. package/dist/helpers/__tests__/ci.test.js +97 -136
  71. package/dist/helpers/__tests__/user-provided-git.test.js +81 -27
  72. package/dist/helpers/__tests__/utils.test.js +4 -0
  73. package/dist/helpers/ci.js +54 -95
  74. package/dist/helpers/interfaces.d.ts +28 -2
  75. package/dist/helpers/user-provided-git.d.ts +2 -1
  76. package/dist/helpers/user-provided-git.js +29 -5
  77. package/dist/helpers/utils.d.ts +4 -0
  78. package/dist/helpers/utils.js +18 -1
  79. package/dist/index.d.ts +3 -1
  80. package/dist/index.js +23 -31
  81. package/package.json +10 -8
@@ -14,51 +14,130 @@ const aws_sdk_1 = require("aws-sdk");
14
14
  const chalk_1 = require("chalk");
15
15
  const clipanion_1 = require("clipanion");
16
16
  const utils_1 = require("../../helpers/utils");
17
+ const constants_1 = require("./constants");
17
18
  const commons_1 = require("./functions/commons");
18
19
  const uninstrument_1 = require("./functions/uninstrument");
20
+ const prompt_1 = require("./prompt");
19
21
  class UninstrumentCommand extends clipanion_1.Command {
20
22
  constructor() {
21
23
  super(...arguments);
22
24
  this.config = {
23
25
  functions: [],
24
- region: process.env.AWS_DEFAULT_REGION,
26
+ region: process.env[constants_1.AWS_DEFAULT_REGION_ENV_VAR],
25
27
  };
26
28
  this.dryRun = false;
27
29
  this.functions = [];
30
+ this.interactive = false;
28
31
  }
29
32
  execute() {
33
+ var _a, _b, _c;
30
34
  return __awaiter(this, void 0, void 0, function* () {
31
35
  const lambdaConfig = { lambda: this.config };
32
36
  this.config = (yield utils_1.parseConfigFile(lambdaConfig, this.configPath)).lambda;
33
- const hasSpecifiedFuntions = this.functions.length !== 0 || this.config.functions.length !== 0;
34
- if (!hasSpecifiedFuntions) {
35
- this.context.stdout.write('No functions specified for un-instrumentation.\n');
36
- return 1;
37
+ let hasSpecifiedFunctions = this.functions.length !== 0 || this.config.functions.length !== 0;
38
+ if (this.interactive) {
39
+ try {
40
+ if (commons_1.isMissingAWSCredentials()) {
41
+ this.context.stdout.write(`${chalk_1.bold(chalk_1.yellow('[!]'))} No existing AWS credentials found, let's set them up!\n`);
42
+ yield prompt_1.requestAWSCredentials();
43
+ }
44
+ }
45
+ catch (e) {
46
+ this.context.stdout.write(`${chalk_1.red('[Error]')} ${e}\n`);
47
+ return 1;
48
+ }
49
+ const region = (_b = (_a = this.region) !== null && _a !== void 0 ? _a : this.config.region) !== null && _b !== void 0 ? _b : process.env[constants_1.AWS_DEFAULT_REGION_ENV_VAR];
50
+ this.region = region;
51
+ if (!hasSpecifiedFunctions) {
52
+ try {
53
+ const lambda = new aws_sdk_1.Lambda({ region });
54
+ this.context.stdout.write('Fetching Lambda functions, this might take a while.\n');
55
+ const functionNames = (_c = (yield commons_1.getAllLambdaFunctionConfigs(lambda)).map((config) => config.FunctionName).sort()) !== null && _c !== void 0 ? _c : [];
56
+ if (functionNames.length === 0) {
57
+ this.context.stdout.write(`${chalk_1.red('[Error]')} Couldn't find any Lambda functions in the specified region.\n`);
58
+ return 1;
59
+ }
60
+ const functions = yield prompt_1.requestFunctionSelection(functionNames);
61
+ this.functions = functions;
62
+ }
63
+ catch (err) {
64
+ this.context.stdout.write(`${chalk_1.red('[Error]')} Couldn't fetch Lambda functions. ${err}\n`);
65
+ return 1;
66
+ }
67
+ }
37
68
  }
38
- const functionGroups = commons_1.collectFunctionsByRegion(this.functions.length !== 0 ? this.functions : this.config.functions, this.region || this.config.region);
39
- if (functionGroups === undefined) {
69
+ hasSpecifiedFunctions = this.functions.length !== 0 || this.config.functions.length !== 0;
70
+ const hasSpecifiedRegExPattern = this.regExPattern !== undefined && this.regExPattern !== '';
71
+ if (!hasSpecifiedFunctions && !hasSpecifiedRegExPattern) {
72
+ this.context.stdout.write(`${chalk_1.red('[Error]')} No functions specified for un-instrumentation.\n`);
40
73
  return 1;
41
74
  }
42
75
  const configGroups = [];
43
76
  // Fetch lambda function configurations that are
44
77
  // available to be un-instrumented.
45
- for (const [region, functionList] of Object.entries(functionGroups)) {
46
- const lambda = new aws_sdk_1.Lambda({ region });
47
- const cloudWatchLogs = new aws_sdk_1.CloudWatchLogs({ region });
78
+ if (hasSpecifiedRegExPattern) {
79
+ if (hasSpecifiedFunctions) {
80
+ const usedCommand = this.functions.length !== 0 ? '"--functions"' : 'Functions in config file';
81
+ this.context.stdout.write(`${chalk_1.red('[Error]')} ${usedCommand} and "--functions-regex" should not be used at the same time.\n`);
82
+ return 1;
83
+ }
84
+ if (this.regExPattern.match(':')) {
85
+ this.context.stdout.write(`${chalk_1.red('[Error]')} "--functions-regex" isn't meant to be used with ARNs.\n`);
86
+ return 1;
87
+ }
88
+ const region = this.region || this.config.region;
89
+ if (!region) {
90
+ this.context.stdout.write(`${chalk_1.red('[Error]')} No default region specified. Use \`-r\`, \`--region\`.`);
91
+ return 1;
92
+ }
48
93
  try {
49
- const configs = yield uninstrument_1.getFunctionConfigs(lambda, cloudWatchLogs, functionList, this.forwarder);
94
+ const cloudWatchLogs = new aws_sdk_1.CloudWatchLogs({ region });
95
+ const lambda = new aws_sdk_1.Lambda({ region });
96
+ this.context.stdout.write('Fetching Lambda functions, this might take a while.\n');
97
+ const configs = yield uninstrument_1.getUninstrumentedFunctionConfigsFromRegEx(lambda, cloudWatchLogs, this.regExPattern, this.forwarder);
50
98
  configGroups.push({ configs, lambda, cloudWatchLogs });
51
99
  }
52
100
  catch (err) {
53
- this.context.stdout.write(`${chalk_1.red('[Error]')} Couldn't fetch lambda functions. ${err}\n`);
101
+ this.context.stdout.write(`${chalk_1.red('[Error]')} Couldn't fetch Lambda functions. ${err}\n`);
102
+ return 1;
103
+ }
104
+ }
105
+ else {
106
+ let functionGroups;
107
+ try {
108
+ functionGroups = commons_1.collectFunctionsByRegion(this.functions.length !== 0 ? this.functions : this.config.functions, this.region || this.config.region);
109
+ }
110
+ catch (err) {
111
+ this.context.stdout.write(`${chalk_1.red('[Error]')} Couldn't group functions. ${err}`);
54
112
  return 1;
55
113
  }
114
+ for (const [region, functionARNs] of Object.entries(functionGroups)) {
115
+ const lambda = new aws_sdk_1.Lambda({ region });
116
+ const cloudWatchLogs = new aws_sdk_1.CloudWatchLogs({ region });
117
+ try {
118
+ const configs = yield uninstrument_1.getUninstrumentedFunctionConfigs(lambda, cloudWatchLogs, functionARNs, this.forwarder);
119
+ configGroups.push({ configs, lambda, cloudWatchLogs });
120
+ }
121
+ catch (err) {
122
+ this.context.stdout.write(`${chalk_1.red('[Error]')} Couldn't fetch Lambda functions. ${err}\n`);
123
+ return 1;
124
+ }
125
+ }
56
126
  }
57
127
  const configList = configGroups.map((group) => group.configs).reduce((a, b) => a.concat(b));
58
128
  this.printPlannedActions(configList);
59
129
  if (this.dryRun || configList.length === 0) {
60
130
  return 0;
61
131
  }
132
+ const willUpdate = commons_1.willUpdateFunctionConfigs(configList);
133
+ if (this.interactive && willUpdate) {
134
+ this.context.stdout.write(`${chalk_1.yellow('[!]')} Confirmation needed.\n`);
135
+ const isConfirmed = yield prompt_1.requestChangesConfirmation('Do you want to apply the changes?');
136
+ if (!isConfirmed) {
137
+ return 0;
138
+ }
139
+ this.context.stdout.write(`${chalk_1.yellow('[!]')} Uninstrumenting functions.\n`);
140
+ }
62
141
  // Un-instrument functions.
63
142
  const promises = Object.values(configGroups).map((group) => {
64
143
  commons_1.updateLambdaFunctionConfigs(group.lambda, group.cloudWatchLogs, group.configs);
@@ -74,22 +153,17 @@ class UninstrumentCommand extends clipanion_1.Command {
74
153
  });
75
154
  }
76
155
  printPlannedActions(configs) {
77
- var _a;
78
156
  const prefix = this.dryRun ? chalk_1.bold(chalk_1.cyan('[Dry Run] ')) : '';
79
- let anyUpdates = false;
80
- for (const config of configs) {
81
- if (config.updateRequest !== undefined ||
82
- ((_a = config.logGroupConfiguration) === null || _a === void 0 ? void 0 : _a.deleteSubscriptionFilterRequest) !== undefined ||
83
- (config === null || config === void 0 ? void 0 : config.tagConfiguration) !== undefined) {
84
- anyUpdates = true;
85
- break;
86
- }
87
- }
88
- if (!anyUpdates) {
157
+ const willUpdate = commons_1.willUpdateFunctionConfigs(configs);
158
+ if (!willUpdate) {
89
159
  this.context.stdout.write(`${prefix}No updates will be applied\n`);
90
160
  return;
91
161
  }
92
- this.context.stdout.write(`${prefix}Will apply the following updates:\n`);
162
+ this.context.stdout.write(`\n${chalk_1.bold(chalk_1.yellow('[!]'))} Functions to be updated:\n`);
163
+ for (const config of configs) {
164
+ this.context.stdout.write(`\t- ${chalk_1.bold(config.functionARN)}\n`);
165
+ }
166
+ this.context.stdout.write(`\n${prefix}Will apply the following updates:\n`);
93
167
  for (const config of configs) {
94
168
  if (config.updateRequest) {
95
169
  this.context.stdout.write(`UpdateFunctionConfiguration -> ${config.functionARN}\n${JSON.stringify(config.updateRequest, undefined, 2)}\n`);
@@ -111,17 +185,20 @@ UninstrumentCommand.addOption('region', clipanion_1.Command.String('-r,--region'
111
185
  UninstrumentCommand.addOption('configPath', clipanion_1.Command.String('--config'));
112
186
  UninstrumentCommand.addOption('dryRun', clipanion_1.Command.Boolean('-d,--dry'));
113
187
  UninstrumentCommand.addOption('forwarder', clipanion_1.Command.String('--forwarder'));
188
+ UninstrumentCommand.addOption('regExPattern', clipanion_1.Command.String('--functions-regex,--functionsRegex'));
189
+ UninstrumentCommand.addOption('interactive', clipanion_1.Command.Boolean('-i,--interactive'));
114
190
  /**
115
191
  * Commands that are not really in use, but to
116
192
  * make uninstrumentation easier for the user.
117
193
  */
118
- UninstrumentCommand.addOption('extensionVersion', clipanion_1.Command.String('-e,--extensionVersion', { hidden: true }));
119
- UninstrumentCommand.addOption('layerVersion', clipanion_1.Command.String('-v,--layerVersion', { hidden: true }));
194
+ UninstrumentCommand.addOption('extensionVersion', clipanion_1.Command.String('-e,--extension-version,--extensionVersion', { hidden: true }));
195
+ UninstrumentCommand.addOption('layerVersion', clipanion_1.Command.String('-v,--layer-version,--layerVersion', { hidden: true }));
120
196
  UninstrumentCommand.addOption('tracing', clipanion_1.Command.String('--tracing', { hidden: true }));
121
- UninstrumentCommand.addOption('mergeXrayTraces', clipanion_1.Command.String('--mergeXrayTraces', { hidden: true }));
122
- UninstrumentCommand.addOption('flushMetricsToLogs', clipanion_1.Command.String('--flushMetricsToLogs', { hidden: true }));
123
- UninstrumentCommand.addOption('logLevel', clipanion_1.Command.String('--logLevel', { hidden: true }));
197
+ UninstrumentCommand.addOption('mergeXrayTraces', clipanion_1.Command.String('--merge-xray-traces,--mergeXrayTraces', { hidden: true }));
198
+ UninstrumentCommand.addOption('flushMetricsToLogs', clipanion_1.Command.String('--flush-metrics-to-logs,--flushMetricsToLogs', { hidden: true }));
199
+ UninstrumentCommand.addOption('logLevel', clipanion_1.Command.String('--log-level,--logLevel', { hidden: true }));
124
200
  UninstrumentCommand.addOption('service', clipanion_1.Command.String('--service', { hidden: true }));
125
201
  UninstrumentCommand.addOption('environment', clipanion_1.Command.String('--env', { hidden: true }));
126
202
  UninstrumentCommand.addOption('version', clipanion_1.Command.String('--version', { hidden: true }));
127
- UninstrumentCommand.addOption('extraTags', clipanion_1.Command.String('--extra-tags', { hidden: true }));
203
+ UninstrumentCommand.addOption('extraTags', clipanion_1.Command.String('--extra-tags,--extraTags', { hidden: true }));
204
+ UninstrumentCommand.addOption('captureLambdaPayload', clipanion_1.Command.String('--capture-lambda-payload,--captureLambdaPayload', { hidden: true }));
@@ -0,0 +1 @@
1
+ export {};
File without changes
@@ -1,6 +1,6 @@
1
1
  import { Command } from 'clipanion';
2
2
  export declare class UploadCommand extends Command {
3
- static usage: import("clipanion/lib/advanced").Usage;
3
+ static usage: import("clipanion").Usage;
4
4
  private basePath?;
5
5
  private cliVersion;
6
6
  private config;
@@ -28,12 +28,34 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
28
28
  });
29
29
  };
30
30
  Object.defineProperty(exports, "__esModule", { value: true });
31
+ const advanced_1 = require("clipanion/lib/advanced");
31
32
  const ciUtils = __importStar(require("../../../helpers/utils"));
32
- const cli_1 = require("../cli");
33
+ const command_1 = require("../command");
33
34
  const interfaces_1 = require("../interfaces");
34
35
  const runTests = __importStar(require("../run-test"));
35
36
  const utils = __importStar(require("../utils"));
36
37
  const fixtures_1 = require("./fixtures");
38
+ test('all option flags are supported', () => __awaiter(void 0, void 0, void 0, function* () {
39
+ const options = [
40
+ 'apiKey',
41
+ 'appKey',
42
+ 'failOnCriticalErrors',
43
+ 'config',
44
+ 'datadogSite',
45
+ 'files',
46
+ 'failOnTimeout',
47
+ 'public-id',
48
+ 'search',
49
+ 'subdomain',
50
+ 'tunnel',
51
+ 'jUnitReport',
52
+ 'runName',
53
+ ];
54
+ const cli = new advanced_1.Cli();
55
+ cli.register(command_1.RunTestCommand);
56
+ const usage = cli.usage(command_1.RunTestCommand);
57
+ options.forEach((option) => expect(usage).toContain(`--${option}`));
58
+ }));
37
59
  describe('run-test', () => {
38
60
  beforeEach(() => {
39
61
  jest.restoreAllMocks();
@@ -46,12 +68,12 @@ describe('run-test', () => {
46
68
  });
47
69
  test('should default to datadog us', () => __awaiter(void 0, void 0, void 0, function* () {
48
70
  process.env = {};
49
- const command = new cli_1.RunTestCommand();
71
+ const command = new command_1.RunTestCommand();
50
72
  expect(command['getAppBaseURL']()).toBe('https://app.datadoghq.com/');
51
73
  }));
52
74
  test('subdomain should be overridable', () => __awaiter(void 0, void 0, void 0, function* () {
53
75
  process.env = { DATADOG_SUBDOMAIN: 'custom' };
54
- const command = new cli_1.RunTestCommand();
76
+ const command = new command_1.RunTestCommand();
55
77
  yield command['resolveConfig']();
56
78
  expect(command['getAppBaseURL']()).toBe('https://custom.datadoghq.com/');
57
79
  }));
@@ -60,7 +82,7 @@ describe('run-test', () => {
60
82
  DATADOG_SITE: 'datadoghq.eu',
61
83
  DATADOG_SUBDOMAIN: 'custom',
62
84
  };
63
- const command = new cli_1.RunTestCommand();
85
+ const command = new command_1.RunTestCommand();
64
86
  yield command['resolveConfig']();
65
87
  expect(command['getAppBaseURL']()).toBe('https://custom.datadoghq.eu/');
66
88
  }));
@@ -83,7 +105,7 @@ describe('run-test', () => {
83
105
  test5: [{ result: { passed: false } }],
84
106
  };
85
107
  test('should sort tests with success, non_blocking failures then failures', () => __awaiter(void 0, void 0, void 0, function* () {
86
- const command = new cli_1.RunTestCommand();
108
+ const command = new command_1.RunTestCommand();
87
109
  tests.sort(command['sortTestsByOutcome'](results));
88
110
  expect(tests).toStrictEqual([test3, test1, test2, test5, test4]);
89
111
  }));
@@ -102,9 +124,9 @@ describe('run-test', () => {
102
124
  DATADOG_SUBDOMAIN: 'custom',
103
125
  };
104
126
  process.env = overrideEnv;
105
- const command = new cli_1.RunTestCommand();
127
+ const command = new command_1.RunTestCommand();
106
128
  yield command['resolveConfig']();
107
- expect(command['config']).toEqual(Object.assign(Object.assign({}, cli_1.DEFAULT_COMMAND_CONFIG), { apiKey: overrideEnv.DATADOG_API_KEY, appKey: overrideEnv.DATADOG_APP_KEY, datadogSite: overrideEnv.DATADOG_SITE, subdomain: overrideEnv.DATADOG_SUBDOMAIN }));
129
+ expect(command['config']).toEqual(Object.assign(Object.assign({}, command_1.DEFAULT_COMMAND_CONFIG), { apiKey: overrideEnv.DATADOG_API_KEY, appKey: overrideEnv.DATADOG_APP_KEY, datadogSite: overrideEnv.DATADOG_SITE, subdomain: overrideEnv.DATADOG_SUBDOMAIN }));
108
130
  }));
109
131
  test('override from config file', () => __awaiter(void 0, void 0, void 0, function* () {
110
132
  const overrideConfigFile = {
@@ -122,9 +144,10 @@ describe('run-test', () => {
122
144
  publicIds: ['ran-dom-id'],
123
145
  subdomain: 'ppa',
124
146
  tunnel: true,
147
+ variableStrings: [],
125
148
  };
126
149
  jest.spyOn(ciUtils, 'getConfig').mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return overrideConfigFile; }));
127
- const command = new cli_1.RunTestCommand();
150
+ const command = new command_1.RunTestCommand();
128
151
  yield command['resolveConfig']();
129
152
  expect(command['config']).toEqual(overrideConfigFile);
130
153
  }));
@@ -142,7 +165,7 @@ describe('run-test', () => {
142
165
  testSearchQuery: 'a-search-query',
143
166
  tunnel: true,
144
167
  };
145
- const command = new cli_1.RunTestCommand();
168
+ const command = new command_1.RunTestCommand();
146
169
  command['apiKey'] = overrideCLI.apiKey;
147
170
  command['appKey'] = overrideCLI.appKey;
148
171
  command['configPath'] = overrideCLI.configPath;
@@ -155,7 +178,7 @@ describe('run-test', () => {
155
178
  command['tunnel'] = overrideCLI.tunnel;
156
179
  command['testSearchQuery'] = overrideCLI.testSearchQuery;
157
180
  yield command['resolveConfig']();
158
- expect(command['config']).toEqual(Object.assign(Object.assign({}, cli_1.DEFAULT_COMMAND_CONFIG), { apiKey: 'fake_api_key', appKey: 'fake_app_key', configPath: 'fake-datadog-ci.json', datadogSite: 'datadoghq.eu', failOnCriticalErrors: true, failOnTimeout: false, files: ['new-file'], publicIds: ['ran-dom-id'], subdomain: 'new-sub-domain', testSearchQuery: 'a-search-query', tunnel: true }));
181
+ expect(command['config']).toEqual(Object.assign(Object.assign({}, command_1.DEFAULT_COMMAND_CONFIG), { apiKey: 'fake_api_key', appKey: 'fake_app_key', configPath: 'fake-datadog-ci.json', datadogSite: 'datadoghq.eu', failOnCriticalErrors: true, failOnTimeout: false, files: ['new-file'], publicIds: ['ran-dom-id'], subdomain: 'new-sub-domain', testSearchQuery: 'a-search-query', tunnel: true }));
159
182
  }));
160
183
  test('override from config file < ENV < CLI', () => __awaiter(void 0, void 0, void 0, function* () {
161
184
  jest.spyOn(ciUtils, 'getConfig').mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () {
@@ -169,10 +192,10 @@ describe('run-test', () => {
169
192
  DATADOG_API_KEY: 'api_key_env',
170
193
  DATADOG_APP_KEY: 'app_key_env',
171
194
  };
172
- const command = new cli_1.RunTestCommand();
195
+ const command = new command_1.RunTestCommand();
173
196
  command['apiKey'] = 'api_key_cli';
174
197
  yield command['resolveConfig']();
175
- expect(command['config']).toEqual(Object.assign(Object.assign({}, cli_1.DEFAULT_COMMAND_CONFIG), { apiKey: 'api_key_cli', appKey: 'app_key_env', datadogSite: 'datadog.config.file' }));
198
+ expect(command['config']).toEqual(Object.assign(Object.assign({}, command_1.DEFAULT_COMMAND_CONFIG), { apiKey: 'api_key_cli', appKey: 'app_key_env', datadogSite: 'datadog.config.file' }));
176
199
  }));
177
200
  test('override locations with ENV variable', () => __awaiter(void 0, void 0, void 0, function* () {
178
201
  const conf = {
@@ -193,7 +216,7 @@ describe('run-test', () => {
193
216
  triggerTests,
194
217
  };
195
218
  const write = jest.fn();
196
- const command = new cli_1.RunTestCommand();
219
+ const command = new command_1.RunTestCommand();
197
220
  command.context = { stdout: { write } };
198
221
  command['config'].global = { locations: ['aws:us-east-2'] };
199
222
  jest.spyOn(runTests, 'getApiHelper').mockImplementation(() => apiHelper);
@@ -54,6 +54,7 @@ exports.ciConfig = {
54
54
  publicIds: [],
55
55
  subdomain: 'app',
56
56
  tunnel: false,
57
+ variableStrings: [],
57
58
  };
58
59
  const getApiTest = (publicId) => ({
59
60
  config: {
@@ -32,6 +32,7 @@ const ciUtils = __importStar(require("../../../helpers/utils"));
32
32
  const errors_1 = require("../errors");
33
33
  const interfaces_1 = require("../interfaces");
34
34
  const runTests = __importStar(require("../run-test"));
35
+ const tunnel_1 = require("../tunnel");
35
36
  const utils = __importStar(require("../utils"));
36
37
  const fixtures_1 = require("./fixtures");
37
38
  describe('run-test', () => {
@@ -95,6 +96,39 @@ describe('run-test', () => {
95
96
  ]), expect.anything());
96
97
  expect(apiHelper.getPresignedURL).not.toHaveBeenCalled();
97
98
  }));
99
+ test('open and close tunnel for successful runs', () => __awaiter(void 0, void 0, void 0, function* () {
100
+ const location = {
101
+ display_name: 'us1',
102
+ id: 1,
103
+ is_active: true,
104
+ name: 'us1',
105
+ region: 'us1',
106
+ };
107
+ jest.spyOn(utils, 'wait').mockImplementation(() => new Promise((res) => setTimeout(res, 10)));
108
+ const startTunnelSpy = jest
109
+ .spyOn(tunnel_1.Tunnel.prototype, 'start')
110
+ .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return ({ host: 'host', id: 'id', privateKey: 'key' }); }));
111
+ const stopTunnelSpy = jest.spyOn(tunnel_1.Tunnel.prototype, 'stop');
112
+ jest.spyOn(utils, 'getTestsToTrigger').mockReturnValue(Promise.resolve({
113
+ overriddenTestsToTrigger: [],
114
+ summary: utils.createSummary(),
115
+ tests: [{ options: { ci: { executionRule: interfaces_1.ExecutionRule.BLOCKING } }, public_id: '123-456-789' }],
116
+ }));
117
+ jest.spyOn(utils, 'runTests').mockReturnValue(Promise.resolve({
118
+ locations: [location],
119
+ results: [{ device: 'chrome_laptop.large', location: 1, public_id: '123-456-789', result_id: '1' }],
120
+ triggered_check_ids: [],
121
+ }));
122
+ const apiHelper = {
123
+ getPresignedURL: () => ({ url: 'url' }),
124
+ pollResults: () => fixtures_1.mockPollResultResponse,
125
+ triggerTests: () => fixtures_1.mockTestTriggerResponse,
126
+ };
127
+ jest.spyOn(runTests, 'getApiHelper').mockImplementation(() => apiHelper);
128
+ yield runTests.executeTests(fixtures_1.mockReporter, Object.assign(Object.assign({}, fixtures_1.ciConfig), { failOnCriticalErrors: true, publicIds: ['123-456-789'], tunnel: true }));
129
+ expect(startTunnelSpy).toHaveBeenCalledTimes(1);
130
+ expect(stopTunnelSpy).toHaveBeenCalledTimes(1);
131
+ }));
98
132
  test('getTestsList throws', () => __awaiter(void 0, void 0, void 0, function* () {
99
133
  const serverError = new Error('Server Error');
100
134
  serverError.response = { data: { errors: ['Bad Gateway'] }, status: 502 };
@@ -137,6 +171,10 @@ describe('run-test', () => {
137
171
  yield expect(runTests.executeTests(fixtures_1.mockReporter, Object.assign(Object.assign({}, fixtures_1.ciConfig), { publicIds: ['public-id-1', 'public-id-2'], tunnel: true }))).rejects.toMatchError(new errors_1.CriticalError('UNAVAILABLE_TUNNEL_CONFIG'));
138
172
  }));
139
173
  test('runTests throws', () => __awaiter(void 0, void 0, void 0, function* () {
174
+ jest
175
+ .spyOn(tunnel_1.Tunnel.prototype, 'start')
176
+ .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return ({ host: 'host', id: 'id', privateKey: 'key' }); }));
177
+ const stopTunnelSpy = jest.spyOn(tunnel_1.Tunnel.prototype, 'stop');
140
178
  jest.spyOn(utils, 'getTestsToTrigger').mockReturnValue(Promise.resolve({
141
179
  overriddenTestsToTrigger: [],
142
180
  summary: utils.createSummary(),
@@ -146,12 +184,14 @@ describe('run-test', () => {
146
184
  serverError.response = { data: { errors: ['Bad Gateway'] }, status: 502 };
147
185
  serverError.config = { baseURL: 'baseURL', url: 'url' };
148
186
  const apiHelper = {
187
+ getPresignedURL: () => ({ url: 'url' }),
149
188
  triggerTests: jest.fn(() => {
150
189
  throw serverError;
151
190
  }),
152
191
  };
153
192
  jest.spyOn(runTests, 'getApiHelper').mockImplementation(() => apiHelper);
154
- yield expect(runTests.executeTests(fixtures_1.mockReporter, Object.assign(Object.assign({}, fixtures_1.ciConfig), { publicIds: ['public-id-1', 'public-id-2'] }))).rejects.toMatchError(new errors_1.CriticalError('TRIGGER_TESTS_FAILED'));
193
+ yield expect(runTests.executeTests(fixtures_1.mockReporter, Object.assign(Object.assign({}, fixtures_1.ciConfig), { publicIds: ['public-id-1', 'public-id-2'], tunnel: true }))).rejects.toMatchError(new errors_1.CriticalError('TRIGGER_TESTS_FAILED'));
194
+ expect(stopTunnelSpy).toHaveBeenCalledTimes(1);
155
195
  }));
156
196
  test('waitForResults throws', () => __awaiter(void 0, void 0, void 0, function* () {
157
197
  const location = {
@@ -161,6 +201,10 @@ describe('run-test', () => {
161
201
  name: 'us1',
162
202
  region: 'us1',
163
203
  };
204
+ jest
205
+ .spyOn(tunnel_1.Tunnel.prototype, 'start')
206
+ .mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return ({ host: 'host', id: 'id', privateKey: 'key' }); }));
207
+ const stopTunnelSpy = jest.spyOn(tunnel_1.Tunnel.prototype, 'stop');
164
208
  jest.spyOn(utils, 'getTestsToTrigger').mockReturnValue(Promise.resolve({
165
209
  overriddenTestsToTrigger: [],
166
210
  summary: utils.createSummary(),
@@ -175,12 +219,14 @@ describe('run-test', () => {
175
219
  serverError.response = { data: { errors: ['Bad Gateway'] }, status: 502 };
176
220
  serverError.config = { baseURL: 'baseURL', url: 'url' };
177
221
  const apiHelper = {
222
+ getPresignedURL: () => ({ url: 'url' }),
178
223
  pollResults: jest.fn(() => {
179
224
  throw serverError;
180
225
  }),
181
226
  };
182
227
  jest.spyOn(runTests, 'getApiHelper').mockImplementation(() => apiHelper);
183
- yield expect(runTests.executeTests(fixtures_1.mockReporter, Object.assign(Object.assign({}, fixtures_1.ciConfig), { failOnCriticalErrors: true, publicIds: ['public-id-1', 'public-id-2'] }))).rejects.toMatchError(new errors_1.CriticalError('POLL_RESULTS_FAILED'));
228
+ yield expect(runTests.executeTests(fixtures_1.mockReporter, Object.assign(Object.assign({}, fixtures_1.ciConfig), { failOnCriticalErrors: true, publicIds: ['public-id-1', 'public-id-2'], tunnel: true }))).rejects.toMatchError(new errors_1.CriticalError('POLL_RESULTS_FAILED'));
229
+ expect(stopTunnelSpy).toHaveBeenCalledTimes(1);
184
230
  }));
185
231
  });
186
232
  describe('getDatadogHost', () => {
@@ -367,10 +367,6 @@ describe('utils', () => {
367
367
  expect(utils.hasResultPassed(result, false, true)).toBeTruthy();
368
368
  expect(utils.hasResultPassed(result, true, true)).toBeFalsy();
369
369
  });
370
- test('removeUndefinedValues', () => {
371
- // tslint:disable-next-line: no-null-keyword
372
- expect(utils.removeUndefinedValues({ a: 'b', c: 'd', e: undefined, g: null })).toEqual({ a: 'b', c: 'd', g: null });
373
- });
374
370
  test('hasTestSucceeded', () => {
375
371
  const testConfiguration = fixtures_1.getApiTest('abc-def-ghi');
376
372
  const passingResult = fixtures_1.getBrowserResult();
@@ -629,4 +625,15 @@ describe('utils', () => {
629
625
  expect(counter).toBe(3);
630
626
  }));
631
627
  });
628
+ test('parseVariablesFromCli', () => {
629
+ const mockLogFunction = (message) => undefined;
630
+ expect(utils.parseVariablesFromCli(['TEST=42'], mockLogFunction)).toEqual({ TEST: '42' });
631
+ expect(utils.parseVariablesFromCli(['TEST=42 with some spaces'], mockLogFunction)).toEqual({
632
+ TEST: '42 with some spaces',
633
+ });
634
+ expect(utils.parseVariablesFromCli(['TEST=42=43=44'], mockLogFunction)).toEqual({ TEST: '42=43=44' });
635
+ expect(utils.parseVariablesFromCli(['TEST='], mockLogFunction)).toEqual({ TEST: '' });
636
+ expect(utils.parseVariablesFromCli([''], mockLogFunction)).toBeUndefined();
637
+ expect(utils.parseVariablesFromCli(undefined, mockLogFunction)).toBeUndefined();
638
+ });
632
639
  });
@@ -30,7 +30,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
30
30
  };
31
31
  Object.defineProperty(exports, "__esModule", { value: true });
32
32
  const ciUtils = __importStar(require("../../../helpers/utils"));
33
- const cli_1 = require("../cli");
33
+ const command_1 = require("../command");
34
34
  const interfaces_1 = require("../interfaces");
35
35
  const runTests = __importStar(require("../run-test"));
36
36
  const fixtures_1 = require("./fixtures");
@@ -62,7 +62,7 @@ describe('Proxy configuration', () => {
62
62
  tunnel: true,
63
63
  });
64
64
  }));
65
- const command = new cli_1.RunTestCommand();
65
+ const command = new command_1.RunTestCommand();
66
66
  command.context = { stdout: { write: jest.fn() } };
67
67
  jest.spyOn(runTests, 'getDatadogHost').mockImplementation(() => 'http://datadoghq.com/');
68
68
  yield command.execute();
@@ -95,7 +95,7 @@ describe('Proxy configuration', () => {
95
95
  tunnel: true,
96
96
  });
97
97
  }));
98
- const command = new cli_1.RunTestCommand();
98
+ const command = new command_1.RunTestCommand();
99
99
  command.context = { stdout: { write: jest.fn() } };
100
100
  jest.spyOn(runTests, 'getDatadogHost').mockImplementation(() => 'http://datadoghq.com/');
101
101
  yield command.execute();
@@ -1,26 +1 @@
1
- import { Command } from 'clipanion';
2
- import { CommandConfig } from './interfaces';
3
- export declare const DEFAULT_COMMAND_CONFIG: CommandConfig;
4
- export declare class RunTestCommand extends Command {
5
- jUnitReport?: string;
6
- runName?: string;
7
- private apiKey?;
8
- private appKey?;
9
- private config;
10
- private configPath?;
11
- private datadogSite?;
12
- private failOnCriticalErrors?;
13
- private failOnTimeout?;
14
- private files?;
15
- private publicIds?;
16
- private reporter?;
17
- private subdomain?;
18
- private testSearchQuery?;
19
- private tunnel?;
20
- execute(): Promise<1 | 0>;
21
- private getAppBaseURL;
22
- private renderResults;
23
- private reportCiError;
24
- private resolveConfig;
25
- private sortTestsByOutcome;
26
- }
1
+ export {};