datadog-ci 1.18.0 → 1.20.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -2
- data/README.md +8 -17
- data/lib/datadog/ci/contrib/rspec/configuration/settings.rb +6 -0
- data/lib/datadog/ci/contrib/rspec/documentation_formatter.rb +126 -0
- data/lib/datadog/ci/contrib/rspec/example.rb +18 -0
- data/lib/datadog/ci/contrib/rspec/ext.rb +9 -0
- data/lib/datadog/ci/contrib/rspec/patcher.rb +2 -0
- data/lib/datadog/ci/ext/environment/configuration_discrepancy_checker.rb +91 -0
- data/lib/datadog/ci/ext/environment/extractor.rb +8 -2
- data/lib/datadog/ci/ext/environment/providers/appveyor.rb +9 -1
- data/lib/datadog/ci/ext/environment/providers/azure.rb +8 -0
- data/lib/datadog/ci/ext/environment/providers/base.rb +3 -0
- data/lib/datadog/ci/ext/environment/providers/bitbucket.rb +4 -0
- data/lib/datadog/ci/ext/environment/providers/bitrise.rb +4 -0
- data/lib/datadog/ci/ext/environment/providers/buddy.rb +4 -0
- data/lib/datadog/ci/ext/environment/providers/buildkite.rb +10 -0
- data/lib/datadog/ci/ext/environment/providers/circleci.rb +4 -0
- data/lib/datadog/ci/ext/environment/providers/codefresh.rb +8 -0
- data/lib/datadog/ci/ext/environment/providers/drone.rb +83 -0
- data/lib/datadog/ci/ext/environment/providers/github_actions.rb +0 -2
- data/lib/datadog/ci/ext/environment/providers/gitlab.rb +4 -4
- data/lib/datadog/ci/ext/environment/providers/jenkins.rb +8 -0
- data/lib/datadog/ci/ext/environment/providers/teamcity.rb +8 -0
- data/lib/datadog/ci/ext/environment/providers/travis.rb +22 -0
- data/lib/datadog/ci/ext/environment/providers.rb +2 -0
- data/lib/datadog/ci/ext/environment.rb +9 -3
- data/lib/datadog/ci/ext/telemetry.rb +3 -0
- data/lib/datadog/ci/ext/test.rb +6 -0
- data/lib/datadog/ci/git/changed_lines.rb +109 -0
- data/lib/datadog/ci/git/diff.rb +90 -0
- data/lib/datadog/ci/git/local_repository.rb +23 -29
- data/lib/datadog/ci/impacted_tests_detection/component.rb +15 -9
- data/lib/datadog/ci/remote/library_settings_client.rb +1 -1
- data/lib/datadog/ci/span.rb +12 -0
- data/lib/datadog/ci/test.rb +16 -0
- data/lib/datadog/ci/test_retries/component.rb +6 -0
- data/lib/datadog/ci/test_retries/driver/base.rb +7 -2
- data/lib/datadog/ci/test_visibility/component.rb +3 -2
- data/lib/datadog/ci/test_visibility/transport.rb +10 -9
- data/lib/datadog/ci/utils/command.rb +2 -1
- data/lib/datadog/ci/version.rb +1 -1
- metadata +6 -1
@@ -104,14 +104,14 @@ module Datadog
|
|
104
104
|
env["CI_MERGE_REQUEST_TARGET_BRANCH_NAME"]
|
105
105
|
end
|
106
106
|
|
107
|
-
def git_pull_request_base_branch_sha
|
108
|
-
env["CI_MERGE_REQUEST_TARGET_BRANCH_SHA"]
|
109
|
-
end
|
110
|
-
|
111
107
|
def git_commit_head_sha
|
112
108
|
env["CI_MERGE_REQUEST_SOURCE_BRANCH_SHA"]
|
113
109
|
end
|
114
110
|
|
111
|
+
def pr_number
|
112
|
+
env["CI_MERGE_REQUEST_IID"]
|
113
|
+
end
|
114
|
+
|
115
115
|
private
|
116
116
|
|
117
117
|
def extract_name_email
|
@@ -61,6 +61,28 @@ module Datadog
|
|
61
61
|
def git_commit_message
|
62
62
|
env["TRAVIS_COMMIT_MESSAGE"]
|
63
63
|
end
|
64
|
+
|
65
|
+
def git_pull_request_base_branch
|
66
|
+
return nil unless pull_request?
|
67
|
+
|
68
|
+
env["TRAVIS_BRANCH"]
|
69
|
+
end
|
70
|
+
|
71
|
+
def git_commit_head_sha
|
72
|
+
return nil unless pull_request?
|
73
|
+
|
74
|
+
env["TRAVIS_PULL_REQUEST_SHA"]
|
75
|
+
end
|
76
|
+
|
77
|
+
def pr_number
|
78
|
+
return nil unless pull_request?
|
79
|
+
|
80
|
+
env["TRAVIS_PULL_REQUEST"]
|
81
|
+
end
|
82
|
+
|
83
|
+
def pull_request?
|
84
|
+
env["TRAVIS_EVENT_TYPE"] == "pull_request"
|
85
|
+
end
|
64
86
|
end
|
65
87
|
end
|
66
88
|
end
|
@@ -10,6 +10,7 @@ require_relative "providers/buddy"
|
|
10
10
|
require_relative "providers/buildkite"
|
11
11
|
require_relative "providers/circleci"
|
12
12
|
require_relative "providers/codefresh"
|
13
|
+
require_relative "providers/drone"
|
13
14
|
require_relative "providers/github_actions"
|
14
15
|
require_relative "providers/gitlab"
|
15
16
|
require_relative "providers/jenkins"
|
@@ -34,6 +35,7 @@ module Datadog
|
|
34
35
|
Providers::Buildkite,
|
35
36
|
Providers::Circleci,
|
36
37
|
Providers::Codefresh,
|
38
|
+
Providers::Drone,
|
37
39
|
Providers::GithubActions,
|
38
40
|
Providers::Gitlab,
|
39
41
|
Providers::Jenkins,
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require "datadog/core/telemetry/logging"
|
4
4
|
|
5
5
|
require_relative "git"
|
6
|
+
require_relative "environment/configuration_discrepancy_checker"
|
6
7
|
require_relative "environment/extractor"
|
7
8
|
|
8
9
|
require_relative "../utils/git"
|
@@ -24,6 +25,7 @@ module Datadog
|
|
24
25
|
TAG_NODE_LABELS = "ci.node.labels"
|
25
26
|
TAG_NODE_NAME = "ci.node.name"
|
26
27
|
TAG_CI_ENV_VARS = "_dd.ci.env_vars"
|
28
|
+
TAG_PR_NUMBER = "pr.number"
|
27
29
|
|
28
30
|
module Provider
|
29
31
|
APPVEYOR = "appveyor"
|
@@ -35,6 +37,7 @@ module Datadog
|
|
35
37
|
BUILDKITE = "buildkite"
|
36
38
|
CIRCLECI = "circleci"
|
37
39
|
CODEFRESH = "codefresh"
|
40
|
+
DRONE = "drone"
|
38
41
|
GITHUB = "github"
|
39
42
|
GITLAB = "gitlab"
|
40
43
|
JENKINS = "jenkins"
|
@@ -51,9 +54,8 @@ module Datadog
|
|
51
54
|
tags = Environment::Extractor.new(env).tags
|
52
55
|
|
53
56
|
# If user defined metadata is defined, overwrite
|
54
|
-
|
55
|
-
|
56
|
-
)
|
57
|
+
user_provided_tags = Environment::Extractor.new(env, provider_klass: Providers::UserDefinedTags).tags
|
58
|
+
tags.merge!(user_provided_tags)
|
57
59
|
|
58
60
|
# Fill out tags from local git as fallback
|
59
61
|
local_git_tags = Environment::Extractor.new(env, provider_klass: Providers::LocalGit).tags
|
@@ -61,6 +63,10 @@ module Datadog
|
|
61
63
|
tags[key] ||= value
|
62
64
|
end
|
63
65
|
|
66
|
+
# send some telemetry for the cases where git commit sha is overriden
|
67
|
+
discrepancy_checker = ConfigurationDiscrepancyChecker.new(tags, local_git_tags, user_provided_tags)
|
68
|
+
discrepancy_checker.check_for_discrepancies
|
69
|
+
|
64
70
|
ensure_post_conditions(tags)
|
65
71
|
|
66
72
|
tags
|
@@ -68,6 +68,9 @@ module Datadog
|
|
68
68
|
|
69
69
|
METRIC_TEST_SESSION = "test_session"
|
70
70
|
|
71
|
+
METRIC_GIT_COMMIT_SHA_MATCH = "git.commit_sha_match"
|
72
|
+
METRIC_GIT_COMMIT_SHA_DISCREPANCY = "git.commit_sha_discrepancy"
|
73
|
+
|
71
74
|
TAG_TEST_FRAMEWORK = "test_framework"
|
72
75
|
TAG_EVENT_TYPE = "event_type"
|
73
76
|
TAG_HAS_CODEOWNER = "has_codeowner"
|
data/lib/datadog/ci/ext/test.rb
CHANGED
@@ -159,6 +159,12 @@ module Datadog
|
|
159
159
|
RETRY_FAILED = "auto_test_retries"
|
160
160
|
RETRY_FLAKY_FIXED = "attempt_to_fix"
|
161
161
|
RETRY_EXTERNAL = "external"
|
162
|
+
|
163
|
+
DATADOG_RETRY_REASONS = [
|
164
|
+
RETRY_FAILED,
|
165
|
+
RETRY_DETECT_FLAKY,
|
166
|
+
RETRY_FLAKY_FIXED
|
167
|
+
]
|
162
168
|
end
|
163
169
|
|
164
170
|
# possible reasons why a test was skipped
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module CI
|
5
|
+
module Git
|
6
|
+
# Helper class to efficiently store and query changed line intervals for a single file
|
7
|
+
# Uses merged sorted intervals with binary search for O(log n) query performance
|
8
|
+
class ChangedLines
|
9
|
+
def initialize
|
10
|
+
@intervals = [] # Array of [start, end] pairs
|
11
|
+
@built = false
|
12
|
+
@mutex = Mutex.new
|
13
|
+
end
|
14
|
+
|
15
|
+
# Add an interval (defers merging until build! is called)
|
16
|
+
def add_interval(start_line, end_line)
|
17
|
+
return if start_line > end_line
|
18
|
+
|
19
|
+
@mutex.synchronize do
|
20
|
+
@intervals << [start_line, end_line]
|
21
|
+
@built = false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Sort and merge all intervals
|
26
|
+
# Call this after all intervals have been added
|
27
|
+
def build!
|
28
|
+
@mutex.synchronize do
|
29
|
+
return false if @built
|
30
|
+
|
31
|
+
@built = true
|
32
|
+
return false if @intervals.empty?
|
33
|
+
|
34
|
+
# Sort intervals by start line
|
35
|
+
@intervals.sort_by!(&:first)
|
36
|
+
|
37
|
+
# Merge overlapping intervals
|
38
|
+
merged = []
|
39
|
+
|
40
|
+
# @type var current_start: Integer
|
41
|
+
# @type var current_end: Integer
|
42
|
+
current_start, current_end = @intervals.first
|
43
|
+
|
44
|
+
@intervals.each_with_index do |interval, index|
|
45
|
+
next if index == 0
|
46
|
+
# @type var start_line: Integer
|
47
|
+
# @type var end_line: Integer
|
48
|
+
start_line, end_line = interval
|
49
|
+
|
50
|
+
if start_line <= current_end + 1
|
51
|
+
# Overlapping or adjacent intervals, merge them
|
52
|
+
current_end = [current_end, end_line].max
|
53
|
+
else
|
54
|
+
# Non-overlapping interval, save current and start new
|
55
|
+
merged << [current_start, current_end]
|
56
|
+
current_start = start_line
|
57
|
+
current_end = end_line
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
merged << [current_start, current_end]
|
62
|
+
|
63
|
+
@intervals = merged
|
64
|
+
true
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Check if any line in the query interval overlaps with changed lines
|
69
|
+
# Uses binary search for O(log n) performance
|
70
|
+
def overlaps?(query_start, query_end)
|
71
|
+
build! unless @built
|
72
|
+
|
73
|
+
return false if @intervals.empty? || query_start > query_end
|
74
|
+
|
75
|
+
# Binary search for the first interval that might overlap
|
76
|
+
left = 0
|
77
|
+
right = @intervals.length - 1
|
78
|
+
|
79
|
+
while left <= right
|
80
|
+
mid = (left + right) / 2
|
81
|
+
# @type var interval_start: Integer
|
82
|
+
# @type var interval_end: Integer
|
83
|
+
interval_start, interval_end = @intervals[mid]
|
84
|
+
|
85
|
+
if interval_end < query_start
|
86
|
+
left = mid + 1
|
87
|
+
elsif interval_start > query_end
|
88
|
+
right = mid - 1
|
89
|
+
else
|
90
|
+
# Found overlap
|
91
|
+
return true
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
false
|
96
|
+
end
|
97
|
+
|
98
|
+
def empty?
|
99
|
+
@intervals.empty?
|
100
|
+
end
|
101
|
+
|
102
|
+
def intervals
|
103
|
+
build! unless @built
|
104
|
+
@intervals.dup
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "set"
|
4
|
+
require_relative "changed_lines"
|
5
|
+
|
6
|
+
module Datadog
|
7
|
+
module CI
|
8
|
+
module Git
|
9
|
+
class Diff
|
10
|
+
FILE_CHANGE_REGEX = /^diff --git a\/(?<file>.+?) b\//.freeze
|
11
|
+
LINES_CHANGE_REGEX = /^@@ -\d+(?:,\d+)? \+(?<start>\d+)(?:,(?<count>\d+))? @@/.freeze
|
12
|
+
|
13
|
+
def initialize(changed_files: {})
|
14
|
+
@changed_files = changed_files # Hash of file_path => ChangedLines
|
15
|
+
end
|
16
|
+
|
17
|
+
# Check if any lines in the given range are changed for the specified file
|
18
|
+
def lines_changed?(file_path, start_line: nil, end_line: nil)
|
19
|
+
changed_lines = @changed_files[file_path]
|
20
|
+
unless changed_lines
|
21
|
+
Datadog.logger.debug { "No changes found for file: #{file_path}" }
|
22
|
+
return false
|
23
|
+
end
|
24
|
+
|
25
|
+
# If either start_line or end_line is nil, return true if file is present
|
26
|
+
return true if start_line.nil? || end_line.nil?
|
27
|
+
|
28
|
+
changed_lines.overlaps?(start_line, end_line)
|
29
|
+
end
|
30
|
+
|
31
|
+
def empty?
|
32
|
+
@changed_files.empty?
|
33
|
+
end
|
34
|
+
|
35
|
+
# for debug purposes
|
36
|
+
def size
|
37
|
+
@changed_files.size
|
38
|
+
end
|
39
|
+
|
40
|
+
# for debug purposes
|
41
|
+
def inspect
|
42
|
+
@changed_files.inspect
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.parse_diff_output(output)
|
46
|
+
return new if output.nil? || output.empty?
|
47
|
+
|
48
|
+
changed_files = {}
|
49
|
+
current_file = nil
|
50
|
+
|
51
|
+
output.each_line do |line|
|
52
|
+
# Match lines like: diff --git a/foo/bar.rb b/foo/bar.rb
|
53
|
+
# This captures git changes on file level
|
54
|
+
match = FILE_CHANGE_REGEX.match(line)
|
55
|
+
if match && match[:file]
|
56
|
+
# this path here is already relative from the git root
|
57
|
+
changed_file = match[:file]
|
58
|
+
|
59
|
+
unless changed_file.nil? || changed_file.empty?
|
60
|
+
current_file = changed_file
|
61
|
+
changed_files[current_file] ||= ChangedLines.new
|
62
|
+
end
|
63
|
+
|
64
|
+
Datadog.logger.debug { "matched changed_file: #{changed_file} from git diff line: #{line}" }
|
65
|
+
|
66
|
+
next
|
67
|
+
end
|
68
|
+
|
69
|
+
# Match lines like: @@ -1,2 +3,4 @@
|
70
|
+
match = LINES_CHANGE_REGEX.match(line)
|
71
|
+
if match && match[:start] && current_file
|
72
|
+
start_line = match[:start].to_i
|
73
|
+
|
74
|
+
line_count = 1 # Default to 1 line if count not specified
|
75
|
+
line_count = match[:count].to_i if match[:count]
|
76
|
+
|
77
|
+
end_line = start_line + line_count - 1
|
78
|
+
|
79
|
+
changed_files[current_file].add_interval(start_line, end_line)
|
80
|
+
|
81
|
+
Datadog.logger.debug { "Added interval [#{start_line}, #{end_line}] for file: #{current_file}" }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
new(changed_files: changed_files)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -8,6 +8,7 @@ require_relative "../ext/telemetry"
|
|
8
8
|
require_relative "../utils/command"
|
9
9
|
require_relative "base_branch_sha_detector"
|
10
10
|
require_relative "cli"
|
11
|
+
require_relative "diff"
|
11
12
|
require_relative "telemetry"
|
12
13
|
require_relative "user"
|
13
14
|
|
@@ -37,14 +38,22 @@ module Datadog
|
|
37
38
|
# that root is a prefix of the path
|
38
39
|
return "" if path.size < prefix_index
|
39
40
|
|
40
|
-
|
41
|
-
|
41
|
+
# this means that the root is not a prefix of this path somehow
|
42
|
+
return "" if path[prefix_index] != File::SEPARATOR
|
43
|
+
|
44
|
+
res = path[prefix_index + 1..]
|
42
45
|
else
|
43
46
|
# prefix_to_root is a difference between the root path and the given path
|
44
|
-
if @prefix_to_root
|
45
|
-
|
46
|
-
|
47
|
-
|
47
|
+
if defined?(@prefix_to_root)
|
48
|
+
# if path starts with ./ remove the dot before applying the optimization
|
49
|
+
# @type var path: String
|
50
|
+
path = path[1..] if path.start_with?("./")
|
51
|
+
|
52
|
+
if @prefix_to_root == ""
|
53
|
+
return path
|
54
|
+
elsif @prefix_to_root
|
55
|
+
return File.join(@prefix_to_root, path)
|
56
|
+
end
|
48
57
|
end
|
49
58
|
|
50
59
|
pathname = Pathname.new(File.expand_path(path))
|
@@ -308,10 +317,10 @@ module Datadog
|
|
308
317
|
res
|
309
318
|
end
|
310
319
|
|
311
|
-
# Returns a
|
320
|
+
# Returns a Diff object with relative file paths for files that were changed since the given base_commit.
|
312
321
|
# If base_commit is nil, returns nil. On error, returns nil.
|
313
|
-
def self.
|
314
|
-
return
|
322
|
+
def self.get_changes_since(base_commit)
|
323
|
+
return Diff.new if base_commit.nil?
|
315
324
|
|
316
325
|
Datadog.logger.debug { "calculating git diff from base_commit: #{base_commit}" }
|
317
326
|
|
@@ -329,29 +338,14 @@ module Datadog
|
|
329
338
|
|
330
339
|
Datadog.logger.debug { "git diff output: #{output}" }
|
331
340
|
|
332
|
-
return
|
333
|
-
|
334
|
-
# 2. Parse the output
|
335
|
-
|
336
|
-
output.each_line do |line|
|
337
|
-
# Match lines like: diff --git a/foo/bar.rb b/foo/bar.rb
|
338
|
-
# This captures git changes on file level
|
339
|
-
match = /^diff --git a\/(?<file>.+?) b\//.match(line)
|
340
|
-
if match && match[:file]
|
341
|
-
changed_file = match[:file]
|
342
|
-
# Normalize to repo root
|
343
|
-
normalized_changed_file = relative_to_root(changed_file)
|
344
|
-
changed_files << normalized_changed_file unless normalized_changed_file.nil? || normalized_changed_file.empty?
|
345
|
-
|
346
|
-
Datadog.logger.debug { "matched changed_file: #{changed_file} from line: #{line}" }
|
347
|
-
Datadog.logger.debug { "normalized_changed_file: #{normalized_changed_file}" }
|
348
|
-
end
|
349
|
-
end
|
350
|
-
changed_files
|
341
|
+
return Diff.new if output.nil?
|
342
|
+
|
343
|
+
# 2. Parse the output using Git::Diff
|
344
|
+
Diff.parse_diff_output(output)
|
351
345
|
rescue => e
|
352
346
|
Telemetry.track_error(e, Ext::Telemetry::Command::DIFF)
|
353
347
|
log_failure(e, "get changed files from diff")
|
354
|
-
|
348
|
+
Diff.new
|
355
349
|
end
|
356
350
|
end
|
357
351
|
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "set"
|
4
|
-
|
5
3
|
require_relative "../ext/test"
|
6
4
|
require_relative "../git/local_repository"
|
7
5
|
|
@@ -11,7 +9,7 @@ module Datadog
|
|
11
9
|
class Component
|
12
10
|
def initialize(enabled:)
|
13
11
|
@enabled = enabled
|
14
|
-
@
|
12
|
+
@git_diff = Git::Diff.new
|
15
13
|
end
|
16
14
|
|
17
15
|
def configure(library_settings, test_session)
|
@@ -29,21 +27,21 @@ module Datadog
|
|
29
27
|
return
|
30
28
|
end
|
31
29
|
|
32
|
-
|
33
|
-
if
|
30
|
+
git_diff = Git::LocalRepository.get_changes_since(base_commit_sha)
|
31
|
+
if git_diff.empty?
|
34
32
|
Datadog.logger.debug { "Impacted tests detection disabled: could not get changed files" }
|
35
33
|
@enabled = false
|
36
34
|
return
|
37
35
|
end
|
38
36
|
|
39
37
|
Datadog.logger.debug do
|
40
|
-
"Impacted tests detection: found #{
|
38
|
+
"Impacted tests detection: found #{git_diff.size} changed files"
|
41
39
|
end
|
42
40
|
Datadog.logger.debug do
|
43
|
-
"Impacted tests detection: changed files: #{
|
41
|
+
"Impacted tests detection: changed files: #{git_diff.inspect}"
|
44
42
|
end
|
45
43
|
|
46
|
-
@
|
44
|
+
@git_diff = git_diff
|
47
45
|
@enabled = true
|
48
46
|
end
|
49
47
|
|
@@ -57,7 +55,15 @@ module Datadog
|
|
57
55
|
source_file = test_span.source_file
|
58
56
|
return false if source_file.nil?
|
59
57
|
|
60
|
-
|
58
|
+
# convert to relative path without leading slash
|
59
|
+
# @type var source_file: String
|
60
|
+
source_file = source_file[1..] if source_file.start_with?("/")
|
61
|
+
|
62
|
+
result = @git_diff.lines_changed?(source_file, start_line: test_span.start_line, end_line: test_span.end_line)
|
63
|
+
Datadog.logger.debug do
|
64
|
+
"Impacted tests detection: test #{test_span.name} with source file #{source_file} is modified: #{result}"
|
65
|
+
end
|
66
|
+
result
|
61
67
|
end
|
62
68
|
|
63
69
|
def tag_modified_test(test_span)
|
@@ -81,7 +81,7 @@ module Datadog
|
|
81
81
|
"service" => test_session.service,
|
82
82
|
"env" => @dd_env,
|
83
83
|
"repository_url" => test_session.git_repository_url,
|
84
|
-
"branch" => test_session.git_branch,
|
84
|
+
"branch" => test_session.git_branch || test_session.git_tag,
|
85
85
|
"sha" => test_session.git_commit_sha,
|
86
86
|
"test_level" => Ext::Test::ITR_TEST_SKIPPING_MODE,
|
87
87
|
"configurations" => {
|
data/lib/datadog/ci/span.rb
CHANGED
@@ -72,6 +72,12 @@ module Datadog
|
|
72
72
|
tracer_span.get_tag(Ext::Test::TAG_STATUS) == Ext::Test::Status::SKIP
|
73
73
|
end
|
74
74
|
|
75
|
+
# Returns the current status of the span.
|
76
|
+
# @return [String, nil] the status of the span ("pass", "fail", "skip"), or nil if not set
|
77
|
+
def status
|
78
|
+
tracer_span.get_tag(Ext::Test::TAG_STATUS)
|
79
|
+
end
|
80
|
+
|
75
81
|
# Sets the status of the span to "pass".
|
76
82
|
# @return [void]
|
77
83
|
def passed!
|
@@ -165,6 +171,12 @@ module Datadog
|
|
165
171
|
tracer_span.get_tag(Ext::Git::TAG_BRANCH)
|
166
172
|
end
|
167
173
|
|
174
|
+
# Returns the git tag extracted from the environment.
|
175
|
+
# @return [String, nil] the tag or nil if not set.
|
176
|
+
def git_tag
|
177
|
+
tracer_span.get_tag(Ext::Git::TAG_TAG)
|
178
|
+
end
|
179
|
+
|
168
180
|
# Returns the base commit SHA for the pull request, if available.
|
169
181
|
# @return [String, nil] the base commit SHA or nil if not set.
|
170
182
|
def base_commit_sha
|
data/lib/datadog/ci/test.rb
CHANGED
@@ -66,6 +66,22 @@ module Datadog
|
|
66
66
|
get_tag(Ext::Test::TAG_TEST_SESSION_ID)
|
67
67
|
end
|
68
68
|
|
69
|
+
# Returns the starting line number of the test in the source file.
|
70
|
+
# @return [Integer] the starting line number
|
71
|
+
# @return [nil] if the starting line is not available
|
72
|
+
def start_line
|
73
|
+
line = get_tag(Ext::Test::TAG_SOURCE_START)
|
74
|
+
line&.to_i
|
75
|
+
end
|
76
|
+
|
77
|
+
# Returns the ending line number of the test in the source file.
|
78
|
+
# @return [Integer] the ending line number
|
79
|
+
# @return [nil] if the ending line is not available
|
80
|
+
def end_line
|
81
|
+
line = get_tag(Ext::Test::TAG_SOURCE_END)
|
82
|
+
line&.to_i
|
83
|
+
end
|
84
|
+
|
69
85
|
# Returns "true" if test span represents a retry.
|
70
86
|
# @return [Boolean] true if this test is a retry, false otherwise.
|
71
87
|
def is_retry?
|
@@ -86,6 +86,12 @@ module Datadog
|
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
|
+
def record_test_started(test_span)
|
90
|
+
# mark test as retry in the beginning
|
91
|
+
# if this is a first execution, the current_retry_driver is nil and this is noop
|
92
|
+
current_retry_driver&.mark_as_retry(test_span)
|
93
|
+
end
|
94
|
+
|
89
95
|
def record_test_finished(test_span)
|
90
96
|
if current_retry_driver.nil?
|
91
97
|
# we always run test at least once and after the first pass create a correct retry driver
|
@@ -11,17 +11,22 @@ module Datadog
|
|
11
11
|
false
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
14
|
+
def mark_as_retry(test_span)
|
15
15
|
test_span&.set_tag(Ext::Test::TAG_IS_RETRY, "true")
|
16
16
|
test_span&.set_tag(Ext::Test::TAG_RETRY_REASON, retry_reason)
|
17
17
|
end
|
18
18
|
|
19
|
+
def record_retry(test_span)
|
20
|
+
end
|
21
|
+
|
19
22
|
# duration in float seconds
|
20
23
|
def record_duration(duration)
|
21
24
|
end
|
22
25
|
|
23
26
|
def retry_reason
|
24
|
-
|
27
|
+
# we set retry reason to be external (ie retried outside of datadog)
|
28
|
+
# by default if we don't know why the test was retried
|
29
|
+
Ext::Test::RetryReason::RETRY_EXTERNAL
|
25
30
|
end
|
26
31
|
end
|
27
32
|
end
|
@@ -267,6 +267,8 @@ module Datadog
|
|
267
267
|
|
268
268
|
test_optimisation.mark_if_skippable(test)
|
269
269
|
test_optimisation.start_coverage(test)
|
270
|
+
|
271
|
+
test_retries.record_test_started(test)
|
270
272
|
end
|
271
273
|
|
272
274
|
def on_test_session_finished(test_session)
|
@@ -293,9 +295,8 @@ module Datadog
|
|
293
295
|
test_optimisation.stop_coverage(test)
|
294
296
|
test_optimisation.on_test_finished(test, maybe_remote_context)
|
295
297
|
|
296
|
-
Telemetry.event_finished(test)
|
297
|
-
|
298
298
|
test_retries.record_test_finished(test)
|
299
|
+
Telemetry.event_finished(test)
|
299
300
|
end
|
300
301
|
|
301
302
|
def on_after_test_span_finished(tracer_span)
|
@@ -19,10 +19,6 @@ module Datadog
|
|
19
19
|
class Transport < Datadog::CI::Transport::EventPlatformTransport
|
20
20
|
attr_reader :serializers_factory, :dd_env
|
21
21
|
|
22
|
-
def self.log_once
|
23
|
-
@log_once ||= Datadog::Core::Utils::OnlyOnce.new
|
24
|
-
end
|
25
|
-
|
26
22
|
def initialize(
|
27
23
|
api:,
|
28
24
|
dd_env:,
|
@@ -72,12 +68,17 @@ module Datadog
|
|
72
68
|
|
73
69
|
encoded
|
74
70
|
else
|
75
|
-
message = "
|
76
|
-
|
77
|
-
|
71
|
+
message = "Event with type #{serializer.event_type}(name=#{serializer.name}) is invalid: #{serializer.validation_errors}"
|
72
|
+
|
73
|
+
if serializer.event_type == "span"
|
74
|
+
# events of type span are often skipped because of missing resource field
|
75
|
+
# (because they are misconfigured in tests context)
|
76
|
+
Datadog.logger.debug(message)
|
77
|
+
else
|
78
|
+
Datadog.logger.warn(message)
|
79
|
+
CI::Transport::Telemetry.endpoint_payload_dropped(1, endpoint: telemetry_endpoint_tag)
|
78
80
|
|
79
|
-
|
80
|
-
self.class.log_once.run do
|
81
|
+
# for CI events log all events to internal telemetry
|
81
82
|
Core::Telemetry::Logger.error(message)
|
82
83
|
end
|
83
84
|
|