@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
@@ -19,74 +19,116 @@ const upload_1 = require("../git-metadata/upload");
19
19
  const constants_1 = require("./constants");
20
20
  const commons_1 = require("./functions/commons");
21
21
  const instrument_1 = require("./functions/instrument");
22
+ const prompt_1 = require("./prompt");
22
23
  class InstrumentCommand extends clipanion_1.Command {
23
24
  constructor() {
24
25
  super(...arguments);
25
26
  this.config = {
26
27
  functions: [],
27
- region: process.env.AWS_DEFAULT_REGION,
28
+ region: process.env[constants_1.AWS_DEFAULT_REGION_ENV_VAR],
28
29
  tracing: 'true',
29
30
  };
30
31
  this.dryRun = false;
31
32
  this.functions = [];
33
+ this.interactive = false;
32
34
  this.sourceCodeIntegration = false;
33
35
  }
34
36
  execute() {
37
+ var _a, _b, _c;
35
38
  return __awaiter(this, void 0, void 0, function* () {
36
39
  const lambdaConfig = { lambda: this.config };
37
40
  this.config = (yield utils_1.parseConfigFile(lambdaConfig, this.configPath)).lambda;
41
+ let hasSpecifiedFunctions = this.functions.length !== 0 || this.config.functions.length !== 0;
42
+ if (this.interactive) {
43
+ try {
44
+ if (commons_1.isMissingAWSCredentials()) {
45
+ this.context.stdout.write(`${chalk_1.bold(chalk_1.yellow('[!]'))} No existing AWS credentials found, let's set them up!\n`);
46
+ yield prompt_1.requestAWSCredentials();
47
+ }
48
+ if (commons_1.isMissingDatadogEnvVars()) {
49
+ this.context.stdout.write(`${chalk_1.bold(chalk_1.yellow('[!]'))} Configure Datadog settings.\n`);
50
+ yield prompt_1.requestDatadogEnvVars();
51
+ }
52
+ }
53
+ catch (e) {
54
+ this.context.stdout.write(`${chalk_1.red('[Error]')} ${e}\n`);
55
+ return 1;
56
+ }
57
+ 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];
58
+ this.region = region;
59
+ // If user doesn't specify functions, allow them
60
+ // to select from all of the functions from the
61
+ // requested region.
62
+ if (!hasSpecifiedFunctions) {
63
+ try {
64
+ const lambda = new aws_sdk_1.Lambda({ region });
65
+ this.context.stdout.write('Fetching Lambda functions, this might take a while.\n');
66
+ const functionNames = (_c = (yield commons_1.getAllLambdaFunctionConfigs(lambda)).map((config) => config.FunctionName).sort()) !== null && _c !== void 0 ? _c : [];
67
+ if (functionNames.length === 0) {
68
+ this.context.stdout.write(`${chalk_1.red('[Error]')} Couldn't find any Lambda functions in the specified region.\n`);
69
+ return 1;
70
+ }
71
+ const functions = yield prompt_1.requestFunctionSelection(functionNames);
72
+ this.functions = functions;
73
+ }
74
+ catch (err) {
75
+ this.context.stdout.write(`${chalk_1.red('[Error]')} Couldn't fetch Lambda functions. ${err}\n`);
76
+ return 1;
77
+ }
78
+ }
79
+ }
38
80
  const settings = this.getSettings();
39
81
  if (settings === undefined) {
40
82
  return 1;
41
83
  }
42
- const hasSpecifiedFuntions = this.functions.length !== 0 || this.config.functions.length !== 0;
43
- const hasSpecifiedRegExPattern = this.regExPattern !== undefined;
44
- if (!hasSpecifiedFuntions && !hasSpecifiedRegExPattern) {
45
- this.context.stdout.write('No functions specified for instrumentation.\n');
84
+ hasSpecifiedFunctions = this.functions.length !== 0 || this.config.functions.length !== 0;
85
+ const hasSpecifiedRegExPattern = this.regExPattern !== undefined && this.regExPattern !== '';
86
+ if (!hasSpecifiedFunctions && !hasSpecifiedRegExPattern) {
87
+ this.context.stdout.write(`${chalk_1.red('[Error]')} No functions specified for instrumentation.\n`);
46
88
  return 1;
47
89
  }
48
90
  if (settings.extensionVersion && settings.forwarderARN) {
49
- this.context.stdout.write('"extensionVersion" and "forwarder" should not be used at the same time.\n');
91
+ this.context.stdout.write(`${chalk_1.red('[Error]')} "extensionVersion" and "forwarder" should not be used at the same time.\n`);
50
92
  return 1;
51
93
  }
52
94
  if (this.sourceCodeIntegration) {
53
95
  if (!process.env.DATADOG_API_KEY) {
54
- this.context.stdout.write('Missing DATADOG_API_KEY in your environment\n');
96
+ this.context.stdout.write(`${chalk_1.red('[Error]')} Missing DATADOG_API_KEY in your environment\n`);
55
97
  return 1;
56
98
  }
57
99
  try {
58
100
  yield this.getGitDataAndUpload(settings);
59
101
  }
60
102
  catch (err) {
61
- this.context.stdout.write(`${err}\n`);
103
+ this.context.stdout.write(`${chalk_1.red('[Error]')} ${err}\n`);
62
104
  return 1;
63
105
  }
64
106
  }
65
107
  const configGroups = [];
66
108
  if (hasSpecifiedRegExPattern) {
67
- if (hasSpecifiedFuntions) {
109
+ if (hasSpecifiedFunctions) {
68
110
  const usedCommand = this.functions.length !== 0 ? '"--functions"' : 'Functions in config file';
69
- this.context.stdout.write(`${usedCommand} and "--functions-regex" should not be used at the same time.\n`);
111
+ this.context.stdout.write(`${chalk_1.red('[Error]')} ${usedCommand} and "--functions-regex" should not be used at the same time.\n`);
70
112
  return 1;
71
113
  }
72
114
  if (this.regExPattern.match(':')) {
73
- this.context.stdout.write(`"--functions-regex" isn't meant to be used with ARNs.\n`);
115
+ this.context.stdout.write(`${chalk_1.red('[Error]')} "--functions-regex" isn't meant to be used with ARNs.\n`);
74
116
  return 1;
75
117
  }
76
118
  const region = this.region || this.config.region;
77
119
  if (!region) {
78
- this.context.stdout.write('No default region specified. Use -r,--region,');
120
+ this.context.stdout.write(`${chalk_1.red('[Error]')} No default region specified. Use \`-r\`, \`--region\`.\n`);
79
121
  return 1;
80
122
  }
81
123
  try {
82
124
  const cloudWatchLogs = new aws_sdk_1.CloudWatchLogs({ region });
83
125
  const lambda = new aws_sdk_1.Lambda({ region });
84
- this.context.stdout.write('Fetching lambda functions, this might take a while.\n');
85
- const configs = yield instrument_1.getLambdaConfigsFromRegEx(lambda, cloudWatchLogs, region, this.regExPattern, settings);
126
+ this.context.stdout.write('Fetching Lambda functions, this might take a while.\n');
127
+ const configs = yield instrument_1.getInstrumentedFunctionConfigsFromRegEx(lambda, cloudWatchLogs, region, this.regExPattern, settings);
86
128
  configGroups.push({ configs, lambda, cloudWatchLogs, region: region });
87
129
  }
88
130
  catch (err) {
89
- this.context.stdout.write(`Couldn't fetch lambda functions. ${err}\n`);
131
+ this.context.stdout.write(`${chalk_1.red('[Error]')} Couldn't fetch Lambda functions. ${err}\n`);
90
132
  return 1;
91
133
  }
92
134
  }
@@ -96,18 +138,18 @@ class InstrumentCommand extends clipanion_1.Command {
96
138
  functionGroups = commons_1.collectFunctionsByRegion(this.functions.length !== 0 ? this.functions : this.config.functions, this.region || this.config.region);
97
139
  }
98
140
  catch (err) {
99
- this.context.stdout.write(`Couldn't group functions. ${err}`);
141
+ this.context.stdout.write(`${chalk_1.red('[Error]')} Couldn't group functions. ${err}`);
100
142
  return 1;
101
143
  }
102
144
  for (const [region, functionList] of Object.entries(functionGroups)) {
103
145
  const lambda = new aws_sdk_1.Lambda({ region });
104
146
  const cloudWatchLogs = new aws_sdk_1.CloudWatchLogs({ region });
105
147
  try {
106
- const configs = yield instrument_1.getFunctionConfigs(lambda, cloudWatchLogs, region, functionList, settings);
148
+ const configs = yield instrument_1.getInstrumentedFunctionConfigs(lambda, cloudWatchLogs, region, functionList, settings);
107
149
  configGroups.push({ configs, lambda, cloudWatchLogs, region });
108
150
  }
109
151
  catch (err) {
110
- this.context.stdout.write(`Couldn't fetch lambda functions. ${err}\n`);
152
+ this.context.stdout.write(`${chalk_1.red('[Error]')} Couldn't fetch Lambda functions. ${err}\n`);
111
153
  return 1;
112
154
  }
113
155
  }
@@ -117,20 +159,26 @@ class InstrumentCommand extends clipanion_1.Command {
117
159
  if (this.dryRun || configList.length === 0) {
118
160
  return 0;
119
161
  }
162
+ const willUpdate = commons_1.willUpdateFunctionConfigs(configList);
163
+ if (this.interactive && willUpdate) {
164
+ this.context.stdout.write(`${chalk_1.yellow('[!]')} Confirmation needed.\n`);
165
+ const isConfirmed = yield prompt_1.requestChangesConfirmation('Do you want to apply the changes?');
166
+ if (!isConfirmed) {
167
+ return 0;
168
+ }
169
+ this.context.stdout.write(`${chalk_1.yellow('[!]')} Instrumenting functions.\n`);
170
+ }
120
171
  const promises = Object.values(configGroups).map((group) => commons_1.updateLambdaFunctionConfigs(group.lambda, group.cloudWatchLogs, group.configs));
121
172
  try {
122
173
  yield Promise.all(promises);
123
174
  }
124
175
  catch (err) {
125
- this.context.stdout.write(`Failure during update. ${err}\n`);
176
+ this.context.stdout.write(`${chalk_1.red('[Error]')} Failure during update. ${err}\n`);
126
177
  return 1;
127
178
  }
128
179
  return 0;
129
180
  });
130
181
  }
131
- convertStringBooleanToBoolean(fallback, value, configValue) {
132
- return value ? value.toLowerCase() === 'true' : configValue ? configValue.toLowerCase() === 'true' : fallback;
133
- }
134
182
  getCurrentGitStatus() {
135
183
  return __awaiter(this, void 0, void 0, function* () {
136
184
  const simpleGit = yield git_1.newSimpleGit();
@@ -173,7 +221,7 @@ class InstrumentCommand extends clipanion_1.Command {
173
221
  });
174
222
  }
175
223
  getSettings() {
176
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
224
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
177
225
  const layerVersionStr = (_a = this.layerVersion) !== null && _a !== void 0 ? _a : this.config.layerVersion;
178
226
  const extensionVersionStr = (_b = this.extensionVersion) !== null && _b !== void 0 ? _b : this.config.extensionVersion;
179
227
  const layerAWSAccount = (_c = this.layerAWSAccount) !== null && _c !== void 0 ? _c : this.config.layerAWSAccount;
@@ -195,23 +243,26 @@ class InstrumentCommand extends clipanion_1.Command {
195
243
  return;
196
244
  }
197
245
  const stringBooleansMap = {
198
- flushMetricsToLogs: (_f = (_e = this.flushMetricsToLogs) === null || _e === void 0 ? void 0 : _e.toLowerCase()) !== null && _f !== void 0 ? _f : (_g = this.config.flushMetricsToLogs) === null || _g === void 0 ? void 0 : _g.toLowerCase(),
199
- mergeXrayTraces: (_j = (_h = this.mergeXrayTraces) === null || _h === void 0 ? void 0 : _h.toLowerCase()) !== null && _j !== void 0 ? _j : (_k = this.config.mergeXrayTraces) === null || _k === void 0 ? void 0 : _k.toLowerCase(),
200
- tracing: (_m = (_l = this.tracing) === null || _l === void 0 ? void 0 : _l.toLowerCase()) !== null && _m !== void 0 ? _m : (_o = this.config.tracing) === null || _o === void 0 ? void 0 : _o.toLowerCase(),
246
+ captureLambdaPayload: (_e = this.captureLambdaPayload) !== null && _e !== void 0 ? _e : this.config.captureLambdaPayload,
247
+ flushMetricsToLogs: (_f = this.flushMetricsToLogs) !== null && _f !== void 0 ? _f : this.config.flushMetricsToLogs,
248
+ mergeXrayTraces: (_g = this.mergeXrayTraces) !== null && _g !== void 0 ? _g : this.config.mergeXrayTraces,
249
+ tracing: (_h = this.tracing) !== null && _h !== void 0 ? _h : this.config.tracing,
201
250
  };
202
251
  for (const [stringBoolean, value] of Object.entries(stringBooleansMap)) {
203
- if (!['true', 'false', undefined].includes(value)) {
252
+ if (!['true', 'false', undefined].includes(value === null || value === void 0 ? void 0 : value.toString().toLowerCase())) {
204
253
  this.context.stdout.write(`Invalid boolean specified for ${stringBoolean}.\n`);
205
254
  return;
206
255
  }
207
256
  }
208
- const flushMetricsToLogs = this.convertStringBooleanToBoolean(true, this.flushMetricsToLogs, this.config.flushMetricsToLogs);
209
- const mergeXrayTraces = this.convertStringBooleanToBoolean(false, this.mergeXrayTraces, this.config.mergeXrayTraces);
210
- const tracingEnabled = this.convertStringBooleanToBoolean(true, this.tracing, this.config.tracing);
211
- const logLevel = (_p = this.logLevel) !== null && _p !== void 0 ? _p : this.config.logLevel;
212
- const service = (_q = this.service) !== null && _q !== void 0 ? _q : this.config.service;
213
- const environment = (_r = this.environment) !== null && _r !== void 0 ? _r : this.config.environment;
214
- const version = (_s = this.version) !== null && _s !== void 0 ? _s : this.config.version;
257
+ const captureLambdaPayload = commons_1.coerceBoolean(false, this.captureLambdaPayload, this.config.captureLambdaPayload);
258
+ const flushMetricsToLogs = commons_1.coerceBoolean(true, this.flushMetricsToLogs, this.config.flushMetricsToLogs);
259
+ const mergeXrayTraces = commons_1.coerceBoolean(false, this.mergeXrayTraces, this.config.mergeXrayTraces);
260
+ const tracingEnabled = commons_1.coerceBoolean(true, this.tracing, this.config.tracing);
261
+ const interactive = commons_1.coerceBoolean(false, this.interactive, this.config.interactive);
262
+ const logLevel = (_j = this.logLevel) !== null && _j !== void 0 ? _j : this.config.logLevel;
263
+ const service = (_k = this.service) !== null && _k !== void 0 ? _k : this.config.service;
264
+ const environment = (_l = this.environment) !== null && _l !== void 0 ? _l : this.config.environment;
265
+ const version = (_m = this.version) !== null && _m !== void 0 ? _m : this.config.version;
215
266
  const tagsMap = {
216
267
  environment,
217
268
  service,
@@ -228,17 +279,19 @@ class InstrumentCommand extends clipanion_1.Command {
228
279
  const plural = tagsMissing.length > 1;
229
280
  this.context.stdout.write(`${chalk_1.bold(chalk_1.yellow('[Warning]'))} The ${tags} tag${plural ? 's have' : ' has'} not been configured. Learn more about Datadog unified service tagging: ${chalk_1.underline(chalk_1.blueBright('https://docs.datadoghq.com/getting_started/tagging/unified_service_tagging/#serverless-environment.'))}\n`);
230
281
  }
231
- const extraTags = (_u = (_t = this.extraTags) === null || _t === void 0 ? void 0 : _t.toLowerCase()) !== null && _u !== void 0 ? _u : (_v = this.config.extraTags) === null || _v === void 0 ? void 0 : _v.toLowerCase();
282
+ const extraTags = (_p = (_o = this.extraTags) === null || _o === void 0 ? void 0 : _o.toLowerCase()) !== null && _p !== void 0 ? _p : (_q = this.config.extraTags) === null || _q === void 0 ? void 0 : _q.toLowerCase();
232
283
  if (extraTags && !commons_1.sentenceMatchesRegEx(extraTags, constants_1.EXTRA_TAGS_REG_EXP)) {
233
284
  this.context.stdout.write('Extra tags do not comply with the <key>:<value> array.\n');
234
285
  return;
235
286
  }
236
287
  return {
288
+ captureLambdaPayload,
237
289
  environment,
238
290
  extensionVersion,
239
291
  extraTags,
240
292
  flushMetricsToLogs,
241
293
  forwarderARN,
294
+ interactive,
242
295
  layerAWSAccount,
243
296
  layerVersion,
244
297
  logLevel,
@@ -249,25 +302,24 @@ class InstrumentCommand extends clipanion_1.Command {
249
302
  };
250
303
  }
251
304
  printPlannedActions(configs) {
252
- var _a, _b, _c;
253
305
  const prefix = this.dryRun ? chalk_1.bold(chalk_1.cyan('[Dry Run] ')) : '';
254
- let anyUpdates = false;
255
- for (const config of configs) {
256
- if (config.updateRequest !== undefined ||
257
- ((_a = config.logGroupConfiguration) === null || _a === void 0 ? void 0 : _a.createLogGroupRequest) !== undefined ||
258
- ((_b = config.logGroupConfiguration) === null || _b === void 0 ? void 0 : _b.deleteSubscriptionFilterRequest) !== undefined ||
259
- ((_c = config.logGroupConfiguration) === null || _c === void 0 ? void 0 : _c.subscriptionFilterRequest) !== undefined ||
260
- (config === null || config === void 0 ? void 0 : config.tagConfiguration) !== undefined) {
261
- anyUpdates = true;
262
- break;
263
- }
264
- }
265
- if (!anyUpdates) {
306
+ const willUpdate = commons_1.willUpdateFunctionConfigs(configs);
307
+ if (!willUpdate) {
266
308
  this.context.stdout.write(`\n${prefix}No updates will be applied\n`);
267
309
  return;
268
310
  }
269
311
  this.context.stdout.write(`${chalk_1.bold(chalk_1.yellow('[Warning]'))} Instrument your ${chalk_1.hex('#FF9900').bold('Lambda')} functions in a dev or staging environment first. Should the instrumentation result be unsatisfactory, run \`${chalk_1.bold('uninstrument')}\` with the same arguments to revert the changes.\n`);
270
- this.context.stdout.write(`${prefix}Will apply the following updates:\n`);
312
+ this.context.stdout.write(`\n${chalk_1.bold(chalk_1.yellow('[!]'))} Functions to be updated:\n`);
313
+ for (const config of configs) {
314
+ this.context.stdout.write(`\t- ${chalk_1.bold(config.functionARN)}\n`);
315
+ // Later, we should inform which layer is the latest.
316
+ if (this.interactive) {
317
+ if (!this.extensionVersion || !this.extensionVersion) {
318
+ this.context.stdout.write(`\t${chalk_1.bold(chalk_1.yellow('[Warning]'))} At least one latest layer version is being used. Ensure to lock in versions for production applications using \`--layerVersion\` and \`--extensionVersion\`.\n`);
319
+ }
320
+ }
321
+ }
322
+ this.context.stdout.write(`\n${prefix}Will apply the following updates:\n`);
271
323
  for (const config of configs) {
272
324
  if (config.updateRequest) {
273
325
  this.context.stdout.write(`UpdateFunctionConfiguration -> ${config.functionARN}\n${JSON.stringify(config.updateRequest, undefined, 2)}\n`);
@@ -301,20 +353,22 @@ class InstrumentCommand extends clipanion_1.Command {
301
353
  exports.InstrumentCommand = InstrumentCommand;
302
354
  InstrumentCommand.addPath('lambda', 'instrument');
303
355
  InstrumentCommand.addOption('functions', clipanion_1.Command.Array('-f,--function'));
304
- InstrumentCommand.addOption('regExPattern', clipanion_1.Command.String('--functions-regex'));
356
+ InstrumentCommand.addOption('regExPattern', clipanion_1.Command.String('--functions-regex,--functionsRegex'));
305
357
  InstrumentCommand.addOption('region', clipanion_1.Command.String('-r,--region'));
306
- InstrumentCommand.addOption('extensionVersion', clipanion_1.Command.String('-e,--extensionVersion'));
307
- InstrumentCommand.addOption('layerVersion', clipanion_1.Command.String('-v,--layerVersion'));
308
- InstrumentCommand.addOption('layerAWSAccount', clipanion_1.Command.String('-a,--layerAccount', { hidden: true }));
358
+ InstrumentCommand.addOption('extensionVersion', clipanion_1.Command.String('-e,--extension-version,--extensionVersion'));
359
+ InstrumentCommand.addOption('layerVersion', clipanion_1.Command.String('-v,--layer-version,--layerVersion'));
360
+ InstrumentCommand.addOption('layerAWSAccount', clipanion_1.Command.String('-a,--layer-account,--layerAccount', { hidden: true }));
309
361
  InstrumentCommand.addOption('tracing', clipanion_1.Command.String('--tracing'));
310
- InstrumentCommand.addOption('mergeXrayTraces', clipanion_1.Command.String('--mergeXrayTraces'));
311
- InstrumentCommand.addOption('flushMetricsToLogs', clipanion_1.Command.String('--flushMetricsToLogs'));
362
+ InstrumentCommand.addOption('mergeXrayTraces', clipanion_1.Command.String('--merge-xray-traces,--mergeXrayTraces'));
363
+ InstrumentCommand.addOption('flushMetricsToLogs', clipanion_1.Command.String('--flush-metrics-to-logs,--flushMetricsToLogs'));
312
364
  InstrumentCommand.addOption('dryRun', clipanion_1.Command.Boolean('-d,--dry'));
313
365
  InstrumentCommand.addOption('configPath', clipanion_1.Command.String('--config'));
314
366
  InstrumentCommand.addOption('forwarder', clipanion_1.Command.String('--forwarder'));
315
- InstrumentCommand.addOption('logLevel', clipanion_1.Command.String('--logLevel'));
367
+ InstrumentCommand.addOption('logLevel', clipanion_1.Command.String('--log-level,--logLevel'));
316
368
  InstrumentCommand.addOption('service', clipanion_1.Command.String('--service'));
317
369
  InstrumentCommand.addOption('environment', clipanion_1.Command.String('--env'));
318
370
  InstrumentCommand.addOption('version', clipanion_1.Command.String('--version'));
319
- InstrumentCommand.addOption('extraTags', clipanion_1.Command.String('--extra-tags'));
320
- InstrumentCommand.addOption('sourceCodeIntegration', clipanion_1.Command.Boolean('-s,--source-code-integration'));
371
+ InstrumentCommand.addOption('extraTags', clipanion_1.Command.String('--extra-tags,--extraTags'));
372
+ InstrumentCommand.addOption('sourceCodeIntegration', clipanion_1.Command.Boolean('-s,--source-code-integration,--sourceCodeIntegration'));
373
+ InstrumentCommand.addOption('interactive', clipanion_1.Command.Boolean('-i,--interactive'));
374
+ InstrumentCommand.addOption('captureLambdaPayload', clipanion_1.Command.String('--capture-lambda-payload,--captureLambdaPayload'));
@@ -4,12 +4,14 @@ import { CloudWatchLogs, Lambda } from 'aws-sdk';
4
4
  * the CLI in order to instrument properly.
5
5
  */
6
6
  export interface LambdaConfigOptions {
7
+ captureLambdaPayload?: string;
7
8
  environment?: string;
8
9
  extensionVersion?: string;
9
10
  extraTags?: string;
10
11
  flushMetricsToLogs?: string;
11
12
  forwarder?: string;
12
13
  functions: string[];
14
+ interactive?: boolean;
13
15
  layerAWSAccount?: string;
14
16
  layerVersion?: string;
15
17
  logLevel?: string;
@@ -27,7 +29,6 @@ export interface LambdaConfigOptions {
27
29
  export interface FunctionConfiguration {
28
30
  functionARN: string;
29
31
  lambdaConfig: Lambda.FunctionConfiguration;
30
- lambdaLibraryLayerArn?: string;
31
32
  logGroupConfiguration?: LogGroupConfiguration;
32
33
  tagConfiguration?: TagConfiguration;
33
34
  updateRequest?: Lambda.UpdateFunctionConfigurationRequest;
@@ -37,9 +38,11 @@ export interface FunctionConfiguration {
37
38
  * lambda to be instrumented.
38
39
  */
39
40
  export interface InstrumentationSettings extends InstrumentationTags {
41
+ captureLambdaPayload?: boolean;
40
42
  extensionVersion?: number;
41
43
  flushMetricsToLogs: boolean;
42
44
  forwarderARN?: string;
45
+ interactive?: boolean;
43
46
  layerAWSAccount?: string;
44
47
  layerVersion?: number;
45
48
  logLevel?: string;
@@ -26,7 +26,9 @@ const applyLogGroupConfig = (logs, config) => __awaiter(void 0, void 0, void 0,
26
26
  if (deleteSubscriptionFilterRequest !== undefined) {
27
27
  yield logs.deleteSubscriptionFilter(deleteSubscriptionFilterRequest).promise();
28
28
  }
29
- yield logs.putSubscriptionFilter(subscriptionFilterRequest).promise();
29
+ if (subscriptionFilterRequest !== undefined) {
30
+ yield logs.putSubscriptionFilter(subscriptionFilterRequest).promise();
31
+ }
30
32
  });
31
33
  exports.applyLogGroupConfig = applyLogGroupConfig;
32
34
  const calculateLogGroupUpdateRequest = (logs, logGroupName, forwarderARN) => __awaiter(void 0, void 0, void 0, function* () {
@@ -0,0 +1,9 @@
1
+ import { CheckboxQuestion, ConfirmQuestion, InputQuestion, ListQuestion } from 'inquirer';
2
+ export declare const datadogApiKeyTypeQuestion: (datadogSite: string) => ListQuestion;
3
+ export declare const datadogEnvVarsQuestions: (datadogApiKeyType: Record<string, any>) => InputQuestion;
4
+ export declare const confirmationQuestion: (message: string) => ConfirmQuestion;
5
+ export declare const functionSelectionQuestion: (functionNames: string[]) => CheckboxQuestion;
6
+ export declare const requestAWSCredentials: () => Promise<void>;
7
+ export declare const requestDatadogEnvVars: () => Promise<void>;
8
+ export declare const requestChangesConfirmation: (message: string) => Promise<any>;
9
+ export declare const requestFunctionSelection: (functionNames: string[]) => Promise<any>;
@@ -0,0 +1,187 @@
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.requestFunctionSelection = exports.requestChangesConfirmation = exports.requestDatadogEnvVars = exports.requestAWSCredentials = exports.functionSelectionQuestion = exports.confirmationQuestion = exports.datadogEnvVarsQuestions = exports.datadogApiKeyTypeQuestion = void 0;
13
+ const chalk_1 = require("chalk");
14
+ const inquirer_1 = require("inquirer");
15
+ const constants_1 = require("./constants");
16
+ const commons_1 = require("./functions/commons");
17
+ const awsCredentialsQuestions = [
18
+ {
19
+ // AWS_ACCESS_KEY_ID question
20
+ message: 'Enter AWS Access Key ID:',
21
+ name: constants_1.AWS_ACCESS_KEY_ID_ENV_VAR,
22
+ type: 'input',
23
+ validate: (value) => {
24
+ if (!value || !commons_1.sentenceMatchesRegEx(value, constants_1.AWS_ACCESS_KEY_ID_REG_EXP)) {
25
+ return 'Enter a valid AWS Access Key ID.';
26
+ }
27
+ return true;
28
+ },
29
+ },
30
+ {
31
+ // AWS_SECRET_ACCESS_KEY_ENV_VAR question
32
+ mask: true,
33
+ message: 'Enter AWS Secret Access Key:',
34
+ name: constants_1.AWS_SECRET_ACCESS_KEY_ENV_VAR,
35
+ type: 'password',
36
+ validate: (value) => {
37
+ if (!value || !commons_1.sentenceMatchesRegEx(value, constants_1.AWS_SECRET_ACCESS_KEY_REG_EXP)) {
38
+ return 'Enter a valid AWS Secret Access Key.';
39
+ }
40
+ return true;
41
+ },
42
+ },
43
+ {
44
+ // AWS_SESSION_TOKEN
45
+ mask: true,
46
+ message: 'Enter AWS Session Token (optional):',
47
+ name: constants_1.AWS_SESSION_TOKEN_ENV_VAR,
48
+ type: 'password',
49
+ },
50
+ {
51
+ // AWS_DEFAULT_REGION
52
+ choices: constants_1.AWS_REGIONS,
53
+ default: 0,
54
+ message: 'Select an AWS region:',
55
+ name: constants_1.AWS_DEFAULT_REGION_ENV_VAR,
56
+ type: 'list',
57
+ },
58
+ ];
59
+ const datadogApiKeyTypeQuestion = (datadogSite) => ({
60
+ choices: [
61
+ {
62
+ name: `Plain text ${chalk_1.bold('API Key')} (Recommended for trial users) `,
63
+ value: {
64
+ envVar: constants_1.CI_API_KEY_ENV_VAR,
65
+ message: 'API Key:',
66
+ },
67
+ },
68
+ new inquirer_1.Separator(),
69
+ {
70
+ name: `API key encrypted with AWS Key Management Service ${chalk_1.bold('(KMS) API Key')}`,
71
+ value: {
72
+ envVar: constants_1.CI_KMS_API_KEY_ENV_VAR,
73
+ message: 'KMS Encrypted API Key:',
74
+ },
75
+ },
76
+ {
77
+ name: `AWS Secrets Manager ${chalk_1.bold('API Key Secret ARN')}`,
78
+ value: {
79
+ envVar: constants_1.CI_API_KEY_SECRET_ARN_ENV_VAR,
80
+ message: 'API Key Secret ARN:',
81
+ },
82
+ },
83
+ ],
84
+ message: `Which type of Datadog API Key you want to set? \nLearn more at ${chalk_1.blueBright(`https://app.${datadogSite}/organization-settings/api-keys`)}`,
85
+ name: 'type',
86
+ type: 'list',
87
+ });
88
+ exports.datadogApiKeyTypeQuestion = datadogApiKeyTypeQuestion;
89
+ const datadogSiteQuestion = {
90
+ // DATADOG SITE
91
+ choices: constants_1.SITES,
92
+ message: `Select the Datadog site to send data. \nLearn more at ${chalk_1.blueBright('https://docs.datadoghq.com/getting_started/site/')}`,
93
+ name: constants_1.CI_SITE_ENV_VAR,
94
+ type: 'list',
95
+ };
96
+ const datadogEnvVarsQuestions = (datadogApiKeyType) => ({
97
+ // DATADOG API KEY given type
98
+ default: process.env[datadogApiKeyType.envVar],
99
+ message: datadogApiKeyType.message,
100
+ name: datadogApiKeyType.envVar,
101
+ type: 'input',
102
+ validate: (value) => {
103
+ if (!value || !commons_1.sentenceMatchesRegEx(value, constants_1.DATADOG_API_KEY_REG_EXP)) {
104
+ return 'Enter a valid Datadog API Key.';
105
+ }
106
+ return true;
107
+ },
108
+ });
109
+ exports.datadogEnvVarsQuestions = datadogEnvVarsQuestions;
110
+ const confirmationQuestion = (message) => ({
111
+ message,
112
+ name: 'confirmation',
113
+ type: 'confirm',
114
+ });
115
+ exports.confirmationQuestion = confirmationQuestion;
116
+ const functionSelectionQuestion = (functionNames) => ({
117
+ choices: functionNames,
118
+ message: 'Select the functions to modify',
119
+ name: 'functions',
120
+ type: 'checkbox',
121
+ validate: (selectedFunctions) => {
122
+ if (selectedFunctions.length < 1) {
123
+ return 'You must choose at least one function.';
124
+ }
125
+ return true;
126
+ },
127
+ });
128
+ exports.functionSelectionQuestion = functionSelectionQuestion;
129
+ const requestAWSCredentials = () => __awaiter(void 0, void 0, void 0, function* () {
130
+ try {
131
+ const awsCredentialsAnswers = yield inquirer_1.prompt(awsCredentialsQuestions);
132
+ process.env[constants_1.AWS_ACCESS_KEY_ID_ENV_VAR] = awsCredentialsAnswers[constants_1.AWS_ACCESS_KEY_ID_ENV_VAR];
133
+ process.env[constants_1.AWS_SECRET_ACCESS_KEY_ENV_VAR] = awsCredentialsAnswers[constants_1.AWS_SECRET_ACCESS_KEY_ENV_VAR];
134
+ process.env[constants_1.AWS_DEFAULT_REGION_ENV_VAR] = awsCredentialsAnswers[constants_1.AWS_DEFAULT_REGION_ENV_VAR];
135
+ if (awsCredentialsAnswers[constants_1.AWS_SESSION_TOKEN_ENV_VAR] !== undefined) {
136
+ process.env[constants_1.AWS_SESSION_TOKEN_ENV_VAR] = awsCredentialsAnswers[constants_1.AWS_SESSION_TOKEN_ENV_VAR];
137
+ }
138
+ }
139
+ catch (e) {
140
+ if (e instanceof Error) {
141
+ throw Error(`Couldn't set AWS Credentials. ${e.message}`);
142
+ }
143
+ }
144
+ });
145
+ exports.requestAWSCredentials = requestAWSCredentials;
146
+ const requestDatadogEnvVars = () => __awaiter(void 0, void 0, void 0, function* () {
147
+ try {
148
+ const datadogSiteAnswer = yield inquirer_1.prompt(datadogSiteQuestion);
149
+ const selectedDatadogSite = datadogSiteAnswer[constants_1.CI_SITE_ENV_VAR];
150
+ process.env[constants_1.CI_SITE_ENV_VAR] = selectedDatadogSite;
151
+ const datadogApiKeyTypeAnswer = yield inquirer_1.prompt(exports.datadogApiKeyTypeQuestion(selectedDatadogSite));
152
+ const datadogApiKeyType = datadogApiKeyTypeAnswer.type;
153
+ const datadogEnvVars = yield inquirer_1.prompt(exports.datadogEnvVarsQuestions(datadogApiKeyType));
154
+ const selectedDatadogApiKeyEnvVar = datadogApiKeyType.envVar;
155
+ process.env[selectedDatadogApiKeyEnvVar] = datadogEnvVars[selectedDatadogApiKeyEnvVar];
156
+ }
157
+ catch (e) {
158
+ if (e instanceof Error) {
159
+ throw Error(`Couldn't set Datadog Environment Variables. ${e.message}`);
160
+ }
161
+ }
162
+ });
163
+ exports.requestDatadogEnvVars = requestDatadogEnvVars;
164
+ const requestChangesConfirmation = (message) => __awaiter(void 0, void 0, void 0, function* () {
165
+ try {
166
+ const confirmationAnswer = yield inquirer_1.prompt(exports.confirmationQuestion(message));
167
+ return confirmationAnswer.confirmation;
168
+ }
169
+ catch (e) {
170
+ if (e instanceof Error) {
171
+ throw Error(`Couldn't receive confirmation. ${e.message}`);
172
+ }
173
+ }
174
+ });
175
+ exports.requestChangesConfirmation = requestChangesConfirmation;
176
+ const requestFunctionSelection = (functionNames) => __awaiter(void 0, void 0, void 0, function* () {
177
+ try {
178
+ const selectedFunctionsAnswer = yield inquirer_1.prompt(exports.functionSelectionQuestion(functionNames));
179
+ return selectedFunctionsAnswer.functions;
180
+ }
181
+ catch (e) {
182
+ if (e instanceof Error) {
183
+ throw Error(`Couldn't receive selected functions. ${e.message}`);
184
+ }
185
+ }
186
+ });
187
+ exports.requestFunctionSelection = requestFunctionSelection;
@@ -5,6 +5,8 @@ export declare class UninstrumentCommand extends Command {
5
5
  private dryRun;
6
6
  private forwarder?;
7
7
  private functions;
8
+ private interactive;
9
+ private regExPattern?;
8
10
  private region?;
9
11
  execute(): Promise<1 | 0>;
10
12
  private printPlannedActions;