forked from Homebrew/homebrew-cask
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ci_matrix.rb
122 lines (98 loc) · 3.69 KB
/
ci_matrix.rb
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
# frozen_string_literal: true
require "cask/cask_loader"
require_relative "changed_files"
module CiMatrix
MAX_JOBS = 256
RUNNERS = {
{ symbol: :catalina, name: "macos-10.15" } => 0.9,
{ symbol: :big_sur, name: "macos-11.0" } => 0.1,
}.freeze
def self.filter_runners(cask_content)
# Retrieve arguments from `depends_on macos:`
args = case cask_content
when /depends_on macos: \[((.*,?\s*)*)\]/
Regexp.last_match(1).scan(/\s*"?:([^\s",]+)"?,?\s*/).flatten.map(&:to_sym)
when /depends_on macos: "?:([^\s"]+)"?/
[*Regexp.last_match(1).to_sym]
when /depends_on macos: "([=<>]=\s:?\S+)"/
[*Regexp.last_match(1)]
end
return RUNNERS if args.nil?
# Preform same checks as `brew install` would
required_macos = if args.count > 1
{ versions: args, comparator: "==" }
elsif MacOS::Version::SYMBOLS.key?(args.first)
{ versions: [args.first], comparator: "==" }
elsif /^\s*(?<comparator><|>|[=<>]=)\s*:?(?<version>\S+)\s*$/ =~ args.first
{ versions: [version.to_sym], comparator: comparator }
else # rubocop:disable Lint/DuplicateBranch
{ versions: [args.first], comparator: "==" }
end
# Filter
filtered_runners = RUNNERS.select do |runner, _|
required_macos[:versions].any? do |v|
MacOS::Version.from_symbol(runner[:symbol]).public_send(required_macos[:comparator], v)
end
end
return filtered_runners unless filtered_runners.empty?
RUNNERS
end
def self.random_runner(avalible_runners = RUNNERS)
avalible_runners.max_by { |(_, weight)| rand ** (1.0 / weight) }.first
end
def self.runners(path)
cask_content = path.read
filtered_runners = filter_runners(cask_content)
if cask_content.match?(/\bMacOS\s*\.version\b/m) &&
filtered_runners.keys.any? { |runner| cask_content.include?(runner[:symbol].inspect) }
# If the cask depends on `MacOS.version`, test it on every possible macOS version.
filtered_runners.keys
else
# Otherwise, select a runner based on weighted random sample.
[random_runner(filtered_runners)]
end
end
def self.generate(tap, labels: [])
odie "This command must be run from inside a tap directory." unless tap
tap.extend(ChangedFiles)
changed_files = tap.changed_files
ruby_files_in_wrong_directory =
changed_files[:modified_ruby_files] - (
changed_files[:modified_cask_files] +
changed_files[:modified_command_files] +
changed_files[:modified_github_actions_files]
)
if ruby_files_in_wrong_directory.any?
ruby_files_in_wrong_directory.each do |path|
puts "::error file=#{path}::File is in wrong directory."
end
odie "Found Ruby files in wrong directory:\n#{ruby_files_in_wrong_directory.join("\n")}"
end
modified_cask_files = changed_files[:modified_cask_files]
jobs = modified_cask_files.count
odie "Maximum job matrix size exceeded: #{jobs}/#{MAX_JOBS}" if jobs > MAX_JOBS
changed_files[:modified_cask_files].flat_map do |path|
cask_token = path.basename(".rb")
appcast_arg = if labels.include?("ci-skip-appcast")
"--no-appcast"
else
"--appcast"
end
audit_args = [appcast_arg, "--online"]
audit_args << "--new-cask" if changed_files[:added_files].include?(path)
runners(path).map do |runner|
{
name: "test #{cask_token} (#{runner[:name]})",
tap: tap.name,
cask: {
token: cask_token,
path: "./#{path}",
},
audit_args: audit_args,
skip_install: labels.include?("ci-skip-install"),
runner: runner[:name],
}
end
end
end
end