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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +30 -2
  3. data/README.md +8 -17
  4. data/lib/datadog/ci/contrib/rspec/configuration/settings.rb +6 -0
  5. data/lib/datadog/ci/contrib/rspec/documentation_formatter.rb +126 -0
  6. data/lib/datadog/ci/contrib/rspec/example.rb +18 -0
  7. data/lib/datadog/ci/contrib/rspec/ext.rb +9 -0
  8. data/lib/datadog/ci/contrib/rspec/patcher.rb +2 -0
  9. data/lib/datadog/ci/ext/environment/configuration_discrepancy_checker.rb +91 -0
  10. data/lib/datadog/ci/ext/environment/extractor.rb +8 -2
  11. data/lib/datadog/ci/ext/environment/providers/appveyor.rb +9 -1
  12. data/lib/datadog/ci/ext/environment/providers/azure.rb +8 -0
  13. data/lib/datadog/ci/ext/environment/providers/base.rb +3 -0
  14. data/lib/datadog/ci/ext/environment/providers/bitbucket.rb +4 -0
  15. data/lib/datadog/ci/ext/environment/providers/bitrise.rb +4 -0
  16. data/lib/datadog/ci/ext/environment/providers/buddy.rb +4 -0
  17. data/lib/datadog/ci/ext/environment/providers/buildkite.rb +10 -0
  18. data/lib/datadog/ci/ext/environment/providers/circleci.rb +4 -0
  19. data/lib/datadog/ci/ext/environment/providers/codefresh.rb +8 -0
  20. data/lib/datadog/ci/ext/environment/providers/drone.rb +83 -0
  21. data/lib/datadog/ci/ext/environment/providers/github_actions.rb +0 -2
  22. data/lib/datadog/ci/ext/environment/providers/gitlab.rb +4 -4
  23. data/lib/datadog/ci/ext/environment/providers/jenkins.rb +8 -0
  24. data/lib/datadog/ci/ext/environment/providers/teamcity.rb +8 -0
  25. data/lib/datadog/ci/ext/environment/providers/travis.rb +22 -0
  26. data/lib/datadog/ci/ext/environment/providers.rb +2 -0
  27. data/lib/datadog/ci/ext/environment.rb +9 -3
  28. data/lib/datadog/ci/ext/telemetry.rb +3 -0
  29. data/lib/datadog/ci/ext/test.rb +6 -0
  30. data/lib/datadog/ci/git/changed_lines.rb +109 -0
  31. data/lib/datadog/ci/git/diff.rb +90 -0
  32. data/lib/datadog/ci/git/local_repository.rb +23 -29
  33. data/lib/datadog/ci/impacted_tests_detection/component.rb +15 -9
  34. data/lib/datadog/ci/remote/library_settings_client.rb +1 -1
  35. data/lib/datadog/ci/span.rb +12 -0
  36. data/lib/datadog/ci/test.rb +16 -0
  37. data/lib/datadog/ci/test_retries/component.rb +6 -0
  38. data/lib/datadog/ci/test_retries/driver/base.rb +7 -2
  39. data/lib/datadog/ci/test_visibility/component.rb +3 -2
  40. data/lib/datadog/ci/test_visibility/transport.rb +10 -9
  41. data/lib/datadog/ci/utils/command.rb +2 -1
  42. data/lib/datadog/ci/version.rb +1 -1
  43. 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
@@ -65,6 +65,14 @@ module Datadog
65
65
  env["GIT_BRANCH"]
66
66
  end
67
67
 
68
+ def git_pull_request_base_branch
69
+ env["CHANGE_TARGET"]
70
+ end
71
+
72
+ def pr_number
73
+ env["CHANGE_ID"]
74
+ end
75
+
68
76
  def ci_env_vars
69
77
  {
70
78
  "DD_CUSTOM_TRACE_ID" => env["DD_CUSTOM_TRACE_ID"]
@@ -25,6 +25,14 @@ module Datadog
25
25
  def job_url
26
26
  env["BUILD_URL"]
27
27
  end
28
+
29
+ def git_pull_request_base_branch
30
+ env["TEAMCITY_PULLREQUEST_TARGET_BRANCH"]
31
+ end
32
+
33
+ def pr_number
34
+ env["TEAMCITY_PULLREQUEST_NUMBER"]
35
+ end
28
36
  end
29
37
  end
30
38
  end
@@ -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
- tags.merge!(
55
- Environment::Extractor.new(env, provider_klass: Providers::UserDefinedTags).tags
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"
@@ -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
- prefix_index += 1 if path[prefix_index] == File::SEPARATOR
41
- res = path[prefix_index..]
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
- return path
46
- elsif @prefix_to_root
47
- return File.join(@prefix_to_root, path)
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 Set of normalized file paths changed since the given base_commit.
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.get_changed_files_from_diff(base_commit)
314
- return nil if base_commit.nil?
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 nil if output.nil?
333
-
334
- # 2. Parse the output to extract which files changed
335
- changed_files = Set.new
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
- nil
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
- @changed_files = Set.new
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
- changed_files = Git::LocalRepository.get_changed_files_from_diff(base_commit_sha)
33
- if changed_files.nil?
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 #{changed_files.size} changed files"
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: #{changed_files.inspect}"
41
+ "Impacted tests detection: changed files: #{git_diff.inspect}"
44
42
  end
45
43
 
46
- @changed_files = changed_files
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
- @changed_files.include?(source_file)
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" => {
@@ -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
@@ -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 record_retry(test_span)
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
- "unknown"
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 = "Invalid event skipped: #{serializer} Errors: #{serializer.validation_errors}"
76
- Datadog.logger.warn(message)
77
- CI::Transport::Telemetry.endpoint_payload_dropped(1, endpoint: telemetry_endpoint_tag)
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
- # log invalid message once as error to internal telemetry
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