datadog-ci 1.17.0 → 1.18.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 (29) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -2
  3. data/ext/datadog_ci_native/ci.c +10 -0
  4. data/ext/{datadog_cov → datadog_ci_native}/datadog_cov.c +119 -147
  5. data/ext/datadog_ci_native/datadog_cov.h +3 -0
  6. data/ext/datadog_ci_native/datadog_source_code.c +28 -0
  7. data/ext/datadog_ci_native/datadog_source_code.h +3 -0
  8. data/ext/{datadog_cov → datadog_ci_native}/extconf.rb +1 -1
  9. data/lib/datadog/ci/contrib/minitest/test.rb +17 -7
  10. data/lib/datadog/ci/contrib/rspec/example.rb +14 -7
  11. data/lib/datadog/ci/ext/telemetry.rb +1 -2
  12. data/lib/datadog/ci/ext/test.rb +1 -0
  13. data/lib/datadog/ci/git/base_branch_sha_detection/base.rb +66 -0
  14. data/lib/datadog/ci/git/base_branch_sha_detection/branch_metric.rb +34 -0
  15. data/lib/datadog/ci/git/base_branch_sha_detection/guesser.rb +137 -0
  16. data/lib/datadog/ci/git/base_branch_sha_detection/merge_base_extractor.rb +29 -0
  17. data/lib/datadog/ci/git/base_branch_sha_detector.rb +63 -0
  18. data/lib/datadog/ci/git/cli.rb +56 -0
  19. data/lib/datadog/ci/git/local_repository.rb +73 -294
  20. data/lib/datadog/ci/git/telemetry.rb +14 -0
  21. data/lib/datadog/ci/impacted_tests_detection/component.rb +0 -2
  22. data/lib/datadog/ci/test_optimisation/component.rb +10 -6
  23. data/lib/datadog/ci/test_optimisation/coverage/ddcov.rb +1 -1
  24. data/lib/datadog/ci/test_visibility/telemetry.rb +3 -0
  25. data/lib/datadog/ci/utils/command.rb +116 -0
  26. data/lib/datadog/ci/utils/source_code.rb +31 -0
  27. data/lib/datadog/ci/version.rb +1 -1
  28. metadata +16 -5
  29. data/lib/datadog/ci/impacted_tests_detection/telemetry.rb +0 -16
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "open3"
4
+ require "datadog/core/utils/time"
5
+
6
+ module Datadog
7
+ module CI
8
+ module Utils
9
+ # Provides a way to call external commands with timeout
10
+ module Command
11
+ DEFAULT_TIMEOUT = 10 # seconds
12
+ BUFFER_SIZE = 1024
13
+
14
+ OPEN_STDIN_RETRY_COUNT = 3
15
+
16
+ # Executes a command with optional timeout and stdin data
17
+ #
18
+ # @param command [Array<String>] Command to execute.
19
+ # @param stdin_data [String, nil] Data to write to stdin
20
+ # @param timeout [Integer] Maximum execution time in seconds
21
+ # @return [Array<String, Process::Status?>] Output and exit status
22
+ #
23
+ # @example Safe usage with array (recommended)
24
+ # Command.exec_command(["git", "log", "-n", "1"])
25
+ #
26
+ #
27
+ def self.exec_command(command, stdin_data: nil, timeout: DEFAULT_TIMEOUT)
28
+ output = +""
29
+ exit_value = nil
30
+ timeout_reached = false
31
+
32
+ begin
33
+ start = Core::Utils::Time.get_time
34
+
35
+ _, stderrout, thread = popen_with_stdin(command, stdin_data: stdin_data)
36
+ pid = thread[:pid]
37
+
38
+ # wait for output and read from stdout/stderr
39
+ while (Core::Utils::Time.get_time - start) < timeout
40
+ # wait for data to appear in stderrout channel
41
+ # maximum wait time 100ms
42
+ Kernel.select([stderrout], [], [], 0.1)
43
+
44
+ begin
45
+ output << stderrout.read_nonblock(1024)
46
+ rescue IO::WaitReadable
47
+ rescue EOFError
48
+ # we're done here, we return from this cycle when we processed the whole output of the command
49
+ break
50
+ end
51
+ end
52
+
53
+ if (Core::Utils::Time.get_time - start) > timeout
54
+ timeout_reached = true
55
+ end
56
+
57
+ if thread.alive?
58
+ begin
59
+ Process.kill("TERM", pid)
60
+ rescue
61
+ # Process already terminated
62
+ end
63
+ end
64
+
65
+ thread.join(1)
66
+ exit_value = thread.value
67
+ rescue Errno::EPIPE
68
+ return ["Error writing to stdin", nil]
69
+ ensure
70
+ stderrout&.close
71
+ end
72
+
73
+ # we read command's output as binary so now we need to set an appropriate encoding for the result
74
+ encoding = Encoding.default_external
75
+
76
+ # Sometimes Encoding.default_external is somehow set to US-ASCII which breaks
77
+ # commit messages with UTF-8 characters like emojis
78
+ # We force output's encoding to be UTF-8 in this case
79
+ # This is safe to do as UTF-8 is compatible with US-ASCII
80
+ if Encoding.default_external == Encoding::US_ASCII
81
+ encoding = Encoding::UTF_8
82
+ end
83
+
84
+ output.force_encoding(encoding)
85
+ output.strip! # There's always a "\n" at the end of the command output
86
+
87
+ if timeout_reached && output.empty?
88
+ output = "Command timed out after #{timeout} seconds"
89
+ end
90
+
91
+ [output, exit_value]
92
+ end
93
+
94
+ def self.popen_with_stdin(command, stdin_data: nil, retries_left: OPEN_STDIN_RETRY_COUNT)
95
+ result = Open3.popen2e(*command)
96
+ stdin = result.first
97
+
98
+ # write input to stdin
99
+ begin
100
+ stdin.write(stdin_data) if stdin_data
101
+ rescue Errno::EPIPE => e
102
+ if retries_left > 0
103
+ return popen_with_stdin(command, stdin_data: stdin_data, retries_left: retries_left - 1)
104
+ else
105
+ raise e
106
+ end
107
+ end
108
+
109
+ result
110
+ ensure
111
+ stdin.close
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module CI
5
+ module Utils
6
+ module SourceCode
7
+ begin
8
+ require "datadog_ci_native.#{RUBY_VERSION}_#{RUBY_PLATFORM}"
9
+
10
+ LAST_LINE_AVAILABLE = true
11
+ rescue LoadError
12
+ LAST_LINE_AVAILABLE = false
13
+ end
14
+
15
+ def self.last_line(target)
16
+ return nil if target.nil?
17
+ return nil unless LAST_LINE_AVAILABLE
18
+
19
+ # Ruby has outdated RBS for RubyVM::InstructionSequence where method `of` is not defined
20
+ # steep:ignore:start
21
+ iseq = RubyVM::InstructionSequence.of(target)
22
+ return nil unless iseq.is_a?(RubyVM::InstructionSequence)
23
+ # steep:ignore:end
24
+
25
+ # this function is implemented in ext/datadog_ci_native/datadog_source_code.c
26
+ _native_last_line_from_iseq(iseq)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -4,7 +4,7 @@ module Datadog
4
4
  module CI
5
5
  module VERSION
6
6
  MAJOR = 1
7
- MINOR = 17
7
+ MINOR = 18
8
8
  PATCH = 0
9
9
  PRE = nil
10
10
  BUILD = nil
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: datadog-ci
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.17.0
4
+ version: 1.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Datadog, Inc.
@@ -60,7 +60,7 @@ email:
60
60
  executables:
61
61
  - ddcirb
62
62
  extensions:
63
- - ext/datadog_cov/extconf.rb
63
+ - ext/datadog_ci_native/extconf.rb
64
64
  extra_rdoc_files: []
65
65
  files:
66
66
  - CHANGELOG.md
@@ -71,8 +71,12 @@ files:
71
71
  - NOTICE
72
72
  - README.md
73
73
  - exe/ddcirb
74
- - ext/datadog_cov/datadog_cov.c
75
- - ext/datadog_cov/extconf.rb
74
+ - ext/datadog_ci_native/ci.c
75
+ - ext/datadog_ci_native/datadog_cov.c
76
+ - ext/datadog_ci_native/datadog_cov.h
77
+ - ext/datadog_ci_native/datadog_source_code.c
78
+ - ext/datadog_ci_native/datadog_source_code.h
79
+ - ext/datadog_ci_native/extconf.rb
76
80
  - lib/datadog/ci.rb
77
81
  - lib/datadog/ci/async_writer.rb
78
82
  - lib/datadog/ci/auto_instrument.rb
@@ -187,6 +191,12 @@ files:
187
191
  - lib/datadog/ci/ext/telemetry.rb
188
192
  - lib/datadog/ci/ext/test.rb
189
193
  - lib/datadog/ci/ext/transport.rb
194
+ - lib/datadog/ci/git/base_branch_sha_detection/base.rb
195
+ - lib/datadog/ci/git/base_branch_sha_detection/branch_metric.rb
196
+ - lib/datadog/ci/git/base_branch_sha_detection/guesser.rb
197
+ - lib/datadog/ci/git/base_branch_sha_detection/merge_base_extractor.rb
198
+ - lib/datadog/ci/git/base_branch_sha_detector.rb
199
+ - lib/datadog/ci/git/cli.rb
190
200
  - lib/datadog/ci/git/local_repository.rb
191
201
  - lib/datadog/ci/git/packfiles.rb
192
202
  - lib/datadog/ci/git/search_commits.rb
@@ -195,7 +205,6 @@ files:
195
205
  - lib/datadog/ci/git/upload_packfile.rb
196
206
  - lib/datadog/ci/git/user.rb
197
207
  - lib/datadog/ci/impacted_tests_detection/component.rb
198
- - lib/datadog/ci/impacted_tests_detection/telemetry.rb
199
208
  - lib/datadog/ci/logs/component.rb
200
209
  - lib/datadog/ci/logs/transport.rb
201
210
  - lib/datadog/ci/readonly_test_module.rb
@@ -265,11 +274,13 @@ files:
265
274
  - lib/datadog/ci/transport/http.rb
266
275
  - lib/datadog/ci/transport/telemetry.rb
267
276
  - lib/datadog/ci/utils/bundle.rb
277
+ - lib/datadog/ci/utils/command.rb
268
278
  - lib/datadog/ci/utils/configuration.rb
269
279
  - lib/datadog/ci/utils/file_storage.rb
270
280
  - lib/datadog/ci/utils/git.rb
271
281
  - lib/datadog/ci/utils/parsing.rb
272
282
  - lib/datadog/ci/utils/rum.rb
283
+ - lib/datadog/ci/utils/source_code.rb
273
284
  - lib/datadog/ci/utils/stateful.rb
274
285
  - lib/datadog/ci/utils/telemetry.rb
275
286
  - lib/datadog/ci/utils/test_run.rb
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../ext/telemetry"
4
- require_relative "../utils/telemetry"
5
-
6
- module Datadog
7
- module CI
8
- module ImpactedTestsDetection
9
- module Telemetry
10
- def self.impacted_test_detected
11
- Utils::Telemetry.inc(Ext::Telemetry::METRIC_IMPACTED_TESTS_IS_MODIFIED, 1)
12
- end
13
- end
14
- end
15
- end
16
- end