dd-trace 6.8.0 → 6.10.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 +27 -25
- package/ci/init.js +6 -6
- package/ci/runbook.md +114 -20
- package/ci/test-optimization-validation/approval-artifacts.js +36 -3
- package/ci/test-optimization-validation/approval.js +78 -22
- package/ci/test-optimization-validation/blocker-category.js +24 -0
- package/ci/test-optimization-validation/ci-discovery.js +23 -17
- package/ci/test-optimization-validation/ci-package-scripts.js +34 -6
- package/ci/test-optimization-validation/ci-remediation.js +1 -1
- package/ci/test-optimization-validation/cli.js +280 -52
- package/ci/test-optimization-validation/command-blocker.js +159 -20
- package/ci/test-optimization-validation/command-output-policy.js +9 -3
- package/ci/test-optimization-validation/command-runner.js +9 -7
- package/ci/test-optimization-validation/environment.js +4 -2
- package/ci/test-optimization-validation/executable.js +15 -13
- package/ci/test-optimization-validation/execution-lock.js +70 -0
- package/ci/test-optimization-validation/framework-adapters/cucumber-validation.json +3 -0
- package/ci/test-optimization-validation/framework-adapters/cucumber.js +657 -5
- package/ci/test-optimization-validation/framework-adapters/vitest.js +517 -0
- package/ci/test-optimization-validation/generated-files.js +38 -28
- package/ci/test-optimization-validation/generated-test-contract.js +8 -4
- package/ci/test-optimization-validation/generated-verifier.js +24 -17
- package/ci/test-optimization-validation/literal-glob.js +52 -0
- package/ci/test-optimization-validation/manifest-loader.js +3 -0
- package/ci/test-optimization-validation/manifest-scaffold.js +300 -50
- package/ci/test-optimization-validation/manifest-schema.js +80 -17
- package/ci/test-optimization-validation/offline-fixtures.js +13 -4
- package/ci/test-optimization-validation/package-check.js +94 -0
- package/ci/test-optimization-validation/plan-writer.js +183 -10
- package/ci/test-optimization-validation/preflight-runner.js +110 -31
- package/ci/test-optimization-validation/project-build-artifact.js +31 -0
- package/ci/test-optimization-validation/redaction.js +18 -27
- package/ci/test-optimization-validation/report-writer.js +182 -48
- package/ci/test-optimization-validation/result-semantics.js +20 -3
- package/ci/test-optimization-validation/runner-command.js +40 -20
- package/ci/test-optimization-validation/runner-contract.js +79 -43
- package/ci/test-optimization-validation/scenarios/basic-reporting.js +59 -5
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +141 -35
- package/ci/test-optimization-validation/scenarios/helpers.js +30 -6
- package/ci/test-optimization-validation/static-diagnosis.js +10 -3
- package/ci/test-optimization-validation/test-output.js +2 -1
- package/ci/test-optimization-validation/validation-blocker.js +21 -0
- package/ci/vitest-no-worker-init-setup.mjs +140 -42
- package/index.d.ts +140 -1
- package/init.js +1 -17
- package/initialize.mjs +11 -0
- package/loader-hook.mjs +6 -4
- package/package.json +8 -5
- package/packages/datadog-core/src/utils/src/parse-tags.js +0 -1
- package/packages/datadog-esbuild/src/utils.js +16 -1
- package/packages/datadog-instrumentations/src/ai.js +61 -34
- package/packages/datadog-instrumentations/src/bluebird.js +6 -6
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +81 -5
- package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +111 -6
- package/packages/datadog-instrumentations/src/cucumber.js +124 -47
- package/packages/datadog-instrumentations/src/dns.js +21 -2
- package/packages/datadog-instrumentations/src/electron.js +1 -0
- package/packages/datadog-instrumentations/src/fastify.js +3 -1
- package/packages/datadog-instrumentations/src/grpc/client.js +4 -2
- package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +3 -1
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +629 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +34 -9
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +199 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +20 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.js +32 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +62 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +83 -1
- package/packages/datadog-instrumentations/src/helpers/router-helper.js +37 -6
- package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +1 -1
- package/packages/datadog-instrumentations/src/jest.js +980 -234
- package/packages/datadog-instrumentations/src/mocha/main.js +108 -10
- package/packages/datadog-instrumentations/src/mocha/utils.js +66 -50
- package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +25 -0
- package/packages/datadog-instrumentations/src/mocha/worker.js +12 -18
- package/packages/datadog-instrumentations/src/mysql.js +46 -16
- package/packages/datadog-instrumentations/src/mysql2.js +119 -18
- package/packages/datadog-instrumentations/src/next.js +155 -23
- package/packages/datadog-instrumentations/src/openai.js +14 -0
- package/packages/datadog-instrumentations/src/path-to-regexp.js +67 -1
- package/packages/datadog-instrumentations/src/pg.js +209 -11
- package/packages/datadog-instrumentations/src/playwright.js +173 -79
- package/packages/datadog-instrumentations/src/promise-js.js +4 -4
- package/packages/datadog-instrumentations/src/promise.js +3 -3
- package/packages/datadog-instrumentations/src/router.js +195 -19
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +85 -13
- package/packages/datadog-instrumentations/src/vitest-main.js +528 -72
- package/packages/datadog-instrumentations/src/vitest-util.js +106 -12
- package/packages/datadog-instrumentations/src/vitest-worker.js +382 -40
- package/packages/datadog-instrumentations/src/webdriverio.js +212 -22
- package/packages/datadog-instrumentations/src/when.js +3 -3
- package/packages/datadog-instrumentations/src/ws.js +5 -1
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +12 -6
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +59 -48
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -5
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -5
- package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +1 -3
- package/packages/datadog-plugin-cucumber/src/index.js +5 -1
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +51 -47
- package/packages/datadog-plugin-cypress/src/support.js +7 -4
- package/packages/datadog-plugin-electron/src/net.js +10 -4
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +31 -17
- package/packages/datadog-plugin-http/src/client.js +1 -1
- package/packages/datadog-plugin-http2/src/client.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +6 -22
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +2 -3
- package/packages/datadog-plugin-kafkajs/src/consumer.js +2 -3
- package/packages/datadog-plugin-kafkajs/src/producer.js +5 -3
- package/packages/datadog-plugin-kafkajs/src/utils.js +65 -7
- package/packages/datadog-plugin-mocha/src/index.js +832 -4
- package/packages/datadog-plugin-mysql/src/index.js +37 -0
- package/packages/datadog-plugin-next/src/index.js +51 -21
- package/packages/datadog-plugin-openai/src/tracing.js +4 -0
- package/packages/datadog-plugin-openai-agents/src/integration.js +278 -69
- package/packages/datadog-plugin-openai-agents/src/processor.js +16 -4
- package/packages/datadog-plugin-pg/src/index.js +66 -1
- package/packages/datadog-plugin-playwright/src/index.js +1 -1
- package/packages/datadog-plugin-vitest/src/index.js +103 -27
- package/packages/datadog-plugin-ws/src/util.js +2 -1
- package/packages/datadog-shimmer/src/shimmer.js +6 -2
- package/packages/dd-trace/src/aiguard/sdk.js +3 -0
- package/packages/dd-trace/src/appsec/api_security/normalized-route.js +453 -0
- package/packages/dd-trace/src/appsec/{blocking.js → blocking/index.js} +26 -6
- package/packages/dd-trace/src/appsec/handlers/auth.js +62 -0
- package/packages/dd-trace/src/appsec/handlers/http-request.js +228 -0
- package/packages/dd-trace/src/appsec/handlers/http-response.js +78 -0
- package/packages/dd-trace/src/appsec/handlers/http-shared.js +24 -0
- package/packages/dd-trace/src/appsec/handlers/payments.js +104 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
- package/packages/dd-trace/src/appsec/index.js +48 -476
- package/packages/dd-trace/src/appsec/sdk/track_event.js +9 -0
- package/packages/dd-trace/src/carrier.js +356 -0
- package/packages/dd-trace/src/ci-visibility/coverage-report-discovery.js +46 -14
- package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +89 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +27 -13
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +17 -0
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +21 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +22 -7
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +9 -14
- package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +21 -5
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +1 -1
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +5 -1
- package/packages/dd-trace/src/config/generated-config-types.d.ts +5 -0
- package/packages/dd-trace/src/config/helper.js +2 -0
- package/packages/dd-trace/src/config/index.js +16 -5
- package/packages/dd-trace/src/config/remote_config.js +1 -1
- package/packages/dd-trace/src/config/supported-configurations.json +18 -0
- package/packages/dd-trace/src/datastreams/context.js +6 -1
- package/packages/dd-trace/src/datastreams/manager.js +5 -1
- package/packages/dd-trace/src/datastreams/pathway.js +23 -22
- package/packages/dd-trace/src/datastreams/processor.js +3 -2
- package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -1
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +0 -1
- package/packages/dd-trace/src/guardrails/apply-pm2-env.js +16 -0
- package/packages/dd-trace/src/guardrails/log.js +1 -10
- package/packages/dd-trace/src/llmobs/constants/tags.js +5 -0
- package/packages/dd-trace/src/llmobs/eval-metric.js +249 -0
- package/packages/dd-trace/src/llmobs/experiments/index.js +33 -25
- package/packages/dd-trace/src/llmobs/experiments/util.js +4 -2
- package/packages/dd-trace/src/llmobs/index.js +34 -2
- package/packages/dd-trace/src/llmobs/noop.js +2 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +5 -5
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +149 -68
- package/packages/dd-trace/src/llmobs/span_processor.js +16 -0
- package/packages/dd-trace/src/llmobs/tagger.js +96 -0
- package/packages/dd-trace/src/llmobs/telemetry.js +18 -0
- package/packages/dd-trace/src/llmobs/util.js +78 -0
- package/packages/dd-trace/src/llmobs/writers/base.js +3 -0
- package/packages/dd-trace/src/llmobs/writers/util.js +2 -0
- package/packages/dd-trace/src/log/channels.js +1 -9
- package/packages/dd-trace/src/log/levels.js +12 -0
- package/packages/dd-trace/src/openfeature/writers/exposures.js +1 -1
- package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
- package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/meter.js +8 -4
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -1
- package/packages/dd-trace/src/opentelemetry/span.js +4 -0
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +126 -120
- package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +4 -8
- package/packages/dd-trace/src/plugin_manager.js +2 -0
- package/packages/dd-trace/src/plugins/ci_plugin.js +21 -5
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/util/ci.js +6 -0
- package/packages/dd-trace/src/plugins/util/git.js +6 -4
- package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +2 -2
- package/packages/dd-trace/src/plugins/util/ip_extractor.js +1 -1
- package/packages/{datadog-plugin-jest/src/util.js → dd-trace/src/plugins/util/jest.js} +3 -62
- package/packages/dd-trace/src/plugins/util/stacktrace.js +3 -0
- package/packages/dd-trace/src/plugins/util/test.js +397 -74
- package/packages/dd-trace/src/plugins/util/url.js +1 -1
- package/packages/dd-trace/src/plugins/util/web.js +76 -3
- package/packages/dd-trace/src/profiler.js +1 -1
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/events.js +2 -2
- package/packages/dd-trace/src/proxy.js +1 -0
- package/packages/dd-trace/src/ritm.js +5 -0
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +4 -2
- package/packages/dd-trace/src/sampling_rule.js +4 -2
- package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +1 -1
- package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +1 -1
- package/packages/dd-trace/src/telemetry/logs/index.js +3 -0
- package/packages/dd-trace/src/telemetry/telemetry.js +1 -1
- package/vendor/dist/pprof-format/index.js +1 -1
- package/version.js +10 -8
- /package/packages/dd-trace/src/appsec/{blocked_templates.js → blocking/templates.js} +0 -0
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/** @typedef {Record<string, unknown>} Carrier */
|
|
4
|
+
/** @typedef {string | Buffer} PathwayValue */
|
|
5
|
+
|
|
6
|
+
const FIELD_READ = 1
|
|
7
|
+
const FIELD_WRITE = 2
|
|
8
|
+
const FIELD_HAS = 4
|
|
9
|
+
const FIELD_DELETE = 8
|
|
10
|
+
const FIELD_NAME_LENGTH = 16
|
|
11
|
+
|
|
12
|
+
/** @type {Record<string, unknown>} */
|
|
13
|
+
const carrierOperations = {}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {object} CarrierCapability
|
|
17
|
+
* @property {unknown} [read]
|
|
18
|
+
* @property {unknown} [write]
|
|
19
|
+
* @property {unknown} [has]
|
|
20
|
+
* @property {unknown} [delete]
|
|
21
|
+
* @property {unknown} [nameLength]
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @template Value
|
|
26
|
+
* @typedef {object} CarrierField
|
|
27
|
+
* @property {(carrier: Carrier) => Value | undefined} read
|
|
28
|
+
* @property {(carrier: Carrier, value: Value) => void} write
|
|
29
|
+
* @property {(carrier: Carrier) => boolean} has
|
|
30
|
+
* @property {(carrier: Carrier) => void} delete
|
|
31
|
+
* @property {(carrier: Carrier, target: Carrier) => void} copy
|
|
32
|
+
* @property {number} nameLength
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @template {CarrierCapability} Capability
|
|
37
|
+
* @param {string} name
|
|
38
|
+
* @param {number} operations
|
|
39
|
+
* @param {Capability} capability
|
|
40
|
+
* @returns {Capability}
|
|
41
|
+
*/
|
|
42
|
+
function defineCapability (name, operations, capability) {
|
|
43
|
+
const suffix = name[0].toUpperCase() + name.slice(1)
|
|
44
|
+
if (operations & FIELD_READ) carrierOperations[`read${suffix}`] = capability.read
|
|
45
|
+
if (operations & FIELD_WRITE) carrierOperations[`write${suffix}`] = capability.write
|
|
46
|
+
if (operations & FIELD_HAS) carrierOperations[`has${suffix}`] = capability.has
|
|
47
|
+
if (operations & FIELD_DELETE) carrierOperations[`delete${suffix}`] = capability.delete
|
|
48
|
+
if (operations & FIELD_NAME_LENGTH) carrierOperations[`${name}NameLength`] = capability.nameLength
|
|
49
|
+
return capability
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @template Value
|
|
54
|
+
* @param {string} fieldName
|
|
55
|
+
* @param {string} headerName
|
|
56
|
+
* @param {(value: unknown) => Value | undefined} resolve
|
|
57
|
+
* @param {number} operations
|
|
58
|
+
* @returns {CarrierField<Value>}
|
|
59
|
+
*/
|
|
60
|
+
function defineField (fieldName, headerName, resolve, operations) {
|
|
61
|
+
return defineCapability(fieldName, operations, {
|
|
62
|
+
/**
|
|
63
|
+
* @param {Carrier} carrier
|
|
64
|
+
* @returns {Value | undefined}
|
|
65
|
+
*/
|
|
66
|
+
read (carrier) {
|
|
67
|
+
return resolve(carrier[headerName])
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @param {Carrier} carrier
|
|
72
|
+
* @param {Value} value
|
|
73
|
+
* @returns {void}
|
|
74
|
+
*/
|
|
75
|
+
write (carrier, value) {
|
|
76
|
+
carrier[headerName] = value
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @param {Carrier} carrier
|
|
81
|
+
* @returns {boolean}
|
|
82
|
+
*/
|
|
83
|
+
has (carrier) {
|
|
84
|
+
return headerName in carrier
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @param {Carrier} carrier
|
|
89
|
+
* @returns {void}
|
|
90
|
+
*/
|
|
91
|
+
delete (carrier) {
|
|
92
|
+
delete carrier[headerName]
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @param {Carrier} carrier
|
|
97
|
+
* @param {Carrier} target
|
|
98
|
+
* @returns {void}
|
|
99
|
+
*/
|
|
100
|
+
copy (carrier, target) {
|
|
101
|
+
if (Object.hasOwn(carrier, headerName)) target[headerName] = carrier[headerName]
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
nameLength: headerName.length,
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Skipping non-strings keeps a Symbol or a throwing `toString` from aborting
|
|
110
|
+
* extraction, which discards the whole context rather than one field.
|
|
111
|
+
*
|
|
112
|
+
* @param {unknown} value
|
|
113
|
+
* @returns {string | undefined}
|
|
114
|
+
*/
|
|
115
|
+
function readListText (value) {
|
|
116
|
+
if (typeof value === 'string') return value
|
|
117
|
+
if (!Array.isArray(value)) return
|
|
118
|
+
|
|
119
|
+
let joined = ''
|
|
120
|
+
let first = true
|
|
121
|
+
|
|
122
|
+
for (const item of value) {
|
|
123
|
+
if (typeof item !== 'string') continue
|
|
124
|
+
if (first) {
|
|
125
|
+
joined = item
|
|
126
|
+
first = false
|
|
127
|
+
} else {
|
|
128
|
+
joined += `,${item}`
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return joined
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* @param {unknown} value
|
|
137
|
+
* @returns {string | undefined}
|
|
138
|
+
*/
|
|
139
|
+
function readLastText (value) {
|
|
140
|
+
if (typeof value === 'string') return value
|
|
141
|
+
if (!Array.isArray(value)) return
|
|
142
|
+
|
|
143
|
+
let result
|
|
144
|
+
for (let i = value.length - 1; i >= 0; i--) {
|
|
145
|
+
if (typeof value[i] === 'string') {
|
|
146
|
+
result = value[i]
|
|
147
|
+
break
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return result
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @param {unknown} value
|
|
155
|
+
* @returns {string | undefined}
|
|
156
|
+
*/
|
|
157
|
+
function readUniqueText (value) {
|
|
158
|
+
let result
|
|
159
|
+
if (typeof value === 'string') {
|
|
160
|
+
result = value
|
|
161
|
+
} else if (Array.isArray(value) && value.length === 1 && typeof value[0] === 'string') {
|
|
162
|
+
result = value[0]
|
|
163
|
+
}
|
|
164
|
+
return result
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* @param {unknown} value
|
|
169
|
+
* @returns {PathwayValue | undefined}
|
|
170
|
+
*/
|
|
171
|
+
function readLastPathway (value) {
|
|
172
|
+
if (typeof value === 'string' || Buffer.isBuffer(value)) return value
|
|
173
|
+
if (!Array.isArray(value)) return
|
|
174
|
+
|
|
175
|
+
let result
|
|
176
|
+
for (let i = value.length - 1; i >= 0; i--) {
|
|
177
|
+
const item = value[i]
|
|
178
|
+
if (typeof item === 'string' || Buffer.isBuffer(item)) {
|
|
179
|
+
result = item
|
|
180
|
+
break
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return result
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const datadogTraceId = defineField(
|
|
187
|
+
'datadogTraceId',
|
|
188
|
+
'x-datadog-trace-id',
|
|
189
|
+
readLastText,
|
|
190
|
+
FIELD_READ | FIELD_WRITE
|
|
191
|
+
)
|
|
192
|
+
const datadogParentId = defineField(
|
|
193
|
+
'datadogParentId',
|
|
194
|
+
'x-datadog-parent-id',
|
|
195
|
+
readLastText,
|
|
196
|
+
FIELD_READ | FIELD_WRITE | FIELD_DELETE
|
|
197
|
+
)
|
|
198
|
+
const datadogOrigin = defineField(
|
|
199
|
+
'datadogOrigin',
|
|
200
|
+
'x-datadog-origin',
|
|
201
|
+
readLastText,
|
|
202
|
+
FIELD_READ | FIELD_WRITE
|
|
203
|
+
)
|
|
204
|
+
const datadogSamplingPriority = defineField(
|
|
205
|
+
'datadogSamplingPriority',
|
|
206
|
+
'x-datadog-sampling-priority',
|
|
207
|
+
readLastText,
|
|
208
|
+
FIELD_READ | FIELD_WRITE
|
|
209
|
+
)
|
|
210
|
+
defineField('datadogTags', 'x-datadog-tags', readListText, FIELD_READ | FIELD_WRITE)
|
|
211
|
+
defineField('baggage', 'baggage', readListText, FIELD_READ | FIELD_WRITE)
|
|
212
|
+
const b3TraceId = defineField('b3TraceId', 'x-b3-traceid', readLastText, FIELD_READ | FIELD_WRITE)
|
|
213
|
+
const b3SpanId = defineField('b3SpanId', 'x-b3-spanid', readLastText, FIELD_READ | FIELD_WRITE)
|
|
214
|
+
const b3ParentId = defineField('b3ParentId', 'x-b3-parentspanid', readLastText, FIELD_WRITE)
|
|
215
|
+
const b3Sampled = defineField('b3Sampled', 'x-b3-sampled', readLastText, FIELD_READ | FIELD_WRITE)
|
|
216
|
+
const b3Flags = defineField('b3Flags', 'x-b3-flags', readLastText, FIELD_READ | FIELD_WRITE)
|
|
217
|
+
const b3 = defineField('b3', 'b3', readLastText, FIELD_READ | FIELD_WRITE)
|
|
218
|
+
defineField('sqsd', 'x-aws-sqsd-attr-_datadog', readLastText, FIELD_READ)
|
|
219
|
+
const traceparent = defineField('traceparent', 'traceparent', readUniqueText, FIELD_READ | FIELD_WRITE)
|
|
220
|
+
const tracestate = defineField('tracestate', 'tracestate', readListText, FIELD_READ | FIELD_WRITE)
|
|
221
|
+
const dsmBase64 = defineField(
|
|
222
|
+
'dsmBase64',
|
|
223
|
+
'dd-pathway-ctx-base64',
|
|
224
|
+
readLastPathway,
|
|
225
|
+
FIELD_READ | FIELD_WRITE | FIELD_HAS | FIELD_NAME_LENGTH
|
|
226
|
+
)
|
|
227
|
+
const dsmBinary = defineField('dsmBinary', 'dd-pathway-ctx', readLastPathway, FIELD_READ | FIELD_HAS)
|
|
228
|
+
|
|
229
|
+
const legacyBaggagePrefix = 'ot-baggage-'
|
|
230
|
+
// RFC 7230 `token`, compatible with Node.js header-name validation.
|
|
231
|
+
const httpHeaderNameExpr = /^[0-9A-Za-z!#$%&'*+\-.^_`|~]+$/
|
|
232
|
+
|
|
233
|
+
defineCapability('legacyBaggage', FIELD_READ | FIELD_WRITE, {
|
|
234
|
+
/**
|
|
235
|
+
* @param {Record<string, string> | undefined} carrier
|
|
236
|
+
* @param {string} key
|
|
237
|
+
* @param {string} value
|
|
238
|
+
* @returns {Record<string, string> | undefined}
|
|
239
|
+
*/
|
|
240
|
+
write (carrier, key, value) {
|
|
241
|
+
const name = legacyBaggagePrefix + key
|
|
242
|
+
if (!httpHeaderNameExpr.test(name)) return
|
|
243
|
+
|
|
244
|
+
carrier ??= {}
|
|
245
|
+
carrier[name] = value
|
|
246
|
+
return carrier
|
|
247
|
+
},
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* @param {Carrier} carrier
|
|
251
|
+
* @param {Record<string, string>} target
|
|
252
|
+
* @returns {void}
|
|
253
|
+
*/
|
|
254
|
+
read (carrier, target) {
|
|
255
|
+
for (const name of Object.keys(carrier)) {
|
|
256
|
+
if (!name.startsWith(legacyBaggagePrefix)) continue
|
|
257
|
+
const key = name.slice(legacyBaggagePrefix.length)
|
|
258
|
+
if (!key) continue
|
|
259
|
+
const value = readLastText(carrier[name])
|
|
260
|
+
if (value !== undefined) target[key] = value
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
const textMapLogFields = [
|
|
266
|
+
datadogTraceId,
|
|
267
|
+
datadogParentId,
|
|
268
|
+
datadogSamplingPriority,
|
|
269
|
+
datadogOrigin,
|
|
270
|
+
b3TraceId,
|
|
271
|
+
b3SpanId,
|
|
272
|
+
b3ParentId,
|
|
273
|
+
b3Sampled,
|
|
274
|
+
b3Flags,
|
|
275
|
+
b3,
|
|
276
|
+
traceparent,
|
|
277
|
+
tracestate,
|
|
278
|
+
]
|
|
279
|
+
const dsmLogFields = [dsmBinary, dsmBase64]
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* @param {Carrier} carrier
|
|
283
|
+
* @param {Array<Pick<CarrierField<unknown>, 'copy'>>} selectedFields
|
|
284
|
+
* @returns {Carrier}
|
|
285
|
+
*/
|
|
286
|
+
function pick (carrier, selectedFields) {
|
|
287
|
+
/** @type {Carrier} */
|
|
288
|
+
const result = {}
|
|
289
|
+
for (const field of selectedFields) field.copy(carrier, result)
|
|
290
|
+
return result
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* @param {Carrier} carrier
|
|
295
|
+
* @returns {Carrier}
|
|
296
|
+
*/
|
|
297
|
+
function pickTextMap (carrier) {
|
|
298
|
+
return pick(carrier, textMapLogFields)
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* @param {Carrier} carrier
|
|
303
|
+
* @returns {Carrier}
|
|
304
|
+
*/
|
|
305
|
+
function pickDsm (carrier) {
|
|
306
|
+
return pick(carrier, dsmLogFields)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* @typedef {object} CarrierOperations
|
|
311
|
+
* @property {typeof datadogParentId.delete} deleteDatadogParentId
|
|
312
|
+
* @property {typeof dsmBase64.nameLength} dsmBase64NameLength
|
|
313
|
+
* @property {typeof dsmBase64.has} hasDsmBase64
|
|
314
|
+
* @property {typeof dsmBinary.has} hasDsmBinary
|
|
315
|
+
* @property {typeof pickDsm} pickDsm
|
|
316
|
+
* @property {typeof pickTextMap} pickTextMap
|
|
317
|
+
* @property {(carrier: Carrier) => string | undefined} readBaggage
|
|
318
|
+
* @property {typeof b3.read} readB3
|
|
319
|
+
* @property {typeof b3Flags.read} readB3Flags
|
|
320
|
+
* @property {typeof b3Sampled.read} readB3Sampled
|
|
321
|
+
* @property {typeof b3SpanId.read} readB3SpanId
|
|
322
|
+
* @property {typeof b3TraceId.read} readB3TraceId
|
|
323
|
+
* @property {typeof datadogOrigin.read} readDatadogOrigin
|
|
324
|
+
* @property {typeof datadogParentId.read} readDatadogParentId
|
|
325
|
+
* @property {typeof datadogSamplingPriority.read} readDatadogSamplingPriority
|
|
326
|
+
* @property {(carrier: Carrier) => string | undefined} readDatadogTags
|
|
327
|
+
* @property {typeof datadogTraceId.read} readDatadogTraceId
|
|
328
|
+
* @property {typeof dsmBase64.read} readDsmBase64
|
|
329
|
+
* @property {typeof dsmBinary.read} readDsmBinary
|
|
330
|
+
* @property {(carrier: Carrier, target: Record<string, string>) => void} readLegacyBaggage
|
|
331
|
+
* @property {(carrier: Carrier) => string | undefined} readSqsd
|
|
332
|
+
* @property {typeof traceparent.read} readTraceparent
|
|
333
|
+
* @property {typeof tracestate.read} readTracestate
|
|
334
|
+
* @property {(carrier: Carrier, value: string) => void} writeBaggage
|
|
335
|
+
* @property {typeof b3.write} writeB3
|
|
336
|
+
* @property {typeof b3Flags.write} writeB3Flags
|
|
337
|
+
* @property {typeof b3ParentId.write} writeB3ParentId
|
|
338
|
+
* @property {typeof b3Sampled.write} writeB3Sampled
|
|
339
|
+
* @property {typeof b3SpanId.write} writeB3SpanId
|
|
340
|
+
* @property {typeof b3TraceId.write} writeB3TraceId
|
|
341
|
+
* @property {typeof datadogOrigin.write} writeDatadogOrigin
|
|
342
|
+
* @property {typeof datadogParentId.write} writeDatadogParentId
|
|
343
|
+
* @property {typeof datadogSamplingPriority.write} writeDatadogSamplingPriority
|
|
344
|
+
* @property {(carrier: Carrier, value: string) => void} writeDatadogTags
|
|
345
|
+
* @property {typeof datadogTraceId.write} writeDatadogTraceId
|
|
346
|
+
* @property {typeof dsmBase64.write} writeDsmBase64
|
|
347
|
+
* @property {(carrier: Record<string, string> | undefined, key: string, value: string) =>
|
|
348
|
+
* Record<string, string> | undefined} writeLegacyBaggage
|
|
349
|
+
* @property {typeof traceparent.write} writeTraceparent
|
|
350
|
+
* @property {typeof tracestate.write} writeTracestate
|
|
351
|
+
*/
|
|
352
|
+
|
|
353
|
+
carrierOperations.pickDsm = pickDsm
|
|
354
|
+
carrierOperations.pickTextMap = pickTextMap
|
|
355
|
+
|
|
356
|
+
module.exports = /** @type {CarrierOperations} */ (carrierOperations)
|
|
@@ -5,6 +5,8 @@ const path = require('node:path')
|
|
|
5
5
|
|
|
6
6
|
const log = require('../log')
|
|
7
7
|
|
|
8
|
+
const BIGINT_LSTAT_OPTIONS = { bigint: true, throwIfNoEntry: false }
|
|
9
|
+
|
|
8
10
|
/**
|
|
9
11
|
* Coverage report file patterns to search for
|
|
10
12
|
* Each entry contains the relative path from root and the format identifier
|
|
@@ -38,7 +40,7 @@ const COVERAGE_REPORT_PATTERNS = [
|
|
|
38
40
|
/**
|
|
39
41
|
* Discovers code coverage report files in the given root directory
|
|
40
42
|
* @param {string} rootDir - The root directory to search for coverage reports
|
|
41
|
-
* @returns {Array<{filePath: string, format: string}>}
|
|
43
|
+
* @returns {Array<{filePath: string, fileDevice: bigint, fileInode: bigint, format: string}>}
|
|
42
44
|
*/
|
|
43
45
|
function discoverCoverageReports (rootDir) {
|
|
44
46
|
if (!rootDir) {
|
|
@@ -46,27 +48,57 @@ function discoverCoverageReports (rootDir) {
|
|
|
46
48
|
return []
|
|
47
49
|
}
|
|
48
50
|
|
|
51
|
+
let resolvedRoot
|
|
52
|
+
try {
|
|
53
|
+
const unresolvedRoot = path.resolve(rootDir)
|
|
54
|
+
const rootStats = fs.lstatSync(unresolvedRoot, BIGINT_LSTAT_OPTIONS)
|
|
55
|
+
if (rootStats?.isSymbolicLink() || !rootStats?.isDirectory()) {
|
|
56
|
+
log.debug('Coverage report root is not a regular directory: %s', unresolvedRoot)
|
|
57
|
+
return []
|
|
58
|
+
}
|
|
59
|
+
resolvedRoot = fs.realpathSync(unresolvedRoot)
|
|
60
|
+
const resolvedRootStats = fs.lstatSync(resolvedRoot, BIGINT_LSTAT_OPTIONS)
|
|
61
|
+
if (!resolvedRootStats || resolvedRootStats.dev !== rootStats.dev || resolvedRootStats.ino !== rootStats.ino) {
|
|
62
|
+
log.debug('Coverage report root changed while resolving it: %s', unresolvedRoot)
|
|
63
|
+
return []
|
|
64
|
+
}
|
|
65
|
+
} catch (error) {
|
|
66
|
+
log.debug('Error checking coverage report root %s: %s', rootDir, error.message)
|
|
67
|
+
return []
|
|
68
|
+
}
|
|
69
|
+
|
|
49
70
|
const discoveredReports = []
|
|
50
71
|
|
|
51
72
|
for (const pattern of COVERAGE_REPORT_PATTERNS) {
|
|
52
|
-
|
|
73
|
+
let currentPath = resolvedRoot
|
|
53
74
|
|
|
54
75
|
try {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (stats.
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
76
|
+
let stats
|
|
77
|
+
for (const pathSegment of pattern.path.split('/')) {
|
|
78
|
+
currentPath = path.join(currentPath, pathSegment)
|
|
79
|
+
stats = fs.lstatSync(currentPath, BIGINT_LSTAT_OPTIONS)
|
|
80
|
+
if (!stats || stats.isSymbolicLink()) break
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// A hard link can name a file outside the root without changing its real path.
|
|
84
|
+
if (stats?.isFile() && stats.nlink === 1n) {
|
|
85
|
+
const resolvedPath = fs.realpathSync(currentPath)
|
|
86
|
+
const pathFromRoot = path.relative(resolvedRoot, resolvedPath)
|
|
87
|
+
if (pathFromRoot === '..' || pathFromRoot.startsWith(`..${path.sep}`) || path.isAbsolute(pathFromRoot)) {
|
|
88
|
+
log.debug('Coverage report resolved outside the root directory: %s', currentPath)
|
|
89
|
+
continue
|
|
65
90
|
}
|
|
91
|
+
discoveredReports.push({
|
|
92
|
+
filePath: resolvedPath,
|
|
93
|
+
fileDevice: stats.dev,
|
|
94
|
+
fileInode: stats.ino,
|
|
95
|
+
format: pattern.format,
|
|
96
|
+
})
|
|
97
|
+
log.debug('Found coverage report: %s (format: %s)', resolvedPath, pattern.format)
|
|
66
98
|
}
|
|
67
|
-
} catch (
|
|
99
|
+
} catch (error) {
|
|
68
100
|
// Log but don't fail if we can't access a file
|
|
69
|
-
log.debug('Error checking coverage report path %s: %s',
|
|
101
|
+
log.debug('Error checking coverage report path %s: %s', currentPath, error.message)
|
|
70
102
|
}
|
|
71
103
|
}
|
|
72
104
|
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const EARLY_FLAKE_DETECTION_RETRY_THRESHOLDS = [
|
|
4
|
+
{ limitMs: 5000, key: '5s' },
|
|
5
|
+
{ limitMs: 10_000, key: '10s' },
|
|
6
|
+
{ limitMs: 30_000, key: '30s' },
|
|
7
|
+
{ limitMs: 300_000, key: '5m' },
|
|
8
|
+
]
|
|
9
|
+
|
|
10
|
+
// A bucket the settings validator accepts but this module ignores silently loses its retries.
|
|
11
|
+
const EARLY_FLAKE_DETECTION_RETRY_BUCKETS =
|
|
12
|
+
Object.freeze(EARLY_FLAKE_DETECTION_RETRY_THRESHOLDS.map(({ key }) => key))
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {object} EfdDurationRetryCount
|
|
16
|
+
* @property {number} durationLimitMs
|
|
17
|
+
* @property {number} retryCount
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @typedef {object} EfdRetryPolicy
|
|
22
|
+
* @property {readonly EfdDurationRetryCount[]} durationRetryCounts
|
|
23
|
+
* @property {number} schedulingRetryCount
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param {number} durationMs
|
|
28
|
+
* @param {EfdRetryPolicy} retryPolicy
|
|
29
|
+
* @returns {number}
|
|
30
|
+
*/
|
|
31
|
+
function getEfdRetryCountForDuration (durationMs, retryPolicy) {
|
|
32
|
+
for (const { durationLimitMs, retryCount } of retryPolicy.durationRetryCounts) {
|
|
33
|
+
if (durationMs < durationLimitMs) {
|
|
34
|
+
return retryCount
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return 0
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @param {Record<string, unknown> | undefined} retriesByDuration
|
|
42
|
+
* @returns {EfdRetryPolicy}
|
|
43
|
+
*/
|
|
44
|
+
function createEfdRetryPolicy (retriesByDuration = {}) {
|
|
45
|
+
const durationRetryCounts = []
|
|
46
|
+
let schedulingRetryCount = 0
|
|
47
|
+
for (const { limitMs: durationLimitMs, key } of EARLY_FLAKE_DETECTION_RETRY_THRESHOLDS) {
|
|
48
|
+
const configuredRetryCount = retriesByDuration[key]
|
|
49
|
+
const retryCount = Number.isSafeInteger(configuredRetryCount) && configuredRetryCount >= 0
|
|
50
|
+
? configuredRetryCount
|
|
51
|
+
: 0
|
|
52
|
+
durationRetryCounts.push(Object.freeze({ durationLimitMs, retryCount }))
|
|
53
|
+
if (retryCount > schedulingRetryCount) {
|
|
54
|
+
schedulingRetryCount = retryCount
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return Object.freeze({
|
|
58
|
+
durationRetryCounts: Object.freeze(durationRetryCounts),
|
|
59
|
+
schedulingRetryCount,
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @param {EfdRetryPolicy | undefined} retryPolicy
|
|
65
|
+
* @returns {boolean}
|
|
66
|
+
*/
|
|
67
|
+
function hasEfdRetries (retryPolicy) {
|
|
68
|
+
return (retryPolicy?.schedulingRetryCount ?? 0) > 0
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @param {number} retryIndex
|
|
73
|
+
* @param {number | undefined} retryCount
|
|
74
|
+
* @returns {boolean}
|
|
75
|
+
*/
|
|
76
|
+
function shouldSkipEfdRetry (retryIndex, retryCount) {
|
|
77
|
+
return retryCount !== undefined && retryIndex > retryCount
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const EMPTY_EFD_RETRY_POLICY = createEfdRetryPolicy()
|
|
81
|
+
|
|
82
|
+
module.exports = {
|
|
83
|
+
EARLY_FLAKE_DETECTION_RETRY_BUCKETS,
|
|
84
|
+
EMPTY_EFD_RETRY_POLICY,
|
|
85
|
+
createEfdRetryPolicy,
|
|
86
|
+
getEfdRetryCountForDuration,
|
|
87
|
+
hasEfdRetries,
|
|
88
|
+
shouldSkipEfdRetry,
|
|
89
|
+
}
|
|
@@ -4,6 +4,7 @@ const { hostname: getHostname } = require('node:os')
|
|
|
4
4
|
const URL = require('url').URL
|
|
5
5
|
|
|
6
6
|
const { version: tracerVersion } = require('../../../../../package.json')
|
|
7
|
+
const { EMPTY_EFD_RETRY_POLICY, createEfdRetryPolicy } = require('../efd-retry-policy')
|
|
7
8
|
const { getLibraryConfiguration: getLibraryConfigurationRequest } = require('../requests/get-library-configuration')
|
|
8
9
|
const { getSkippableSuites: getSkippableSuitesRequest } = require('../intelligent-test-runner/get-skippable-suites')
|
|
9
10
|
const { getKnownTests: getKnownTestsRequest } = require('../early-flake-detection/get-known-tests')
|
|
@@ -23,6 +24,18 @@ const { sendGitMetadata: sendGitMetadataRequest } = require('./git/git_metadata'
|
|
|
23
24
|
const hostname = getHostname()
|
|
24
25
|
const EMPTY_SETTINGS = Object.freeze({})
|
|
25
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Test session identity sent with every request. Fields are optional because the CI provider,
|
|
29
|
+
* the git repository or the runtime may not expose them.
|
|
30
|
+
*
|
|
31
|
+
* @typedef {{
|
|
32
|
+
* repositoryUrl?: string, sha?: string, branch?: string, tag?: string, testLevel?: string,
|
|
33
|
+
* osVersion?: string, osPlatform?: string, osArchitecture?: string,
|
|
34
|
+
* runtimeName?: string, runtimeVersion?: string, commitMessage?: string,
|
|
35
|
+
* pullRequestBaseSha?: string, commitHeadSha?: string, commitHeadMessage?: string,
|
|
36
|
+
* }} TestConfiguration
|
|
37
|
+
*/
|
|
38
|
+
|
|
26
39
|
function getTestConfigurationTags (tags) {
|
|
27
40
|
if (!tags) {
|
|
28
41
|
return {}
|
|
@@ -190,6 +203,7 @@ class CiVisibilityExporter extends BufferingExporter {
|
|
|
190
203
|
const cachedSkippableSuites = this._testOptimizationHttpCache.readSkippableSuites({
|
|
191
204
|
testLevel: requestConfiguration.testLevel,
|
|
192
205
|
isCoverageReportUploadEnabled: requestConfiguration.isCoverageReportUploadEnabled,
|
|
206
|
+
isLineCoverageSupported: requestConfiguration.isLineCoverageSupported,
|
|
193
207
|
})
|
|
194
208
|
if (cachedSkippableSuites !== CACHE_MISS) {
|
|
195
209
|
const { skippableSuites, correlationId, coverage } = cachedSkippableSuites
|
|
@@ -238,6 +252,10 @@ class CiVisibilityExporter extends BufferingExporter {
|
|
|
238
252
|
/**
|
|
239
253
|
* We can't request library configuration until we know whether we can use the
|
|
240
254
|
* CI Visibility Protocol, hence the this._canUseCiVisProtocol promise.
|
|
255
|
+
*
|
|
256
|
+
* @param {TestConfiguration} testConfiguration
|
|
257
|
+
* @param {(error: Error | null, libraryConfig?: Readonly<Record<string, unknown>>) => void} callback
|
|
258
|
+
* @returns {void}
|
|
241
259
|
*/
|
|
242
260
|
getLibraryConfiguration (testConfiguration, callback) {
|
|
243
261
|
const { repositoryUrl } = testConfiguration
|
|
@@ -321,21 +339,14 @@ class CiVisibilityExporter extends BufferingExporter {
|
|
|
321
339
|
DD_TEST_MANAGEMENT_ATTEMPT_TO_FIX_RETRIES: configuredAttemptToFixRetries = 0,
|
|
322
340
|
DD_TEST_MANAGEMENT_ENABLED: isTestManagementAllowed,
|
|
323
341
|
} = testOptimization
|
|
324
|
-
const
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
? Object.freeze({
|
|
342
|
+
const earlyFlakeDetectionRetryPolicy = earlyFlakeDetectionRetryCount === undefined
|
|
343
|
+
? remoteConfiguration.earlyFlakeDetectionRetryPolicy ?? EMPTY_EFD_RETRY_POLICY
|
|
344
|
+
: createEfdRetryPolicy({
|
|
328
345
|
'5s': earlyFlakeDetectionRetryCount,
|
|
329
346
|
'10s': earlyFlakeDetectionRetryCount,
|
|
330
347
|
'30s': earlyFlakeDetectionRetryCount,
|
|
331
348
|
'5m': earlyFlakeDetectionRetryCount,
|
|
332
349
|
})
|
|
333
|
-
: Object.isFrozen(configuredSlowTestRetries)
|
|
334
|
-
? configuredSlowTestRetries
|
|
335
|
-
: Object.freeze({ ...configuredSlowTestRetries })
|
|
336
|
-
const earlyFlakeDetectionNumRetries = hasEarlyFlakeDetectionRetryCount
|
|
337
|
-
? earlyFlakeDetectionRetryCount
|
|
338
|
-
: remoteConfiguration.earlyFlakeDetectionNumRetries ?? 0
|
|
339
350
|
const testManagementAttemptToFixRetries =
|
|
340
351
|
remoteConfiguration.testManagementAttemptToFixRetries ?? configuredAttemptToFixRetries
|
|
341
352
|
|
|
@@ -346,8 +357,7 @@ class CiVisibilityExporter extends BufferingExporter {
|
|
|
346
357
|
requireGit: remoteConfiguration.requireGit === true,
|
|
347
358
|
isEarlyFlakeDetectionEnabled:
|
|
348
359
|
remoteConfiguration.isEarlyFlakeDetectionEnabled === true && isEarlyFlakeDetectionAllowed === true,
|
|
349
|
-
|
|
350
|
-
earlyFlakeDetectionSlowTestRetries,
|
|
360
|
+
earlyFlakeDetectionRetryPolicy,
|
|
351
361
|
earlyFlakeDetectionFaultyThreshold: remoteConfiguration.earlyFlakeDetectionFaultyThreshold ?? 30,
|
|
352
362
|
isFlakyTestRetriesEnabled:
|
|
353
363
|
remoteConfiguration.isFlakyTestRetriesEnabled === true && isFlakyTestRetriesAllowed === true,
|
|
@@ -521,17 +531,21 @@ class CiVisibilityExporter extends BufferingExporter {
|
|
|
521
531
|
* Uploads a single coverage report to the CI intake.
|
|
522
532
|
* @param {object} options - Upload options
|
|
523
533
|
* @param {string} options.filePath - Path to the coverage report file
|
|
534
|
+
* @param {bigint} options.fileDevice - Device containing the discovered report
|
|
535
|
+
* @param {bigint} options.fileInode - Inode of the discovered report
|
|
524
536
|
* @param {string} options.format - Format of the coverage report
|
|
525
537
|
* @param {object} options.testEnvironmentMetadata - Test environment metadata containing git/CI tags
|
|
526
538
|
* @param {(error: Error|null) => void} callback - Callback function
|
|
527
539
|
*/
|
|
528
|
-
uploadCoverageReport ({ filePath, format, testEnvironmentMetadata }, callback) {
|
|
540
|
+
uploadCoverageReport ({ filePath, fileDevice, fileInode, format, testEnvironmentMetadata }, callback) {
|
|
529
541
|
if (!this._codeCoverageReportUrl) {
|
|
530
542
|
return callback(new Error('Coverage report upload URL not configured'))
|
|
531
543
|
}
|
|
532
544
|
|
|
533
545
|
uploadCoverageReportRequest({
|
|
534
546
|
filePath,
|
|
547
|
+
fileDevice,
|
|
548
|
+
fileInode,
|
|
535
549
|
format,
|
|
536
550
|
flags: this._coverageReportFlags,
|
|
537
551
|
testEnvironmentMetadata,
|
|
@@ -32,6 +32,9 @@ const {
|
|
|
32
32
|
TELEMETRY_GIT_REQUESTS_OBJECT_PACKFILES_BYTES,
|
|
33
33
|
} = require('../../../ci-visibility/telemetry')
|
|
34
34
|
|
|
35
|
+
/** @typedef {{ isEvpProxy: boolean, evpProxyPrefix: string }} EvpProxyConfiguration */
|
|
36
|
+
/** @typedef {EvpProxyConfiguration & { url: URL, repositoryUrl: string }} GitUploadTarget */
|
|
37
|
+
|
|
35
38
|
const isValidSha1 = (sha) => /^[0-9a-f]{40}$/.test(sha)
|
|
36
39
|
const isValidSha256 = (sha) => /^[0-9a-f]{64}$/.test(sha)
|
|
37
40
|
|
|
@@ -62,6 +65,10 @@ function getCommonRequestOptions (url) {
|
|
|
62
65
|
* This function posts the SHAs of the commits of the last month
|
|
63
66
|
* The response are the commits for which the backend already has information
|
|
64
67
|
* This response is used to know which commits can be ignored from there on
|
|
68
|
+
*
|
|
69
|
+
* @param {GitUploadTarget & { latestCommits: string[] }} options
|
|
70
|
+
* @param {(error: Error | null, commitsToUpload?: string[]) => void} callback
|
|
71
|
+
* @returns {void}
|
|
65
72
|
*/
|
|
66
73
|
function getCommitsToUpload ({ url, repositoryUrl, latestCommits, isEvpProxy, evpProxyPrefix }, callback) {
|
|
67
74
|
const commonOptions = getCommonRequestOptions(url)
|
|
@@ -127,6 +134,10 @@ function getCommitsToUpload ({ url, repositoryUrl, latestCommits, isEvpProxy, ev
|
|
|
127
134
|
|
|
128
135
|
/**
|
|
129
136
|
* This function uploads a git packfile
|
|
137
|
+
*
|
|
138
|
+
* @param {GitUploadTarget & { packFileToUpload: string, headCommit: string }} options
|
|
139
|
+
* @param {(error: Error | null, uploadSize?: number) => void} callback
|
|
140
|
+
* @returns {void}
|
|
130
141
|
*/
|
|
131
142
|
function uploadPackFile ({ url, isEvpProxy, evpProxyPrefix, packFileToUpload, repositoryUrl, headCommit }, callback) {
|
|
132
143
|
const form = new FormData()
|
|
@@ -245,6 +256,12 @@ function generateAndUploadPackFiles ({
|
|
|
245
256
|
|
|
246
257
|
/**
|
|
247
258
|
* This function uploads git metadata to CI Visibility's backend.
|
|
259
|
+
*
|
|
260
|
+
* @param {URL} url
|
|
261
|
+
* @param {EvpProxyConfiguration} evpProxyConfiguration
|
|
262
|
+
* @param {string | undefined} configRepositoryUrl repository URL from the configuration, if set
|
|
263
|
+
* @param {(error?: Error | null) => void} callback
|
|
264
|
+
* @returns {void}
|
|
248
265
|
*/
|
|
249
266
|
function sendGitMetadata (url, { isEvpProxy, evpProxyPrefix }, configRepositoryUrl, callback) {
|
|
250
267
|
if (!isGitAvailable()) {
|