dd-trace 5.116.0 → 5.118.0
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/ci/diagnose.js +162 -21
- package/ci/init.js +0 -1
- package/ci/runbook.md +187 -180
- package/ci/test-optimization-validation/approval-artifacts.js +3 -1
- package/ci/test-optimization-validation/approval.js +52 -15
- package/ci/test-optimization-validation/ci-command-candidate.js +26 -32
- package/ci/test-optimization-validation/ci-discovery.js +1 -1
- package/ci/test-optimization-validation/ci-package-scripts.js +141 -0
- package/ci/test-optimization-validation/ci-remediation.js +112 -39
- package/ci/test-optimization-validation/cli.js +516 -681
- package/ci/test-optimization-validation/command-blocker.js +188 -33
- package/ci/test-optimization-validation/command-output-policy.js +3 -26
- package/ci/test-optimization-validation/command-runner.js +189 -245
- package/ci/test-optimization-validation/environment.js +90 -0
- package/ci/test-optimization-validation/executable.js +159 -388
- package/ci/test-optimization-validation/framework-adapters/cucumber.js +119 -0
- package/ci/test-optimization-validation/framework-adapters/cypress.js +107 -0
- package/ci/test-optimization-validation/framework-adapters/playwright.js +181 -0
- package/ci/test-optimization-validation/generated-files.js +75 -13
- package/ci/test-optimization-validation/generated-test-contract.js +283 -0
- package/ci/test-optimization-validation/generated-verifier.js +49 -16
- package/ci/test-optimization-validation/literal-environment.js +57 -0
- package/ci/test-optimization-validation/manifest-loader.js +2 -22
- package/ci/test-optimization-validation/manifest-scaffold.js +816 -515
- package/ci/test-optimization-validation/manifest-schema.js +494 -702
- package/ci/test-optimization-validation/offline-fixtures.js +4 -1
- package/ci/test-optimization-validation/plan-writer.js +243 -984
- package/ci/test-optimization-validation/preflight-runner.js +49 -55
- package/ci/test-optimization-validation/redaction.js +2 -1
- package/ci/test-optimization-validation/report-writer.js +391 -1357
- package/ci/test-optimization-validation/result-semantics.js +86 -0
- package/ci/test-optimization-validation/runner-command.js +249 -0
- package/ci/test-optimization-validation/runner-contract.js +664 -0
- package/ci/test-optimization-validation/scenarios/auto-test-retries.js +29 -3
- package/ci/test-optimization-validation/scenarios/basic-reporting.js +240 -543
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +450 -670
- package/ci/test-optimization-validation/scenarios/early-flake-detection.js +4 -3
- package/ci/test-optimization-validation/scenarios/helpers.js +67 -9
- package/ci/test-optimization-validation/scenarios/test-management.js +4 -3
- package/ci/test-optimization-validation/source-text.js +87 -0
- package/ci/test-optimization-validation/test-output.js +12 -22
- package/ext/tags.d.ts +1 -0
- package/index.d.ts +7 -0
- package/package.json +3 -3
- package/packages/datadog-instrumentations/src/cucumber.js +11 -12
- package/packages/datadog-instrumentations/src/helpers/channel.js +74 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/openai-agents.js +31 -0
- package/packages/datadog-instrumentations/src/jest.js +18 -17
- package/packages/datadog-instrumentations/src/mocha/main.js +79 -30
- package/packages/datadog-instrumentations/src/openai-agents.js +159 -0
- package/packages/datadog-instrumentations/src/playwright.js +3 -24
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +1 -1
- package/packages/datadog-instrumentations/src/vitest-main.js +14 -26
- package/packages/datadog-instrumentations/src/vitest-util.js +0 -7
- package/packages/datadog-instrumentations/src/vitest-worker.js +5 -8
- package/packages/datadog-plugin-cucumber/src/index.js +2 -1
- package/packages/datadog-plugin-mocha/src/index.js +2 -1
- package/packages/datadog-plugin-openai-agents/src/index.js +74 -0
- package/packages/datadog-plugin-openai-agents/src/integration.js +503 -0
- package/packages/datadog-plugin-openai-agents/src/processor.js +108 -0
- package/packages/datadog-plugin-openai-agents/src/util.js +60 -0
- package/packages/datadog-plugin-playwright/src/index.js +4 -1
- package/packages/datadog-plugin-vitest/src/index.js +5 -5
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +48 -49
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +161 -33
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +6 -4
- package/packages/dd-trace/src/config/generated-config-types.d.ts +2 -0
- package/packages/dd-trace/src/config/supported-configurations.json +7 -0
- package/packages/dd-trace/src/encode/span-stats.js +7 -1
- package/packages/dd-trace/src/exporter.js +16 -9
- package/packages/dd-trace/src/llmobs/index.js +9 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +104 -22
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +5 -9
- package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +20 -0
- package/packages/dd-trace/src/llmobs/plugins/openai-agents/utils.js +321 -0
- package/packages/dd-trace/src/llmobs/sdk.js +2 -1
- package/packages/dd-trace/src/llmobs/span_processor.js +7 -2
- package/packages/dd-trace/src/llmobs/tagger.js +23 -3
- package/packages/dd-trace/src/llmobs/util.js +56 -3
- package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +3 -6
- package/packages/dd-trace/src/openfeature/configuration_source.js +5 -8
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +5 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +9 -3
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/outbound.js +4 -1
- package/packages/dd-trace/src/profiling/profilers/space.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/wall.js +1 -0
- package/packages/dd-trace/src/span_processor.js +1 -1
- package/packages/dd-trace/src/span_stats.js +22 -4
- package/ci/test-optimization-validation/command-suitability.js +0 -471
- package/ci/test-optimization-validation/init-probe-preload.js +0 -163
- package/ci/test-optimization-validation/init-probe.js +0 -246
- package/ci/test-optimization-validation/late-initialization.js +0 -63
- package/ci/test-optimization-validation/local-command.js +0 -163
- package/ci/test-optimization-validation/setup-runner.js +0 -97
- package/ci/test-optimization-validation-manifest.schema.json +0 -1
|
@@ -1,8 +1,29 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { stripAnsi } = require('./test-output')
|
|
4
|
+
|
|
3
5
|
const FILESYSTEM_PERMISSION_PATTERN = /\b(?:EACCES|EPERM|Operation not permitted|Permission denied)\b/i
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
+
const LOCAL_SOCKET_PATTERN = /\b(?:127\.0\.0\.1|localhost|listen)\b/i
|
|
7
|
+
const CONNECTION_REFUSED_PATTERN = /\bECONNREFUSED\b|\bconnection refused\b/i
|
|
8
|
+
const NO_TESTS_FOUND_PATTERN =
|
|
9
|
+
/\b(?:No test files? found|No tests? found|No test files? were found|0 tests? collected)\b/i
|
|
10
|
+
const MODULE_OR_TRANSFORM_PATTERN =
|
|
11
|
+
/\b(?:Cannot find (?:module|package)|ERR_MODULE_NOT_FOUND|MODULE_NOT_FOUND|ERR_PACKAGE_PATH_NOT_EXPORTED|Package subpath\b[\s\S]*\bnot defined by "exports"|Could not resolve|transform failed)\b/i
|
|
12
|
+
const CYPRESS_BINARY_PATTERN =
|
|
13
|
+
/(?:Cypress executable not found|Cypress binary is missing|Cypress failed to start|Please reinstall Cypress)/i
|
|
14
|
+
const PLAYWRIGHT_BROWSER_PATTERN = new RegExp(
|
|
15
|
+
String.raw`(?:browserType\.launch: Executable doesn't exist|` +
|
|
16
|
+
'Please run the following command to download new browsers|playwright install)',
|
|
17
|
+
'i'
|
|
18
|
+
)
|
|
19
|
+
const PLAYWRIGHT_BROWSER_LAUNCH_PATTERN =
|
|
20
|
+
/(?:browserType\.launch: Failed to launch the browser process|bootstrap_check_in|MachPortRendezvous)/i
|
|
21
|
+
const PLAYWRIGHT_BROWSER_ABORT_PATTERN =
|
|
22
|
+
/(?:browserType\.launch: Target page, context or browser has been closed|Browser logs:)[\s\S]*?(?:signal=SIGABRT|Received signal 6|Abort trap: 6)/i
|
|
23
|
+
const VITEST_BROWSER_PROVIDER_PATTERN =
|
|
24
|
+
/(?:Cannot find (?:module|package).*@vitest\/browser|@vitest\/browser-[^\s'"]+.*(?:missing|not (?:found|installed)))/i
|
|
25
|
+
const RUNNER_COMMAND_NOT_FOUND_PATTERN =
|
|
26
|
+
/(?:command not found|is not recognized as an internal or external command|spawn [^\r\n]+ ENOENT)/i
|
|
6
27
|
|
|
7
28
|
/**
|
|
8
29
|
* Identifies toolchain and execution-environment failures that happen before tests start.
|
|
@@ -10,52 +31,186 @@ const WATCHMAN_PATTERN = /\bwatchman\b/i
|
|
|
10
31
|
* @param {object} result command result
|
|
11
32
|
* @param {string} [result.stdout] captured stdout
|
|
12
33
|
* @param {string} [result.stderr] captured stderr
|
|
34
|
+
* @param {object} [options] classification options
|
|
35
|
+
* @param {boolean} [options.browserRequired] whether the selected runner uses browser mode
|
|
36
|
+
* @param {string} [options.framework] test framework identifier
|
|
37
|
+
* @param {boolean} [options.testsRan] whether reliable test output was observed
|
|
13
38
|
* @returns {object|undefined} structured blocker diagnosis
|
|
14
39
|
*/
|
|
15
|
-
function getCommandBlocker (result) {
|
|
40
|
+
function getCommandBlocker (result, options = {}) {
|
|
16
41
|
const output = `${result.stdout || ''}\n${result.stderr || ''}`
|
|
17
|
-
|
|
18
|
-
/defines "packageManager": "(yarn@[^"]+)"[\s\S]*?current global version of Yarn is ([0-9][0-9.]*)\./i
|
|
19
|
-
)
|
|
20
|
-
if (yarnVersions) {
|
|
42
|
+
if (Array.isArray(result.missingRequiredEnvVars) && result.missingRequiredEnvVars.length > 0) {
|
|
21
43
|
return {
|
|
22
|
-
kind: '
|
|
23
|
-
summary:
|
|
24
|
-
|
|
25
|
-
recommendation:
|
|
26
|
-
'
|
|
27
|
-
signals:
|
|
44
|
+
kind: 'project-command-environment-missing',
|
|
45
|
+
summary: 'The selected project test command requires approved non-secret environment variables that are not ' +
|
|
46
|
+
'available in the validator process. No Test Optimization conclusion was reached.',
|
|
47
|
+
recommendation: `Set the required project test variables (${result.missingRequiredEnvVars.join(', ')}) in the ` +
|
|
48
|
+
'environment that launches the validator, then render and approve a fresh plan.',
|
|
49
|
+
signals: result.missingRequiredEnvVars.map(name => `${name} is not set.`),
|
|
28
50
|
toolchainBlocked: true,
|
|
29
51
|
}
|
|
30
52
|
}
|
|
31
|
-
|
|
32
|
-
if (WATCHMAN_PATTERN.test(output) && FILESYSTEM_PERMISSION_PATTERN.test(output)) {
|
|
53
|
+
if (LOCAL_SOCKET_PATTERN.test(output) && FILESYSTEM_PERMISSION_PATTERN.test(output)) {
|
|
33
54
|
return {
|
|
34
|
-
kind: '
|
|
35
|
-
summary: 'The
|
|
36
|
-
'Test Optimization conclusion was reached.',
|
|
37
|
-
recommendation: '
|
|
38
|
-
'
|
|
39
|
-
|
|
55
|
+
kind: 'local-test-socket-blocked',
|
|
56
|
+
summary: 'The selected project test could not start its localhost listener in this execution environment. ' +
|
|
57
|
+
'The offline Datadog validator did not open this socket. No Test Optimization conclusion was reached.',
|
|
58
|
+
recommendation: 'Run the same approved plan in an environment that permits the project test to use its ' +
|
|
59
|
+
'required localhost socket. This may require normal project-test permissions. Do not request broader ' +
|
|
60
|
+
'permissions automatically or interpret this as a Test Optimization failure.',
|
|
61
|
+
signals: getMatchingLines(
|
|
62
|
+
output,
|
|
63
|
+
/127\.0\.0\.1|localhost|listen|EACCES|EPERM|Operation not permitted|Permission denied/i
|
|
64
|
+
),
|
|
40
65
|
blockedByExecutionEnvironment: true,
|
|
41
66
|
}
|
|
42
67
|
}
|
|
68
|
+
if (options.framework === 'cypress' && result.exitCode !== 0 &&
|
|
69
|
+
CONNECTION_REFUSED_PATTERN.test(output) && LOCAL_SOCKET_PATTERN.test(output)) {
|
|
70
|
+
return {
|
|
71
|
+
kind: 'cypress-application-unavailable',
|
|
72
|
+
summary: 'The selected Cypress spec could not connect to its localhost application. Discovery does not start ' +
|
|
73
|
+
'customer services, so no Test Optimization conclusion was reached.',
|
|
74
|
+
recommendation: 'Start the application through the project\'s normal setup, confirm the selected Cypress spec ' +
|
|
75
|
+
'passes normally, then render and approve a fresh validation plan.',
|
|
76
|
+
signals: getMatchingLines(output, /ECONNREFUSED|connection refused|127\.0\.0\.1|localhost/i),
|
|
77
|
+
blockedByProjectSetup: true,
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (options.testsRan !== true && NO_TESTS_FOUND_PATTERN.test(output)) {
|
|
81
|
+
return {
|
|
82
|
+
kind: 'no-tests-collected',
|
|
83
|
+
summary: 'The selected representative was not collected by the project test runner. No Test Optimization ' +
|
|
84
|
+
'conclusion was reached.',
|
|
85
|
+
recommendation: 'Use the project\'s normal configuration to make a single runtime test collectible, then ' +
|
|
86
|
+
'create a fresh validation plan. Type-only tests and files outside the runner\'s include rules are not valid ' +
|
|
87
|
+
'representatives.',
|
|
88
|
+
signals: getMatchingLines(output, NO_TESTS_FOUND_PATTERN),
|
|
89
|
+
blockedByProjectSetup: true,
|
|
90
|
+
}
|
|
91
|
+
}
|
|
43
92
|
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
93
|
+
const browserMode = options.framework === 'playwright' ||
|
|
94
|
+
(options.framework === 'vitest' && options.browserRequired === true)
|
|
95
|
+
if (browserMode &&
|
|
96
|
+
result.exitCode !== 0 &&
|
|
97
|
+
PLAYWRIGHT_BROWSER_LAUNCH_PATTERN.test(output) && FILESYSTEM_PERMISSION_PATTERN.test(output)) {
|
|
98
|
+
const runner = options.framework === 'vitest' ? 'Vitest browser mode' : 'Playwright'
|
|
49
99
|
return {
|
|
50
|
-
kind:
|
|
51
|
-
summary:
|
|
52
|
-
'
|
|
53
|
-
recommendation: '
|
|
54
|
-
'
|
|
55
|
-
|
|
100
|
+
kind: `${options.framework}-browser-launch-blocked`,
|
|
101
|
+
summary: `${runner} needs to launch the project browser, but the current agent sandbox denied that launch. ` +
|
|
102
|
+
'No Test Optimization conclusion was reached.',
|
|
103
|
+
recommendation: 'Retry the same approved plan from a host shell or another environment where the installed ' +
|
|
104
|
+
'project browser can launch. Do not request broader permissions automatically or change the command, ' +
|
|
105
|
+
'approval file, or approval SHA.',
|
|
106
|
+
signals: getMatchingLines(
|
|
107
|
+
output,
|
|
108
|
+
/browserType\.launch|bootstrap_check_in|MachPortRendezvous|EACCES|EPERM|Operation not permitted|Permission denied/i
|
|
109
|
+
),
|
|
56
110
|
blockedByExecutionEnvironment: true,
|
|
57
111
|
}
|
|
58
112
|
}
|
|
113
|
+
|
|
114
|
+
if (options.framework === 'playwright' && result.exitCode !== 0 &&
|
|
115
|
+
PLAYWRIGHT_BROWSER_ABORT_PATTERN.test(stripAnsi(output))) {
|
|
116
|
+
return {
|
|
117
|
+
kind: 'playwright-browser-process-aborted',
|
|
118
|
+
summary: 'A browser launched by Playwright aborted before the selected tests could produce reliable results. ' +
|
|
119
|
+
'The available evidence does not identify whether the browser/runtime setup, the project, the execution ' +
|
|
120
|
+
'environment, or another local condition caused the abort. No Test Optimization conclusion was reached.',
|
|
121
|
+
recommendation: 'Run the same approved Playwright command directly in the project\'s normal test environment ' +
|
|
122
|
+
'and collect Playwright, browser, and operating-system crash diagnostics. If it succeeds there, render and ' +
|
|
123
|
+
'approve a fresh validation plan in that environment. Do not treat this result as a Test Optimization failure.',
|
|
124
|
+
signals: getMatchingLines(
|
|
125
|
+
output,
|
|
126
|
+
/browserType\.launch: Target page, context or browser has been closed|signal=SIGABRT|Received signal 6|Abort trap: 6/i
|
|
127
|
+
),
|
|
128
|
+
localRuntimeBlocked: true,
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (options.framework === 'cypress' && result.exitCode !== 0 &&
|
|
133
|
+
options.testsRan !== true && CYPRESS_BINARY_PATTERN.test(output)) {
|
|
134
|
+
return {
|
|
135
|
+
kind: 'cypress-runtime-missing',
|
|
136
|
+
summary: 'The Cypress npm package is installed, but its application binary is missing or could not start. ' +
|
|
137
|
+
'No Test Optimization conclusion was reached.',
|
|
138
|
+
recommendation: 'Complete the project\'s normal Cypress binary/browser setup, then render and approve a ' +
|
|
139
|
+
'fresh validation plan. The validator does not download browsers automatically.',
|
|
140
|
+
signals: getMatchingLines(output, CYPRESS_BINARY_PATTERN),
|
|
141
|
+
toolchainBlocked: true,
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (browserMode && result.exitCode !== 0 && options.testsRan !== true &&
|
|
146
|
+
PLAYWRIGHT_BROWSER_PATTERN.test(output)) {
|
|
147
|
+
const vitestBrowser = options.framework === 'vitest' && options.browserRequired === true
|
|
148
|
+
return {
|
|
149
|
+
kind: vitestBrowser ? 'vitest-browser-provider-missing' : 'playwright-browser-missing',
|
|
150
|
+
summary: `${vitestBrowser ? 'Vitest browser mode' : 'Playwright Test'} is installed, but the selected project ` +
|
|
151
|
+
'test requires a browser binary or provider that is not installed. ' +
|
|
152
|
+
'No Test Optimization conclusion was reached.',
|
|
153
|
+
recommendation: `Complete the project's normal ${vitestBrowser ? 'Vitest browser' : 'Playwright browser'} ` +
|
|
154
|
+
'setup, then render and approve a fresh ' +
|
|
155
|
+
'validation plan. The validator does not download browsers automatically.',
|
|
156
|
+
signals: getMatchingLines(output, PLAYWRIGHT_BROWSER_PATTERN),
|
|
157
|
+
toolchainBlocked: true,
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (result.exitCode !== 0 && options.testsRan !== true && options.framework === 'vitest' &&
|
|
162
|
+
options.browserRequired === true && VITEST_BROWSER_PROVIDER_PATTERN.test(output)) {
|
|
163
|
+
return {
|
|
164
|
+
kind: 'vitest-browser-provider-missing',
|
|
165
|
+
summary: 'Vitest browser mode could not load its configured browser provider. Local Test Optimization ' +
|
|
166
|
+
'compatibility was not tested. No Test Optimization conclusion was reached.',
|
|
167
|
+
recommendation: 'Complete the project\'s normal Vitest browser setup, then render and approve a fresh ' +
|
|
168
|
+
'validation plan. The validator does not install browser providers or download browsers automatically.',
|
|
169
|
+
signals: getMatchingLines(output, VITEST_BROWSER_PROVIDER_PATTERN),
|
|
170
|
+
toolchainBlocked: true,
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (result.exitCode !== 0 && options.testsRan !== true && RUNNER_COMMAND_NOT_FOUND_PATTERN.test(output)) {
|
|
175
|
+
return {
|
|
176
|
+
kind: 'test-runner-command-missing',
|
|
177
|
+
summary: 'The selected project test command could not find its test-runner executable, so local Test ' +
|
|
178
|
+
'Optimization compatibility was not tested. No Test Optimization conclusion was reached.',
|
|
179
|
+
recommendation: 'Complete the project\'s normal dependency or package-manager setup so the selected test ' +
|
|
180
|
+
'command can resolve its runner, then render and approve a fresh validation plan.',
|
|
181
|
+
signals: getMatchingLines(output, RUNNER_COMMAND_NOT_FOUND_PATTERN),
|
|
182
|
+
toolchainBlocked: true,
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (result.exitCode !== 0 && options.testsRan !== true && MODULE_OR_TRANSFORM_PATTERN.test(output)) {
|
|
187
|
+
return {
|
|
188
|
+
kind: 'project-command-initialization-failed',
|
|
189
|
+
summary: 'The selected project test command failed during module resolution, transformation, or runner ' +
|
|
190
|
+
'initialization before a reliable test result was observed. No Test Optimization conclusion was reached.',
|
|
191
|
+
recommendation: 'Satisfy the selected test command\'s build and module prerequisites, or select a focused ' +
|
|
192
|
+
'test command whose prerequisites already exist, then render and approve a fresh plan.',
|
|
193
|
+
signals: getMatchingLines(output, MODULE_OR_TRANSFORM_PATTERN),
|
|
194
|
+
toolchainBlocked: true,
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (options.framework === 'cypress' && result.exitCode === 134 && options.testsRan !== true) {
|
|
199
|
+
return {
|
|
200
|
+
kind: 'cypress-process-aborted',
|
|
201
|
+
summary: 'Cypress exited with code 134 before any test result was observed. The available evidence does not ' +
|
|
202
|
+
'identify whether Cypress, its browser/runtime setup, the project, or the execution environment caused the ' +
|
|
203
|
+
'abort. No Test Optimization conclusion was reached.',
|
|
204
|
+
recommendation: 'Run the same project Cypress command directly in the project\'s normal test environment and ' +
|
|
205
|
+
'capture Cypress or operating-system crash diagnostics. If that command succeeds there, render and approve ' +
|
|
206
|
+
'a fresh validation plan in that environment. Do not treat this result as a Test Optimization failure.',
|
|
207
|
+
signals: [
|
|
208
|
+
'Cypress exited with code 134 before any test result was observed.',
|
|
209
|
+
'The captured output did not match a known setup or execution-environment failure.',
|
|
210
|
+
],
|
|
211
|
+
localRuntimeBlocked: true,
|
|
212
|
+
}
|
|
213
|
+
}
|
|
59
214
|
}
|
|
60
215
|
|
|
61
216
|
/**
|
|
@@ -69,7 +224,7 @@ function getMatchingLines (output, pattern) {
|
|
|
69
224
|
const lines = []
|
|
70
225
|
const seen = new Set()
|
|
71
226
|
for (const line of output.split(/\r?\n/)) {
|
|
72
|
-
const value = line.trim()
|
|
227
|
+
const value = stripAnsi(line).trim()
|
|
73
228
|
if (!value || seen.has(value) || !pattern.test(value)) continue
|
|
74
229
|
seen.add(value)
|
|
75
230
|
lines.push(value)
|
|
@@ -10,11 +10,7 @@ const path = require('node:path')
|
|
|
10
10
|
* @returns {string[]} absolute output paths
|
|
11
11
|
*/
|
|
12
12
|
function getCommandOutputPaths (command) {
|
|
13
|
-
|
|
14
|
-
const tokens = command.usesShell ? tokenizeShell(command.shellCommand) : command.argv || []
|
|
15
|
-
const coverageDirectory = getCoverageDirectory(tokens)
|
|
16
|
-
if (coverageDirectory) paths.add(path.resolve(command.cwd, coverageDirectory))
|
|
17
|
-
return [...paths]
|
|
13
|
+
return [...new Set((command.outputPaths || []).map(outputPath => path.resolve(command.cwd, outputPath)))]
|
|
18
14
|
}
|
|
19
15
|
|
|
20
16
|
/**
|
|
@@ -38,7 +34,8 @@ function prepareCommandOutputs ({ command, artifactRoot, repositoryRoot }) {
|
|
|
38
34
|
if (pathExists(outputPath)) {
|
|
39
35
|
throw new Error(
|
|
40
36
|
`Command output path already exists and will not be moved or overwritten: ${outputPath}. ` +
|
|
41
|
-
'
|
|
37
|
+
'The validator will not delete pre-existing output. Inspect and remove it manually, or choose a fresh ' +
|
|
38
|
+
'output path, then render a new approval plan.'
|
|
42
39
|
)
|
|
43
40
|
}
|
|
44
41
|
states.push({
|
|
@@ -140,26 +137,6 @@ function pathExists (filename) {
|
|
|
140
137
|
}
|
|
141
138
|
}
|
|
142
139
|
|
|
143
|
-
function getCoverageDirectory (tokens) {
|
|
144
|
-
let coverageEnabled = false
|
|
145
|
-
for (let index = 0; index < tokens.length; index++) {
|
|
146
|
-
const token = String(tokens[index])
|
|
147
|
-
if (token === '--coverage' || token === '--coverage=true') coverageEnabled = true
|
|
148
|
-
const inline = /^(?:--coverageDirectory|--coverage-directory|--coverage\.reportsDirectory)=(.+)$/.exec(token)
|
|
149
|
-
if (inline) return inline[1]
|
|
150
|
-
if (['--coverageDirectory', '--coverage-directory', '--coverage.reportsDirectory'].includes(token)) {
|
|
151
|
-
return tokens[index + 1]
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
return coverageEnabled ? 'coverage' : undefined
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
function tokenizeShell (source) {
|
|
158
|
-
return String(source || '').match(/"[^"]*"|'[^']*'|[^\s]+/g)?.map(token => {
|
|
159
|
-
return token.replace(/^(?:"([\s\S]*)"|'([\s\S]*)')$/, '$1$2')
|
|
160
|
-
}) || []
|
|
161
|
-
}
|
|
162
|
-
|
|
163
140
|
function assertSafeOutputPath ({ outputPath, repositoryRoot, artifactRoot, command }) {
|
|
164
141
|
const relative = path.relative(repositoryRoot, outputPath)
|
|
165
142
|
if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) {
|