dd-trace 2.22.2 → 2.23.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/README.md +108 -43
- package/ci/init.js +6 -1
- package/ext/exporters.d.ts +2 -1
- package/ext/exporters.js +2 -1
- package/index.d.ts +6 -1
- package/package.json +2 -2
- package/packages/datadog-instrumentations/src/http/server.js +4 -1
- package/packages/datadog-instrumentations/src/jest.js +26 -9
- package/packages/datadog-instrumentations/src/mocha.js +12 -3
- package/packages/datadog-instrumentations/src/opensearch.js +1 -1
- package/packages/datadog-instrumentations/src/router.js +1 -1
- package/packages/datadog-plugin-cucumber/src/index.js +1 -1
- package/packages/datadog-plugin-http/src/server.js +2 -1
- package/packages/datadog-plugin-jest/src/index.js +21 -25
- package/packages/datadog-plugin-mocha/src/index.js +11 -18
- package/packages/datadog-plugin-mongodb-core/src/index.js +3 -3
- package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +4 -0
- package/packages/dd-trace/src/appsec/index.js +6 -1
- package/packages/dd-trace/src/appsec/remote_config/index.js +23 -2
- package/packages/dd-trace/src/appsec/remote_config/manager.js +1 -1
- package/packages/dd-trace/src/appsec/rule_manager.js +58 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +62 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +8 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +11 -59
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +9 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +196 -0
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +20 -7
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +22 -19
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +22 -18
- package/packages/dd-trace/src/config.js +10 -8
- package/packages/dd-trace/src/exporter.js +3 -0
- package/packages/dd-trace/src/exporters/agent/index.js +4 -0
- package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +82 -0
- package/packages/dd-trace/src/plugin_manager.js +0 -8
- package/packages/dd-trace/src/plugins/ci_plugin.js +9 -50
- package/packages/dd-trace/src/plugins/util/ci.js +35 -2
- package/packages/dd-trace/src/plugins/util/test.js +4 -0
- package/packages/dd-trace/src/plugins/util/web.js +1 -2
- package/packages/dd-trace/src/profiling/exporters/agent.js +4 -0
- package/packages/dd-trace/src/proxy.js +4 -18
- package/packages/dd-trace/src/ritm.js +18 -13
- package/packages/dd-trace/src/telemetry/dependencies.js +11 -1
|
@@ -44,7 +44,7 @@ function getCommonRequestOptions (url) {
|
|
|
44
44
|
* The response are the commits for which the backend already has information
|
|
45
45
|
* This response is used to know which commits can be ignored from there on
|
|
46
46
|
*/
|
|
47
|
-
function getCommitsToExclude ({ url, repositoryUrl }, callback) {
|
|
47
|
+
function getCommitsToExclude ({ url, isEvpProxy, repositoryUrl }, callback) {
|
|
48
48
|
const latestCommits = getLatestCommits()
|
|
49
49
|
const [headCommit] = latestCommits
|
|
50
50
|
|
|
@@ -59,6 +59,12 @@ function getCommitsToExclude ({ url, repositoryUrl }, callback) {
|
|
|
59
59
|
path: '/api/v2/git/repository/search_commits'
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
if (isEvpProxy) {
|
|
63
|
+
options.path = '/evp_proxy/v2/api/v2/git/repository/search_commits'
|
|
64
|
+
options.headers['X-Datadog-EVP-Subdomain'] = 'api'
|
|
65
|
+
delete options.headers['dd-api-key']
|
|
66
|
+
}
|
|
67
|
+
|
|
62
68
|
const localCommitData = JSON.stringify({
|
|
63
69
|
meta: {
|
|
64
70
|
repository_url: repositoryUrl
|
|
@@ -87,7 +93,7 @@ function getCommitsToExclude ({ url, repositoryUrl }, callback) {
|
|
|
87
93
|
/**
|
|
88
94
|
* This function uploads a git packfile
|
|
89
95
|
*/
|
|
90
|
-
function uploadPackFile ({ url, packFileToUpload, repositoryUrl, headCommit }, callback) {
|
|
96
|
+
function uploadPackFile ({ url, isEvpProxy, packFileToUpload, repositoryUrl, headCommit }, callback) {
|
|
91
97
|
const form = new FormData()
|
|
92
98
|
|
|
93
99
|
const pushedSha = JSON.stringify({
|
|
@@ -125,6 +131,13 @@ function uploadPackFile ({ url, packFileToUpload, repositoryUrl, headCommit }, c
|
|
|
125
131
|
...form.getHeaders()
|
|
126
132
|
}
|
|
127
133
|
}
|
|
134
|
+
|
|
135
|
+
if (isEvpProxy) {
|
|
136
|
+
options.path = '/evp_proxy/v2/api/v2/git/repository/packfile'
|
|
137
|
+
options.headers['X-Datadog-EVP-Subdomain'] = 'api'
|
|
138
|
+
delete options.headers['dd-api-key']
|
|
139
|
+
}
|
|
140
|
+
|
|
128
141
|
request(form, options, (err, _, statusCode) => {
|
|
129
142
|
if (err) {
|
|
130
143
|
const error = new Error(`Could not upload packfiles: status code ${statusCode}: ${err.message}`)
|
|
@@ -137,16 +150,14 @@ function uploadPackFile ({ url, packFileToUpload, repositoryUrl, headCommit }, c
|
|
|
137
150
|
/**
|
|
138
151
|
* This function uploads git metadata to CI Visibility's backend.
|
|
139
152
|
*/
|
|
140
|
-
function sendGitMetadata (
|
|
141
|
-
const url = new URL(`https://api.${site}`)
|
|
142
|
-
|
|
153
|
+
function sendGitMetadata (url, isEvpProxy, callback) {
|
|
143
154
|
const repositoryUrl = getRepositoryUrl()
|
|
144
155
|
|
|
145
156
|
if (!repositoryUrl) {
|
|
146
157
|
return callback(new Error('Repository URL is empty'))
|
|
147
158
|
}
|
|
148
159
|
|
|
149
|
-
getCommitsToExclude({ url, repositoryUrl }, (err, commitsToExclude, headCommit) => {
|
|
160
|
+
getCommitsToExclude({ url, repositoryUrl, isEvpProxy }, (err, commitsToExclude, headCommit) => {
|
|
150
161
|
if (err) {
|
|
151
162
|
return callback(err)
|
|
152
163
|
}
|
|
@@ -172,6 +183,7 @@ function sendGitMetadata (site, callback) {
|
|
|
172
183
|
{
|
|
173
184
|
packFileToUpload: packFilesToUpload[packFileIndex++],
|
|
174
185
|
url,
|
|
186
|
+
isEvpProxy,
|
|
175
187
|
repositoryUrl,
|
|
176
188
|
headCommit
|
|
177
189
|
},
|
|
@@ -181,8 +193,9 @@ function sendGitMetadata (site, callback) {
|
|
|
181
193
|
|
|
182
194
|
uploadPackFile(
|
|
183
195
|
{
|
|
184
|
-
url,
|
|
185
196
|
packFileToUpload: packFilesToUpload[packFileIndex++],
|
|
197
|
+
url,
|
|
198
|
+
isEvpProxy,
|
|
186
199
|
repositoryUrl,
|
|
187
200
|
headCommit
|
|
188
201
|
},
|
package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js
CHANGED
|
@@ -3,7 +3,7 @@ const id = require('../../id')
|
|
|
3
3
|
|
|
4
4
|
function getItrConfiguration ({
|
|
5
5
|
url,
|
|
6
|
-
|
|
6
|
+
isEvpProxy,
|
|
7
7
|
env,
|
|
8
8
|
service,
|
|
9
9
|
repositoryUrl,
|
|
@@ -15,28 +15,31 @@ function getItrConfiguration ({
|
|
|
15
15
|
runtimeVersion,
|
|
16
16
|
branch
|
|
17
17
|
}, done) {
|
|
18
|
-
const intakeUrl = url || new URL(`https://api.${site}`)
|
|
19
|
-
|
|
20
|
-
const apiKey = process.env.DATADOG_API_KEY || process.env.DD_API_KEY
|
|
21
|
-
const appKey = process.env.DATADOG_APP_KEY ||
|
|
22
|
-
process.env.DD_APP_KEY ||
|
|
23
|
-
process.env.DATADOG_APPLICATION_KEY ||
|
|
24
|
-
process.env.DD_APPLICATION_KEY
|
|
25
|
-
|
|
26
|
-
if (!apiKey || !appKey) {
|
|
27
|
-
done(new Error('App key or API key undefined'))
|
|
28
|
-
return
|
|
29
|
-
}
|
|
30
|
-
|
|
31
18
|
const options = {
|
|
32
19
|
path: '/api/v2/libraries/tests/services/setting',
|
|
33
20
|
method: 'POST',
|
|
34
21
|
headers: {
|
|
35
|
-
'dd-api-key': apiKey,
|
|
36
|
-
'dd-application-key': appKey,
|
|
37
22
|
'Content-Type': 'application/json'
|
|
38
23
|
},
|
|
39
|
-
url
|
|
24
|
+
url
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (isEvpProxy) {
|
|
28
|
+
options.path = '/evp_proxy/v2/api/v2/libraries/tests/services/setting'
|
|
29
|
+
options.headers['X-Datadog-EVP-Subdomain'] = 'api'
|
|
30
|
+
options.headers['X-Datadog-NeedsAppKey'] = 'true'
|
|
31
|
+
} else {
|
|
32
|
+
const apiKey = process.env.DATADOG_API_KEY || process.env.DD_API_KEY
|
|
33
|
+
const appKey = process.env.DATADOG_APP_KEY ||
|
|
34
|
+
process.env.DD_APP_KEY ||
|
|
35
|
+
process.env.DATADOG_APPLICATION_KEY ||
|
|
36
|
+
process.env.DD_APPLICATION_KEY
|
|
37
|
+
|
|
38
|
+
if (!apiKey || !appKey) {
|
|
39
|
+
return done(new Error('App key or API key undefined'))
|
|
40
|
+
}
|
|
41
|
+
options.headers['dd-api-key'] = apiKey
|
|
42
|
+
options.headers['dd-application-key'] = appKey
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
const data = JSON.stringify({
|
|
@@ -76,8 +79,8 @@ function getItrConfiguration ({
|
|
|
76
79
|
} = JSON.parse(res)
|
|
77
80
|
|
|
78
81
|
done(null, { isCodeCoverageEnabled, isSuitesSkippingEnabled })
|
|
79
|
-
} catch (
|
|
80
|
-
done(
|
|
82
|
+
} catch (err) {
|
|
83
|
+
done(err)
|
|
81
84
|
}
|
|
82
85
|
}
|
|
83
86
|
})
|
|
@@ -2,7 +2,7 @@ const request = require('../../exporters/common/request')
|
|
|
2
2
|
|
|
3
3
|
function getSkippableSuites ({
|
|
4
4
|
url,
|
|
5
|
-
|
|
5
|
+
isEvpProxy,
|
|
6
6
|
env,
|
|
7
7
|
service,
|
|
8
8
|
repositoryUrl,
|
|
@@ -13,28 +13,32 @@ function getSkippableSuites ({
|
|
|
13
13
|
runtimeName,
|
|
14
14
|
runtimeVersion
|
|
15
15
|
}, done) {
|
|
16
|
-
const intakeUrl = url || new URL(`https://api.${site}`)
|
|
17
|
-
|
|
18
|
-
const apiKey = process.env.DATADOG_API_KEY || process.env.DD_API_KEY
|
|
19
|
-
const appKey = process.env.DATADOG_APP_KEY ||
|
|
20
|
-
process.env.DD_APP_KEY ||
|
|
21
|
-
process.env.DATADOG_APPLICATION_KEY ||
|
|
22
|
-
process.env.DD_APPLICATION_KEY
|
|
23
|
-
|
|
24
|
-
if (!apiKey || !appKey) {
|
|
25
|
-
return done(new Error('API key or Application key are undefined.'))
|
|
26
|
-
}
|
|
27
|
-
|
|
28
16
|
const options = {
|
|
29
17
|
path: '/api/v2/ci/tests/skippable',
|
|
30
18
|
method: 'POST',
|
|
31
19
|
headers: {
|
|
32
|
-
'dd-api-key': apiKey,
|
|
33
|
-
'dd-application-key': appKey,
|
|
34
20
|
'Content-Type': 'application/json'
|
|
35
21
|
},
|
|
36
22
|
timeout: 15000,
|
|
37
|
-
url
|
|
23
|
+
url
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (isEvpProxy) {
|
|
27
|
+
options.path = '/evp_proxy/v2/api/v2/ci/tests/skippable'
|
|
28
|
+
options.headers['X-Datadog-EVP-Subdomain'] = 'api'
|
|
29
|
+
options.headers['X-Datadog-NeedsAppKey'] = 'true'
|
|
30
|
+
} else {
|
|
31
|
+
const apiKey = process.env.DATADOG_API_KEY || process.env.DD_API_KEY
|
|
32
|
+
const appKey = process.env.DATADOG_APP_KEY ||
|
|
33
|
+
process.env.DD_APP_KEY ||
|
|
34
|
+
process.env.DATADOG_APPLICATION_KEY ||
|
|
35
|
+
process.env.DD_APPLICATION_KEY
|
|
36
|
+
|
|
37
|
+
if (!apiKey || !appKey) {
|
|
38
|
+
return done(new Error('App key or API key undefined'))
|
|
39
|
+
}
|
|
40
|
+
options.headers['dd-api-key'] = apiKey
|
|
41
|
+
options.headers['dd-application-key'] = appKey
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
const data = JSON.stringify({
|
|
@@ -68,8 +72,8 @@ function getSkippableSuites ({
|
|
|
68
72
|
.filter(({ type }) => type === 'suite')
|
|
69
73
|
.map(({ attributes: { suite } }) => suite)
|
|
70
74
|
done(null, skippableSuites)
|
|
71
|
-
} catch (
|
|
72
|
-
done(
|
|
75
|
+
} catch (err) {
|
|
76
|
+
done(err)
|
|
73
77
|
}
|
|
74
78
|
}
|
|
75
79
|
})
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
const fs = require('fs')
|
|
4
4
|
const os = require('os')
|
|
5
5
|
const URL = require('url').URL
|
|
6
|
-
const path = require('path')
|
|
7
6
|
const log = require('./log')
|
|
8
7
|
const pkg = require('./pkg')
|
|
9
8
|
const coalesce = require('koalas')
|
|
@@ -114,8 +113,11 @@ class Config {
|
|
|
114
113
|
process.env.DD_TRACE_URL,
|
|
115
114
|
null
|
|
116
115
|
)
|
|
116
|
+
const DD_IS_CIVISIBILITY = coalesce(
|
|
117
|
+
options.isCiVisibility,
|
|
118
|
+
false
|
|
119
|
+
)
|
|
117
120
|
const DD_CIVISIBILITY_AGENTLESS_URL = process.env.DD_CIVISIBILITY_AGENTLESS_URL
|
|
118
|
-
const DD_CIVISIBILITY_AGENTLESS_ENABLED = process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED
|
|
119
121
|
|
|
120
122
|
const DD_CIVISIBILITY_ITR_ENABLED = coalesce(
|
|
121
123
|
process.env.DD_CIVISIBILITY_ITR_ENABLED,
|
|
@@ -221,8 +223,7 @@ class Config {
|
|
|
221
223
|
|
|
222
224
|
const DD_APPSEC_RULES = coalesce(
|
|
223
225
|
appsec.rules,
|
|
224
|
-
process.env.DD_APPSEC_RULES
|
|
225
|
-
path.join(__dirname, 'appsec', 'recommended.json')
|
|
226
|
+
process.env.DD_APPSEC_RULES
|
|
226
227
|
)
|
|
227
228
|
const DD_APPSEC_TRACE_RATE_LIMIT = coalesce(
|
|
228
229
|
parseInt(appsec.rateLimit),
|
|
@@ -379,10 +380,11 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
379
380
|
maxContextOperations: DD_IAST_MAX_CONTEXT_OPERATIONS
|
|
380
381
|
}
|
|
381
382
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
this.
|
|
385
|
-
|
|
383
|
+
this.isCiVisibility = isTrue(DD_IS_CIVISIBILITY)
|
|
384
|
+
|
|
385
|
+
this.isIntelligentTestRunnerEnabled = this.isCiVisibility && isTrue(DD_CIVISIBILITY_ITR_ENABLED)
|
|
386
|
+
this.isGitUploadEnabled = this.isCiVisibility &&
|
|
387
|
+
(this.isIntelligentTestRunnerEnabled || isTrue(DD_CIVISIBILITY_GIT_UPLOAD_ENABLED))
|
|
386
388
|
|
|
387
389
|
this.stats = {
|
|
388
390
|
enabled: isTrue(DD_TRACE_STATS_COMPUTATION_ENABLED)
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const AgentExporter = require('./exporters/agent')
|
|
4
4
|
const LogExporter = require('./exporters/log')
|
|
5
5
|
const AgentlessCiVisibilityExporter = require('./ci-visibility/exporters/agentless')
|
|
6
|
+
const AgentProxyCiVisibilityExporter = require('./ci-visibility/exporters/agent-proxy')
|
|
6
7
|
const exporters = require('../../../ext/exporters')
|
|
7
8
|
const fs = require('fs')
|
|
8
9
|
const constants = require('./constants')
|
|
@@ -18,6 +19,8 @@ module.exports = name => {
|
|
|
18
19
|
return AgentExporter
|
|
19
20
|
case exporters.DATADOG:
|
|
20
21
|
return AgentlessCiVisibilityExporter
|
|
22
|
+
case exporters.AGENT_PROXY:
|
|
23
|
+
return AgentProxyCiVisibilityExporter
|
|
21
24
|
default:
|
|
22
25
|
return inAWSLambda && !usingLambdaExtension ? LogExporter : AgentExporter
|
|
23
26
|
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
const { URL, format } = require('url')
|
|
2
|
+
|
|
3
|
+
const request = require('./request')
|
|
4
|
+
|
|
5
|
+
function fetchAgentInfo (url, callback) {
|
|
6
|
+
request('', {
|
|
7
|
+
path: '/info',
|
|
8
|
+
url
|
|
9
|
+
}, (err, res) => {
|
|
10
|
+
if (err) {
|
|
11
|
+
return callback(err)
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
const response = JSON.parse(res)
|
|
15
|
+
return callback(null, response)
|
|
16
|
+
} catch (e) {
|
|
17
|
+
return callback(e)
|
|
18
|
+
}
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Exporter that exposes a way to query /info endpoint from the agent and gives you the response.
|
|
24
|
+
* While this._writer is not initialized, exported traces are stored as is.
|
|
25
|
+
*/
|
|
26
|
+
class AgentInfoExporter {
|
|
27
|
+
constructor (tracerConfig) {
|
|
28
|
+
this._config = tracerConfig
|
|
29
|
+
const { url, hostname, port } = this._config
|
|
30
|
+
this._url = url || new URL(format({
|
|
31
|
+
protocol: 'http:',
|
|
32
|
+
hostname: hostname || 'localhost',
|
|
33
|
+
port
|
|
34
|
+
}))
|
|
35
|
+
this._traceBuffer = []
|
|
36
|
+
this._isInitialized = false
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
getAgentInfo (onReceivedInfo) {
|
|
40
|
+
fetchAgentInfo(this._url, onReceivedInfo)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export (trace) {
|
|
44
|
+
if (!this._isInitialized) {
|
|
45
|
+
this._traceBuffer.push(trace)
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
this._export(trace)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
_export (payload, writer = this._writer, timerKey = '_timer') {
|
|
52
|
+
writer.append(payload)
|
|
53
|
+
|
|
54
|
+
const { flushInterval } = this._config
|
|
55
|
+
|
|
56
|
+
if (flushInterval === 0) {
|
|
57
|
+
writer.flush()
|
|
58
|
+
} else if (flushInterval > 0 && !this[timerKey]) {
|
|
59
|
+
this[timerKey] = setTimeout(() => {
|
|
60
|
+
writer.flush()
|
|
61
|
+
this[timerKey] = clearTimeout(this[timerKey])
|
|
62
|
+
}, flushInterval).unref()
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
getUncodedTraces () {
|
|
67
|
+
return this._traceBuffer
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
exportUncodedTraces () {
|
|
71
|
+
this.getUncodedTraces().forEach(uncodedTrace => {
|
|
72
|
+
this.export(uncodedTrace)
|
|
73
|
+
})
|
|
74
|
+
this.resetUncodedTraces()
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
resetUncodedTraces () {
|
|
78
|
+
this._traceBuffer = []
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
module.exports = AgentInfoExporter
|
|
@@ -121,9 +121,7 @@ module.exports = class PluginManager {
|
|
|
121
121
|
serviceMapping,
|
|
122
122
|
clientIpHeaderDisabled,
|
|
123
123
|
clientIpHeader,
|
|
124
|
-
isIntelligentTestRunnerEnabled,
|
|
125
124
|
site,
|
|
126
|
-
experimental,
|
|
127
125
|
queryStringObfuscation,
|
|
128
126
|
url,
|
|
129
127
|
dbmPropagationMode
|
|
@@ -147,12 +145,6 @@ module.exports = class PluginManager {
|
|
|
147
145
|
sharedConfig.clientIpHeader = clientIpHeader
|
|
148
146
|
}
|
|
149
147
|
|
|
150
|
-
if (experimental) {
|
|
151
|
-
sharedConfig.isAgentlessEnabled = experimental.exporter === 'datadog'
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
sharedConfig.isIntelligentTestRunnerEnabled = isIntelligentTestRunnerEnabled
|
|
155
|
-
|
|
156
148
|
sharedConfig.dbmPropagationMode = dbmPropagationMode
|
|
157
149
|
|
|
158
150
|
if (serviceMapping && serviceMapping[name]) {
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
const { channel } = require('diagnostics_channel')
|
|
2
|
-
|
|
3
1
|
const {
|
|
4
2
|
getTestEnvironmentMetadata,
|
|
5
3
|
getCodeOwnersFileEntries,
|
|
@@ -9,8 +7,6 @@ const {
|
|
|
9
7
|
TEST_CODE_OWNERS,
|
|
10
8
|
CI_APP_ORIGIN
|
|
11
9
|
} = require('./util/test')
|
|
12
|
-
const { getItrConfiguration } = require('../ci-visibility/intelligent-test-runner/get-itr-configuration')
|
|
13
|
-
const { getSkippableSuites } = require('../ci-visibility/intelligent-test-runner/get-skippable-suites')
|
|
14
10
|
const { COMPONENT } = require('../constants')
|
|
15
11
|
|
|
16
12
|
const Plugin = require('./plugin')
|
|
@@ -19,52 +15,18 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
19
15
|
constructor (...args) {
|
|
20
16
|
super(...args)
|
|
21
17
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const gitMetadataPromise = new Promise(resolve => {
|
|
27
|
-
gitMetadataUploadFinishCh.subscribe(err => {
|
|
28
|
-
resolve(err)
|
|
29
|
-
})
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
this.codeOwnersEntries = getCodeOwnersFileEntries()
|
|
33
|
-
|
|
34
|
-
this.addSub(`ci:${this.constructor.name}:configuration`, ({ onDone }) => {
|
|
35
|
-
if (!this.config.isAgentlessEnabled || !this.config.isIntelligentTestRunnerEnabled) {
|
|
36
|
-
onDone({ config: {} })
|
|
37
|
-
return
|
|
38
|
-
}
|
|
39
|
-
getItrConfiguration(this.testConfiguration, (err, config) => {
|
|
40
|
-
if (err) {
|
|
41
|
-
onDone({ err })
|
|
42
|
-
} else {
|
|
43
|
-
this.itrConfig = config
|
|
44
|
-
onDone({ config })
|
|
18
|
+
this.addSub(`ci:${this.constructor.name}:itr-configuration`, ({ onDone }) => {
|
|
19
|
+
this.tracer._exporter.getItrConfiguration(this.testConfiguration, (err, itrConfig) => {
|
|
20
|
+
if (!err) {
|
|
21
|
+
this.itrConfig = itrConfig
|
|
45
22
|
}
|
|
23
|
+
onDone({ err, itrConfig })
|
|
46
24
|
})
|
|
47
25
|
})
|
|
48
26
|
|
|
49
27
|
this.addSub(`ci:${this.constructor.name}:test-suite:skippable`, ({ onDone }) => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
// we only request after git upload has happened, if it didn't fail
|
|
54
|
-
gitMetadataPromise.then((gitUploadError) => {
|
|
55
|
-
if (gitUploadError) {
|
|
56
|
-
return onDone({ err: gitUploadError })
|
|
57
|
-
}
|
|
58
|
-
if (!this.itrConfig || !this.itrConfig.isSuitesSkippingEnabled) {
|
|
59
|
-
return onDone({ skippableSuites: [] })
|
|
60
|
-
}
|
|
61
|
-
getSkippableSuites(this.testConfiguration, (err, skippableSuites) => {
|
|
62
|
-
if (err) {
|
|
63
|
-
onDone({ err })
|
|
64
|
-
} else {
|
|
65
|
-
onDone({ skippableSuites })
|
|
66
|
-
}
|
|
67
|
-
})
|
|
28
|
+
this.tracer._exporter.getSkippableSuites(this.testConfiguration, (err, skippableSuites) => {
|
|
29
|
+
onDone({ err, skippableSuites })
|
|
68
30
|
})
|
|
69
31
|
})
|
|
70
32
|
}
|
|
@@ -72,6 +34,7 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
72
34
|
configure (config) {
|
|
73
35
|
super.configure(config)
|
|
74
36
|
this.testEnvironmentMetadata = getTestEnvironmentMetadata(this.constructor.name, this.config)
|
|
37
|
+
this.codeOwnersEntries = getCodeOwnersFileEntries()
|
|
75
38
|
|
|
76
39
|
const {
|
|
77
40
|
'git.repository_url': repositoryUrl,
|
|
@@ -92,11 +55,7 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
92
55
|
osArchitecture,
|
|
93
56
|
runtimeName,
|
|
94
57
|
runtimeVersion,
|
|
95
|
-
branch
|
|
96
|
-
url: this.config.url,
|
|
97
|
-
site: this.config.site,
|
|
98
|
-
env: this.tracer._env,
|
|
99
|
-
service: this.config.service || this.tracer._service
|
|
58
|
+
branch
|
|
100
59
|
}
|
|
101
60
|
}
|
|
102
61
|
|
|
@@ -18,7 +18,9 @@ const {
|
|
|
18
18
|
CI_JOB_URL,
|
|
19
19
|
CI_JOB_NAME,
|
|
20
20
|
CI_STAGE_NAME,
|
|
21
|
-
CI_ENV_VARS
|
|
21
|
+
CI_ENV_VARS,
|
|
22
|
+
GIT_COMMIT_COMMITTER_NAME,
|
|
23
|
+
GIT_COMMIT_COMMITTER_EMAIL
|
|
22
24
|
} = require('./tags')
|
|
23
25
|
|
|
24
26
|
// Receives a string with the form 'John Doe <john.doe@gmail.com>'
|
|
@@ -281,6 +283,7 @@ module.exports = {
|
|
|
281
283
|
APPVEYOR_REPO_TAG_NAME,
|
|
282
284
|
APPVEYOR_REPO_COMMIT_AUTHOR,
|
|
283
285
|
APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL,
|
|
286
|
+
APPVEYOR_REPO_COMMIT_MESSAGE,
|
|
284
287
|
APPVEYOR_REPO_COMMIT_MESSAGE_EXTENDED
|
|
285
288
|
} = env
|
|
286
289
|
|
|
@@ -296,7 +299,7 @@ module.exports = {
|
|
|
296
299
|
[CI_WORKSPACE_PATH]: APPVEYOR_BUILD_FOLDER,
|
|
297
300
|
[GIT_COMMIT_AUTHOR_NAME]: APPVEYOR_REPO_COMMIT_AUTHOR,
|
|
298
301
|
[GIT_COMMIT_AUTHOR_EMAIL]: APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL,
|
|
299
|
-
[GIT_COMMIT_MESSAGE]: APPVEYOR_REPO_COMMIT_MESSAGE_EXTENDED
|
|
302
|
+
[GIT_COMMIT_MESSAGE]: APPVEYOR_REPO_COMMIT_MESSAGE + '\n' + APPVEYOR_REPO_COMMIT_MESSAGE_EXTENDED
|
|
300
303
|
}
|
|
301
304
|
|
|
302
305
|
if (APPVEYOR_REPO_PROVIDER === 'github') {
|
|
@@ -506,6 +509,36 @@ module.exports = {
|
|
|
506
509
|
}
|
|
507
510
|
}
|
|
508
511
|
|
|
512
|
+
if (env.BUDDY) {
|
|
513
|
+
const {
|
|
514
|
+
BUDDY_EXECUTION_BRANCH,
|
|
515
|
+
BUDDY_EXECUTION_ID,
|
|
516
|
+
BUDDY_EXECUTION_REVISION,
|
|
517
|
+
BUDDY_EXECUTION_REVISION_COMMITTER_EMAIL,
|
|
518
|
+
BUDDY_EXECUTION_REVISION_COMMITTER_NAME,
|
|
519
|
+
BUDDY_EXECUTION_REVISION_MESSAGE,
|
|
520
|
+
BUDDY_EXECUTION_TAG,
|
|
521
|
+
BUDDY_EXECUTION_URL,
|
|
522
|
+
BUDDY_PIPELINE_ID,
|
|
523
|
+
BUDDY_PIPELINE_NAME,
|
|
524
|
+
BUDDY_SCM_URL
|
|
525
|
+
} = env
|
|
526
|
+
tags = {
|
|
527
|
+
[CI_PROVIDER_NAME]: 'buddy',
|
|
528
|
+
[CI_PIPELINE_ID]: `${BUDDY_PIPELINE_ID}/${BUDDY_EXECUTION_ID}`,
|
|
529
|
+
[CI_PIPELINE_NAME]: BUDDY_PIPELINE_NAME,
|
|
530
|
+
[CI_PIPELINE_NUMBER]: BUDDY_EXECUTION_ID,
|
|
531
|
+
[CI_PIPELINE_URL]: BUDDY_EXECUTION_URL,
|
|
532
|
+
[GIT_COMMIT_SHA]: BUDDY_EXECUTION_REVISION,
|
|
533
|
+
[GIT_REPOSITORY_URL]: BUDDY_SCM_URL,
|
|
534
|
+
[GIT_BRANCH]: BUDDY_EXECUTION_BRANCH,
|
|
535
|
+
[GIT_TAG]: BUDDY_EXECUTION_TAG,
|
|
536
|
+
[GIT_COMMIT_MESSAGE]: BUDDY_EXECUTION_REVISION_MESSAGE,
|
|
537
|
+
[GIT_COMMIT_COMMITTER_NAME]: BUDDY_EXECUTION_REVISION_COMMITTER_NAME,
|
|
538
|
+
[GIT_COMMIT_COMMITTER_EMAIL]: BUDDY_EXECUTION_REVISION_COMMITTER_EMAIL
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
509
542
|
normalizeTag(tags, CI_WORKSPACE_PATH, resolveTilde)
|
|
510
543
|
normalizeTag(tags, GIT_REPOSITORY_URL, filterSensitiveInfoFromRepository)
|
|
511
544
|
normalizeTag(tags, GIT_BRANCH, normalizeRef)
|
|
@@ -46,6 +46,8 @@ const CI_APP_ORIGIN = 'ciapp-test'
|
|
|
46
46
|
const JEST_TEST_RUNNER = 'test.jest.test_runner'
|
|
47
47
|
|
|
48
48
|
const TEST_ITR_TESTS_SKIPPED = '_dd.ci.itr.tests_skipped'
|
|
49
|
+
const TEST_SESSION_ITR_SKIPPING_ENABLED = 'test_session.itr.tests_skipping.enabled'
|
|
50
|
+
const TEST_SESSION_ITR_CODE_COVERAGE_ENABLED = 'test_session.itr.code_coverage.enabled'
|
|
49
51
|
|
|
50
52
|
const TEST_CODE_COVERAGE_LINES_TOTAL = 'test.codecov_lines_total'
|
|
51
53
|
|
|
@@ -78,6 +80,8 @@ module.exports = {
|
|
|
78
80
|
TEST_SESSION_ID,
|
|
79
81
|
TEST_SUITE_ID,
|
|
80
82
|
TEST_ITR_TESTS_SKIPPED,
|
|
83
|
+
TEST_SESSION_ITR_SKIPPING_ENABLED,
|
|
84
|
+
TEST_SESSION_ITR_CODE_COVERAGE_ENABLED,
|
|
81
85
|
TEST_CODE_COVERAGE_LINES_TOTAL,
|
|
82
86
|
getCoveredFilenamesFromCoverage,
|
|
83
87
|
resetCoverage,
|
|
@@ -265,8 +265,7 @@ const web = {
|
|
|
265
265
|
|
|
266
266
|
// Extract the parent span from the headers and start a new span as its child
|
|
267
267
|
startChildSpan (tracer, name, headers) {
|
|
268
|
-
const childOf = tracer.
|
|
269
|
-
|
|
268
|
+
const childOf = tracer.extract(FORMAT_HTTP_HEADERS, headers)
|
|
270
269
|
const span = tracer.startSpan(name, { childOf })
|
|
271
270
|
|
|
272
271
|
return span
|
|
@@ -6,11 +6,14 @@ const { request } = require('http')
|
|
|
6
6
|
// TODO: avoid using dd-trace internals. Make this a separate module?
|
|
7
7
|
const docker = require('../../exporters/common/docker')
|
|
8
8
|
const FormData = require('../../exporters/common/form-data')
|
|
9
|
+
const { storage } = require('../../../../datadog-core')
|
|
9
10
|
const version = require('../../../../../package.json').version
|
|
10
11
|
|
|
11
12
|
const containerId = docker.id()
|
|
12
13
|
|
|
13
14
|
function sendRequest (options, form, callback) {
|
|
15
|
+
const store = storage.getStore()
|
|
16
|
+
storage.enterWith({ noop: true })
|
|
14
17
|
const req = request(options, res => {
|
|
15
18
|
if (res.statusCode >= 400) {
|
|
16
19
|
const error = new Error(`HTTP Error ${res.statusCode}`)
|
|
@@ -22,6 +25,7 @@ function sendRequest (options, form, callback) {
|
|
|
22
25
|
})
|
|
23
26
|
req.on('error', callback)
|
|
24
27
|
if (form) form.pipe(req)
|
|
28
|
+
storage.enterWith(store)
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
function getBody (stream, callback) {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict'
|
|
2
|
-
const
|
|
3
|
-
|
|
2
|
+
const PluginManager = require('./plugin_manager')
|
|
4
3
|
const NoopProxy = require('./noop/proxy')
|
|
5
4
|
const DatadogTracer = require('./tracer')
|
|
6
5
|
const Config = require('./config')
|
|
@@ -8,12 +7,8 @@ const metrics = require('./metrics')
|
|
|
8
7
|
const log = require('./log')
|
|
9
8
|
const { setStartupLogPluginManager } = require('./startup-log')
|
|
10
9
|
const telemetry = require('./telemetry')
|
|
11
|
-
const PluginManager = require('./plugin_manager')
|
|
12
|
-
const { sendGitMetadata } = require('./ci-visibility/exporters/git/git_metadata')
|
|
13
10
|
const remoteConfig = require('./appsec/remote_config')
|
|
14
11
|
|
|
15
|
-
const gitMetadataUploadFinishCh = channel('ci:git-metadata-upload:finish')
|
|
16
|
-
|
|
17
12
|
class Tracer extends NoopProxy {
|
|
18
13
|
constructor () {
|
|
19
14
|
super()
|
|
@@ -30,7 +25,9 @@ class Tracer extends NoopProxy {
|
|
|
30
25
|
try {
|
|
31
26
|
const config = new Config(options) // TODO: support dynamic config
|
|
32
27
|
|
|
33
|
-
|
|
28
|
+
if (!config.isCiVisibility) {
|
|
29
|
+
remoteConfig.enable(config)
|
|
30
|
+
}
|
|
34
31
|
|
|
35
32
|
if (config.profiling.enabled) {
|
|
36
33
|
// do not stop tracer initialization if the profiler fails to be imported
|
|
@@ -61,17 +58,6 @@ class Tracer extends NoopProxy {
|
|
|
61
58
|
setStartupLogPluginManager(this._pluginManager)
|
|
62
59
|
telemetry.start(config, this._pluginManager)
|
|
63
60
|
}
|
|
64
|
-
|
|
65
|
-
if (config.isGitUploadEnabled) {
|
|
66
|
-
sendGitMetadata(config.site, (err) => {
|
|
67
|
-
if (err) {
|
|
68
|
-
log.error(`Error uploading git metadata: ${err.message}`)
|
|
69
|
-
} else {
|
|
70
|
-
log.debug('Successfully uploaded git metadata')
|
|
71
|
-
}
|
|
72
|
-
gitMetadataUploadFinishCh.publish(err)
|
|
73
|
-
})
|
|
74
|
-
}
|
|
75
61
|
} catch (e) {
|
|
76
62
|
log.error(e)
|
|
77
63
|
}
|