-
Notifications
You must be signed in to change notification settings - Fork 56
/
Copy pathmatrix_from_metadata_v2
executable file
·246 lines (214 loc) · 9.16 KB
/
matrix_from_metadata_v2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
#!/usr/bin/env ruby
# frozen_string_literal: true
# this script creates a build matrix for github actions from the claimed supported platforms and puppet versions in metadata.json
require 'json'
# Sets an output variable in GitHub Actions. If the GITHUB_OUTPUT environment
# variable is not set, this will fail with an exit code of 1 and
# send an ::error:: message to the GitHub Actions log.
# @param name [String] The name of the output variable
# @param value [String] The value of the output variable
def set_output(name, value)
# Get the output path
output = ENV.fetch('GITHUB_OUTPUT')
# Write the output variable to GITHUB_OUTPUT
File.open(output, 'a') do |f|
f.puts "#{name}=#{value}"
end
rescue KeyError
puts '::error::GITHUB_OUTPUT environment variable not set.'
exit 1
end
IMAGE_TABLE = {
'RedHat-7' => 'rhel-7',
'RedHat-8' => 'rhel-8',
'RedHat-9' => 'rhel-9',
'SLES-12' => 'sles-12',
'SLES-15' => 'sles-15',
'Windows-2016' => 'windows-2016',
'Windows-2019' => 'windows-2019',
'Windows-2022' => 'windows-2022'
}.freeze
ARM_IMAGE_TABLE = {
'Debian-12-arm' => 'debian-12-arm64',
'RedHat-9-arm' => 'rhel-9-arm64',
'Ubuntu-22.04-arm' => 'ubuntu-2204-lts-arm64',
'Ubuntu-24.04-arm' => 'ubuntu-2404-lts-arm64'
}.freeze
DOCKER_PLATFORMS = {
'AmazonLinux-2' => 'litmusimage/amazonlinux:2',
'AmazonLinux-2023' => 'litmusimage/amazonlinux:2023',
'CentOS-7' => 'litmusimage/centos:7',
'CentOS-8' => 'litmusimage/centos:stream8', # Support officaly moved to Stream8, metadata is being left as is
'CentOS-9' => 'litmusimage/centos:stream9',
'Rocky-8' => 'litmusimage/rockylinux:8',
'Rocky-9' => 'litmusimage/rockylinux:9',
'AlmaLinux-8' => 'litmusimage/almalinux:8',
'AlmaLinux-9' => 'litmusimage/almalinux:9',
'Debian-10' => 'litmusimage/debian:10',
'Debian-11' => 'litmusimage/debian:11',
'Debian-12' => 'litmusimage/debian:12',
'OracleLinux-7' => 'litmusimage/oraclelinux:7',
'OracleLinux-8' => 'litmusimage/oraclelinux:8',
'OracleLinux-9' => 'litmusimage/oraclelinux:9',
'Scientific-7' => 'litmusimage/scientificlinux:7',
'Ubuntu-18.04' => 'litmusimage/ubuntu:18.04',
'Ubuntu-20.04' => 'litmusimage/ubuntu:20.04',
'Ubuntu-22.04' => 'litmusimage/ubuntu:22.04',
'Ubuntu-24.04' => 'litmusimage/ubuntu:24.04'
}.freeze
# This table uses the latest version in each collection for accurate
# comparison when evaluating puppet requirements from the metadata
COLLECTION_TABLE = [
{
puppet_maj_version: 7,
ruby_version: 2.7
},
{
puppet_maj_version: 8,
ruby_version: 3.2
}
].freeze
matrix = {
platforms: [],
collection: []
}
spec_matrix = {
include: []
}
if ARGV.include?('--exclude-platforms')
exclude_platforms_occurencies = ARGV.count { |arg| arg == '--exclude-platforms' }
raise '--exclude-platforms argument should be present just one time in the command' unless exclude_platforms_occurencies <= 1
exclude_platforms_list = ARGV[ARGV.find_index('--exclude-platforms') + 1]
raise 'you need to provide a list of platforms in JSON format' if exclude_platforms_list.nil?
begin
exclude_list = JSON.parse(exclude_platforms_list).map(&:downcase)
rescue JSON::ParserError
raise 'the exclude platforms list must valid JSON'
end
else
exclude_list = []
end
# Force the use of the provision_service provisioner, if the --provision-service argument is present
if ARGV.include?('--provision-service')
provision_service_occurrences = ARGV.count { |arg| arg == '--provision-service' }
raise 'the --provision-service argument should be present just one time in the command' unless provision_service_occurrences <= 1
# NOTE: that the below are the only available images for the provision service
updated_platforms = {
'AlmaLinux-8' => 'almalinux-cloud/almalinux-8',
'AlmaLinux-9' => 'almalinux-cloud/almalinux-9',
'CentOS-7' => 'centos-7',
'CentOS-8' => 'centos-stream-8',
'CentOS-9' => 'centos-stream-9',
'Rocky-8' => 'rocky-linux-cloud/rocky-linux-8',
'Rocky-9' => 'rocky-linux-cloud/rocky-linux-9',
'Debian-10' => 'debian-10',
'Debian-11' => 'debian-11',
'Debian-12' => 'debian-12',
'Ubuntu-20.04' => 'ubuntu-2004-lts',
'Ubuntu-22.04' => 'ubuntu-2204-lts',
'Ubuntu-24.04' => 'ubuntu-2404-lts'
}
updated_list = IMAGE_TABLE.dup.clone
updated_list.merge!(updated_platforms)
IMAGE_TABLE = updated_list.freeze
DOCKER_PLATFORMS = {}.freeze
end
# disable provision service if repository owner is not puppetlabs
unless ['puppetlabs', nil].include?(ENV.fetch('GITHUB_REPOSITORY_OWNER', nil))
IMAGE_TABLE = {}.freeze
ARM_IMAGE_TABLE = {}.freeze
end
metadata_path = ENV['TEST_MATRIX_FROM_METADATA'] || 'metadata.json'
metadata = JSON.parse(File.read(metadata_path))
# Allow the user to pass a file containing a custom matrix
if ARGV.include?('--custom-matrix')
custom_matrix_occurrences = ARGV.count { |arg| arg == '--custom-matrix' }
raise '--custom-matrix argument should be present just one time in the command' unless custom_matrix_occurrences <= 1
file_path = ARGV[ARGV.find_index('--custom-matrix') + 1]
raise 'no file path specified' if file_path.nil?
begin
custom_matrix = JSON.parse(File.read(file_path))
rescue StandardError => e
case e
when JSON::ParserError
raise 'the matrix must be an array of valid JSON objects'
when Errno::ENOENT
raise "File not found: #{e.message}"
else
raise "An unknown exception occurred: #{e.message}"
end
end
custom_matrix.each do |platform|
matrix[:platforms] << platform
end
else
# Set platforms based on declared operating system support
metadata['operatingsystem_support'].sort_by { |a| a['operatingsystem'] }.each do |sup|
os = sup['operatingsystem']
sup['operatingsystemrelease'].sort_by(&:to_i).each do |ver|
image_key = "#{os}-#{ver}"
# Add ARM images if they exist and are not excluded
if ARM_IMAGE_TABLE.key?("#{image_key}-arm") && !exclude_list.include?("#{image_key.downcase}-arm")
matrix[:platforms] << {
label: "#{image_key}-arm",
provider: 'provision_service',
image: ARM_IMAGE_TABLE["#{image_key}-arm"]
}
end
if IMAGE_TABLE.key?(image_key) && !exclude_list.include?(image_key.downcase)
matrix[:platforms] << {
label: image_key,
provider: 'provision_service',
image: IMAGE_TABLE[image_key]
}
elsif DOCKER_PLATFORMS.key?(image_key) && !exclude_list.include?(image_key.downcase)
matrix[:platforms] << {
label: image_key,
provider: 'docker',
image: DOCKER_PLATFORMS[image_key]
}
else
puts "::warning::#{image_key} was excluded from testing" if exclude_list.include?(image_key.downcase)
puts "::warning::Cannot find image for #{image_key}" unless exclude_list.include?(image_key.downcase)
end
end
end
end
# Set collections based on puppet version requirements
if metadata.key?('requirements') && metadata['requirements'].length.positive?
metadata['requirements'].each do |req|
next unless req.key?('name') && req.key?('version_requirement') && req['name'] == 'puppet'
ver_regexp = /^([>=<]{1,2})\s*([\d.]+)\s+([>=<]{1,2})\s*([\d.]+)$/
match = ver_regexp.match(req['version_requirement'])
if match.nil?
puts "::warning::Didn't recognize version_requirement '#{req['version_requirement']}'"
break
end
cmp_one, ver_one, cmp_two, ver_two = match.captures
reqs = ["#{cmp_one} #{ver_one}", "#{cmp_two} #{ver_two}"]
COLLECTION_TABLE.each do |collection|
# Test against the "largest" puppet version in a collection, e.g. `7.9999` to allow puppet requirements with a non-zero lower bound on minor/patch versions.
# This assumes that such a boundary will always allow the latest actually existing puppet version of a release stream, trading off simplicity vs accuracy here.
next unless Gem::Requirement.create(reqs).satisfied_by?(Gem::Version.new("#{collection[:puppet_maj_version]}.9999"))
matrix[:collection] << "puppet#{collection[:puppet_maj_version]}-nightly"
include_version = {
8 => "~> #{collection[:puppet_maj_version]}.0",
7 => "~> #{collection[:puppet_maj_version]}.24",
6 => "~> #{collection[:puppet_maj_version]}.0"
}
spec_matrix[:include] << { puppet_version: include_version[collection[:puppet_maj_version]], ruby_version: collection[:ruby_version] }
end
end
end
# Set to defaults (all collections) if no matches are found
matrix[:collection] = COLLECTION_TABLE.map { |collection| "puppet#{collection[:puppet_maj_version]}-nightly" } if matrix[:collection].empty?
# Just to make sure there aren't any duplicates
matrix[:platforms] = matrix[:platforms].uniq.sort_by { |a| a[:label] } unless ARGV.include?('--custom-matrix')
matrix[:collection] = matrix[:collection].uniq.sort
set_output('matrix', JSON.generate(matrix))
set_output('spec_matrix', JSON.generate(spec_matrix))
acceptance_test_cell_count = matrix[:platforms].length * matrix[:collection].length
spec_test_cell_count = spec_matrix[:include].length
puts "Created matrix with #{acceptance_test_cell_count + spec_test_cell_count} cells:"
puts " - Acceptance Test Cells: #{acceptance_test_cell_count}"
puts " - Spec Test Cells: #{spec_test_cell_count}"