Skip to content

Commit 80e5120

Browse files
committed
Add Github Actions tests
1 parent 9c8d52b commit 80e5120

File tree

4 files changed

+325
-15
lines changed

4 files changed

+325
-15
lines changed

.github/workflows/test.yml

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# Please do NOT manually edit this file.
2+
# This file is generated by 'bundle exec rake github:actions:test_template'
3+
---
4+
name: Unit Tests
5+
'on':
6+
- push
7+
concurrency:
8+
group: "${{ github.workflow }}-${{ github.ref }}"
9+
cancel-in-progress: "${{ github.ref != 'refs/heads/master' }}"
10+
jobs:
11+
compute_tasks:
12+
runs-on: ubuntu-22.04
13+
strategy:
14+
fail-fast: false
15+
matrix:
16+
engine:
17+
- name: ruby
18+
version: '3.3'
19+
alias: ruby-33
20+
- name: ruby
21+
version: '3.2'
22+
alias: ruby-32
23+
container:
24+
image: ghcr.io/datadog/images-rb/engines/${{ matrix.engine.name }}:${{ matrix.engine.version }}
25+
outputs:
26+
ruby-33-matrix: "${{ steps.set-matrix.outputs.ruby-33 }}"
27+
ruby-32-matrix: "${{ steps.set-matrix.outputs.ruby-32 }}"
28+
steps:
29+
- uses: actions/checkout@v4
30+
- run: bundle install
31+
- id: set-matrix
32+
run: |
33+
matrix_json=$(bundle exec rake github:generate_matrix)
34+
# Debug output
35+
echo "Generated JSON:"
36+
echo "$matrix_json"
37+
# Set the output
38+
echo "${{ matrix.engine.alias }}=$(echo "$matrix_json")" >> $GITHUB_OUTPUT
39+
- uses: actions/upload-artifact@v4
40+
with:
41+
name: bundled-lock-${{ github.run_id }}-${{ matrix.engine.alias }}
42+
retention-days: 1
43+
path: 'Gemfile.lock
44+
45+
'
46+
test-ruby-33:
47+
name: 'ruby-3.3: ${{ matrix.task }} (${{ matrix.group }})'
48+
needs:
49+
- compute_tasks
50+
runs-on: ubuntu-22.04
51+
strategy:
52+
fail-fast: false
53+
matrix:
54+
include: "${{ fromJSON(needs.compute_tasks.outputs.ruby-33-matrix) }}"
55+
container:
56+
image: ghcr.io/datadog/images-rb/engines/ruby:3.3
57+
env:
58+
BUNDLE_GEMFILE: "${{ matrix.gemfile }}"
59+
steps:
60+
- uses: actions/checkout@v4
61+
- name: Configure Git
62+
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
63+
- uses: actions/download-artifact@v4
64+
with:
65+
name: bundled-lock-${{ github.run_id }}-ruby-33
66+
- run: bundle install && bundle exec rake compile_ext
67+
- name: Test ${{ matrix.task }} with ${{ matrix.gemfile }}
68+
run: bundle exec rake spec:${{ matrix.task }}
69+
test-ruby-32:
70+
name: 'ruby-3.2: ${{ matrix.task }} (${{ matrix.group }})'
71+
needs:
72+
- compute_tasks
73+
runs-on: ubuntu-22.04
74+
strategy:
75+
fail-fast: false
76+
matrix:
77+
include: "${{ fromJSON(needs.compute_tasks.outputs.ruby-32-matrix) }}"
78+
container:
79+
image: ghcr.io/datadog/images-rb/engines/ruby:3.2
80+
env:
81+
BUNDLE_GEMFILE: "${{ matrix.gemfile }}"
82+
steps:
83+
- uses: actions/checkout@v4
84+
- name: Configure Git
85+
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
86+
- uses: actions/download-artifact@v4
87+
with:
88+
name: bundled-lock-${{ github.run_id }}-ruby-32
89+
- run: bundle install && bundle exec rake compile_ext
90+
- name: Test ${{ matrix.task }} with ${{ matrix.gemfile }}
91+
run: bundle exec rake spec:${{ matrix.task }}

Rakefile

+15-15
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,6 @@ if Gem.loaded_specs.key? "ruby_memcheck"
2020
)
2121
end
2222

23-
RSpec::Core::RakeTask.new(:spec)
24-
25-
Dir.glob("tasks/*.rake").each { |r| import r }
26-
27-
YARD::Rake::YardocTask.new(:docs) do |t|
28-
# Options defined in `.yardopts` are read first, then merged with
29-
# options defined here.
30-
#
31-
# It's recommended to define options in `.yardopts` instead of here,
32-
# as `.yardopts` can be read by external YARD tools, like the
33-
# hot-reload YARD server `yard server --reload`.
34-
35-
t.options += ["--title", "datadog-ci #{Datadog::CI::VERSION} documentation"]
36-
end
37-
3823
# ADD NEW RUBIES HERE
3924
TEST_METADATA = {
4025
"main" => {
@@ -84,6 +69,21 @@ TEST_METADATA = {
8469
}
8570
}
8671

72+
RSpec::Core::RakeTask.new(:spec)
73+
74+
Dir.glob("tasks/*.rake").each { |r| import r }
75+
76+
YARD::Rake::YardocTask.new(:docs) do |t|
77+
# Options defined in `.yardopts` are read first, then merged with
78+
# options defined here.
79+
#
80+
# It's recommended to define options in `.yardopts` instead of here,
81+
# as `.yardopts` can be read by external YARD tools, like the
82+
# hot-reload YARD server `yard server --reload`.
83+
84+
t.options += ["--title", "datadog-ci #{Datadog::CI::VERSION} documentation"]
85+
end
86+
8787
namespace :test do
8888
task all: TEST_METADATA.map { |k, _| "test:#{k}" }
8989

tasks/appraisal_conversion.rb

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
require 'pathname'
2+
3+
# This module translates our custom mapping between appraisal and bundler.
4+
#
5+
# It cannot be included into `Appraisal` file, because it was invoked via `instance_eval`.
6+
module AppraisalConversion
7+
module_function
8+
9+
@gemfile_dir = 'gemfiles'
10+
@definition_dir = 'appraisal'
11+
12+
def to_bundle_gemfile(group)
13+
gemfile = "#{runtime_identifier}_#{group}.gemfile".tr('-', '_')
14+
path = root_path.join(gemfile_dir, gemfile)
15+
16+
if path.exist?
17+
path.to_s
18+
else
19+
raise "Gemfile not found at #{path}"
20+
end
21+
end
22+
23+
def definition
24+
path = root_path.join(@definition_dir, "#{runtime_identifier}.rb")
25+
26+
if path.exist?
27+
path.to_s
28+
else
29+
raise "Definition not found at #{path}"
30+
end
31+
end
32+
33+
def runtime_identifier
34+
major, minor, = Gem::Version.new(RUBY_ENGINE_VERSION).segments
35+
"#{RUBY_ENGINE}-#{major}.#{minor}"
36+
end
37+
38+
def gemfile_pattern
39+
root_path + gemfile_dir + "#{runtime_identifier.tr('-', '_')}_*.gemfile"
40+
end
41+
42+
def gemfile_dir
43+
@gemfile_dir
44+
end
45+
46+
def root_path
47+
Pathname.pwd
48+
end
49+
end

tasks/github.rake

+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
require 'json'
2+
require "psych"
3+
require 'ostruct'
4+
require_relative 'appraisal_conversion'
5+
6+
# rubocop:disable Metrics/BlockLength
7+
namespace :github do
8+
namespace :actions do
9+
task :test_template do |t|
10+
ubuntu = "ubuntu-22.04"
11+
12+
runtimes = [
13+
"ruby:3.3",
14+
"ruby:3.2",
15+
# "ruby:3.1",
16+
# "ruby:3.0",
17+
# "ruby:2.7",
18+
# "jruby:9.4",
19+
].map do |runtime|
20+
engine, version = runtime.split(':')
21+
runtime_alias = "#{engine}-#{version.gsub('.', '')}"
22+
23+
OpenStruct.new(
24+
"engine" => engine,
25+
"version" => version,
26+
"alias" => runtime_alias,
27+
"image" => "ghcr.io/datadog/images-rb/engines/#{engine}:#{version}"
28+
)
29+
end
30+
31+
test_jobs = runtimes.map do |runtime|
32+
{
33+
"test-#{runtime.alias}" => {
34+
"name" => "#{runtime.engine}-#{runtime.version}: ${{ matrix.task }} (${{ matrix.group }})",
35+
"needs" => ["compute_tasks"],
36+
"runs-on" => ubuntu,
37+
"strategy" => {
38+
"fail-fast" => false,
39+
"matrix" => {
40+
"include" => "${{ fromJSON(needs.compute_tasks.outputs.#{runtime.alias}-matrix) }}"
41+
}
42+
},
43+
"container" => {
44+
"image" => runtime.image,
45+
"env" => {
46+
"BUNDLE_GEMFILE" => "${{ matrix.gemfile }}"
47+
}
48+
},
49+
"steps" => [
50+
{ "uses" => "actions/checkout@v4" },
51+
{
52+
"name" => "Configure Git",
53+
"run" => 'git config --global --add safe.directory "$GITHUB_WORKSPACE"'
54+
},
55+
{
56+
"uses" => "actions/download-artifact@v4",
57+
"with" => {
58+
"name" => "bundled-lock-${{ github.run_id }}-#{runtime.alias}",
59+
}
60+
},
61+
{ "run" => "bundle install && bundle exec rake compile_ext" },
62+
{
63+
"name" => "Test ${{ matrix.task }} with ${{ matrix.gemfile }}",
64+
"run" => "bundle exec rake spec:${{ matrix.task }}"
65+
}
66+
]
67+
}
68+
}
69+
end
70+
71+
compute_tasks = {
72+
"runs-on" => ubuntu,
73+
"strategy" => {
74+
"fail-fast" => false,
75+
"matrix" => {
76+
"engine" => runtimes.map do |runtime|
77+
{ "name" => runtime.engine, "version" => runtime.version, "alias" => runtime.alias }
78+
end
79+
}
80+
},
81+
"container" =>{
82+
"image" => "ghcr.io/datadog/images-rb/engines/${{ matrix.engine.name }}:${{ matrix.engine.version }}"
83+
},
84+
"outputs" => runtimes.each_with_object({}) do |runtime, hash|
85+
hash["#{runtime.alias}-matrix"] = "${{ steps.set-matrix.outputs.#{runtime.alias} }}"
86+
end,
87+
"steps" => [
88+
{ "uses" => "actions/checkout@v4" },
89+
{ "run" => "bundle install" },
90+
{
91+
"id" => "set-matrix",
92+
"run" => <<~BASH
93+
matrix_json=$(bundle exec rake github:generate_matrix)
94+
# Debug output
95+
echo "Generated JSON:"
96+
echo "$matrix_json"
97+
# Set the output
98+
echo "${{ matrix.engine.alias }}=$(echo "$matrix_json")" >> $GITHUB_OUTPUT
99+
BASH
100+
},
101+
{
102+
"uses" => "actions/upload-artifact@v4",
103+
"with" => {
104+
"name" => "bundled-lock-${{ github.run_id }}-${{ matrix.engine.alias }}",
105+
"retention-days" => 1,
106+
"path" => <<~STRING
107+
Gemfile.lock
108+
STRING
109+
}
110+
},
111+
]
112+
}
113+
114+
base = {
115+
"name" => 'Unit Tests',
116+
"on" => ['push'],
117+
"concurrency" => {
118+
"group" => '${{ github.workflow }}-${{ github.ref }}',
119+
"cancel-in-progress" => '${{ github.ref != \'refs/heads/master\' }}'
120+
},
121+
"jobs" => {
122+
"compute_tasks" => compute_tasks,
123+
**test_jobs.reduce(&:merge)
124+
}
125+
}
126+
127+
# `Psych.dump` directly creates anchors, but Github Actions does not support anchors for YAML,
128+
# convert to JSON first to avoid anchors
129+
json = JSON.dump(base)
130+
yaml = Psych.safe_load(json)
131+
132+
string = +""
133+
string << <<~EOS
134+
# Please do NOT manually edit this file.
135+
# This file is generated by 'bundle exec rake #{t.name}'
136+
EOS
137+
string << Psych.dump(yaml, line_width: 120)
138+
File.binwrite(".github/workflows/test.yml", string)
139+
end
140+
end
141+
142+
task :generate_matrix do
143+
matrix = TEST_METADATA
144+
145+
ruby_version = RUBY_VERSION[0..2]
146+
array = []
147+
matrix.each do |key, spec_metadata|
148+
spec_metadata.each do |group, rubies|
149+
matched = if RUBY_PLATFORM == 'java'
150+
rubies.include?("✅ #{ruby_version}") && rubies.include?('✅ jruby')
151+
else
152+
rubies.include?("✅ #{ruby_version}")
153+
end
154+
155+
if matched
156+
gemfile = AppraisalConversion.to_bundle_gemfile(group) rescue "Gemfile"
157+
158+
array << {
159+
group: group,
160+
gemfile: gemfile,
161+
task: key
162+
}
163+
end
164+
end
165+
end
166+
167+
puts JSON.dump(array)
168+
end
169+
end
170+
# rubocop:enable Metrics/BlockLength

0 commit comments

Comments
 (0)