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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -2
- data/ext/datadog_ci_native/ci.c +10 -0
- data/ext/{datadog_cov → datadog_ci_native}/datadog_cov.c +119 -147
- data/ext/datadog_ci_native/datadog_cov.h +3 -0
- data/ext/datadog_ci_native/datadog_source_code.c +28 -0
- data/ext/datadog_ci_native/datadog_source_code.h +3 -0
- data/ext/{datadog_cov → datadog_ci_native}/extconf.rb +1 -1
- data/lib/datadog/ci/contrib/minitest/test.rb +17 -7
- data/lib/datadog/ci/contrib/rspec/example.rb +14 -7
- data/lib/datadog/ci/ext/telemetry.rb +1 -2
- data/lib/datadog/ci/ext/test.rb +1 -0
- data/lib/datadog/ci/git/base_branch_sha_detection/base.rb +66 -0
- data/lib/datadog/ci/git/base_branch_sha_detection/branch_metric.rb +34 -0
- data/lib/datadog/ci/git/base_branch_sha_detection/guesser.rb +137 -0
- data/lib/datadog/ci/git/base_branch_sha_detection/merge_base_extractor.rb +29 -0
- data/lib/datadog/ci/git/base_branch_sha_detector.rb +63 -0
- data/lib/datadog/ci/git/cli.rb +56 -0
- data/lib/datadog/ci/git/local_repository.rb +73 -294
- data/lib/datadog/ci/git/telemetry.rb +14 -0
- data/lib/datadog/ci/impacted_tests_detection/component.rb +0 -2
- data/lib/datadog/ci/test_optimisation/component.rb +10 -6
- data/lib/datadog/ci/test_optimisation/coverage/ddcov.rb +1 -1
- data/lib/datadog/ci/test_visibility/telemetry.rb +3 -0
- data/lib/datadog/ci/utils/command.rb +116 -0
- data/lib/datadog/ci/utils/source_code.rb +31 -0
- data/lib/datadog/ci/version.rb +1 -1
- metadata +16 -5
- 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
|
data/lib/datadog/ci/version.rb
CHANGED
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.
|
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/
|
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/
|
75
|
-
- ext/datadog_cov
|
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
|