Skip to content

Commit 644dfa9

Browse files
committed
Make Cask CI generate correctly for partial arch dependencies
1 parent 1fe6567 commit 644dfa9

4 files changed

Lines changed: 290 additions & 14 deletions

File tree

Library/Homebrew/cask/artifact.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,7 @@ module Artifact
5252
::Cask::Artifact::VstPlugin,
5353
::Cask::Artifact::Vst3Plugin,
5454
].freeze
55+
56+
LINUX_ONLY_ARTIFACTS = [].freeze
5557
end
5658
end

Library/Homebrew/cask/cask.rb

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,12 +167,36 @@ def supports_macos? = true
167167
sig { returns(T::Boolean) }
168168
def supports_linux?
169169
return true if font?
170+
return false if contains_os_specific_artifacts?
170171

171-
return false if artifacts.any? do |artifact|
172-
::Cask::Artifact::MACOS_ONLY_ARTIFACTS.include?(artifact.class)
172+
@dsl.os.present?
173+
end
174+
175+
sig { returns(T::Boolean) }
176+
def contains_os_specific_artifacts?
177+
return false unless @dsl.on_system_blocks_exist?
178+
179+
any_loaded = false
180+
@contains_os_specific_artifacts ||= begin
181+
OnSystem::VALID_OS_ARCH_TAGS.each do |bottle_tag|
182+
Homebrew::SimulateSystem.with_tag(bottle_tag) do
183+
refresh
184+
185+
any_loaded = true if artifacts.any? do |artifact|
186+
(bottle_tag.linux? && ::Cask::Artifact::MACOS_ONLY_ARTIFACTS.include?(artifact.class)) ||
187+
(bottle_tag.macos? && ::Cask::Artifact::LINUX_ONLY_ARTIFACTS.include?(artifact.class))
188+
end
189+
end
190+
end
191+
192+
any_loaded
193+
rescue CaskInvalidError
194+
# Invalid cask
195+
ensure
196+
refresh
173197
end
174198

175-
@dsl.os.present?
199+
@contains_os_specific_artifacts
176200
end
177201

178202
# The caskfile is needed during installation when there are

Library/Homebrew/dev-cmd/generate-cask-ci-matrix.rb

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -139,21 +139,41 @@ def filter_runners(cask)
139139
RUNNERS.dup
140140
end
141141

142-
filtered_runners = filtered_runners.merge(LINUX_RUNNERS) if cask.supports_linux?
143-
144-
archs = architectures(cask:)
142+
macos_archs = architectures(cask:, os: :macos)
145143
filtered_runners.select! do |runner, _|
146-
archs.include?(runner.fetch(:arch))
144+
macos_archs.include?(runner.fetch(:arch))
145+
end
146+
147+
return filtered_runners unless cask.supports_linux?
148+
149+
linux_archs = architectures(cask:, os: :linux)
150+
linux_runners = LINUX_RUNNERS.select do |runner, _|
151+
linux_archs.include?(runner.fetch(:arch))
147152
end
148153

149-
filtered_runners
154+
filtered_runners.merge(linux_runners)
150155
end
151156

152-
sig { params(cask: Cask::Cask).returns(T::Array[Symbol]) }
153-
def architectures(cask:)
154-
return RUNNERS.keys.map { |r| r.fetch(:arch).to_sym }.uniq.sort if cask.depends_on.arch.blank?
157+
sig { params(cask: Cask::Cask, os: Symbol).returns(T::Array[Symbol]) }
158+
def architectures(cask:, os: :macos)
159+
architectures = []
160+
[:arm, :intel].each do |arch|
161+
tag = Utils::Bottles::Tag.new(system: os, arch: arch)
162+
Homebrew::SimulateSystem.with_tag(tag) do
163+
cask.refresh
164+
165+
if cask.depends_on.arch.blank?
166+
architectures = RUNNERS.keys.map { |r| r.fetch(:arch).to_sym }.uniq.sort
167+
next
168+
end
169+
170+
architectures = cask.depends_on.arch.map { |arch| arch[:type] }
171+
end
172+
rescue ::Cask::CaskInvalidError
173+
# Can't read cask for this system-arch combination.
174+
end
155175

156-
cask.depends_on.arch.map { |arch| arch[:type] }.uniq.sort
176+
architectures
157177
end
158178

159179
sig {
@@ -253,9 +273,9 @@ def generate_matrix(tap, labels: [], cask_names: [], skip_install: false, new_ca
253273
runners, multi_os = runners(cask:)
254274
runners.product(architectures(cask:)).filter_map do |runner, arch|
255275
native_runner_arch = arch == runner.fetch(:arch)
256-
# we don't need to run simulated archs on Linux
276+
# we don't need to run simulated archs on Linux or macOS Sequoia
277+
# because it has a GitHub hosted x86_64 runner
257278
next if runner.fetch(:symbol) == :linux && !native_runner_arch
258-
# we don't need to run simulated archs on macOS
259279
next if runner.fetch(:symbol) == :sequoia && !native_runner_arch
260280

261281
# If it's just a single OS test then we can just use the two real arch runners.

Library/Homebrew/test/dev-cmd/generate-cask-ci-matrix_spec.rb

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,235 @@
44
require "dev-cmd/generate-cask-ci-matrix"
55

66
RSpec.describe Homebrew::DevCmd::GenerateCaskCiMatrix do
7+
subject(:generate_matrix) { described_class.new(["test"]) }
8+
9+
let(:c_on_system_depends_on_mixed) do
10+
Cask::Cask.new("test-on-system-depends-on-mixed") do
11+
os macos: "darwin", linux: "linux"
12+
13+
version "0.0.1,2"
14+
15+
url "https://brew.sh/test-0.0.1.dmg"
16+
name "Test"
17+
desc "Test cask"
18+
homepage "https://brew.sh"
19+
20+
on_macos do
21+
depends_on arch: :x86_64
22+
end
23+
24+
on_linux do
25+
depends_on arch: :arm64
26+
end
27+
end
28+
end
29+
let(:c_on_macos_depends_on_intel) do
30+
Cask::Cask.new("test-on-macos-depends-on-intel") do
31+
os macos: "darwin", linux: "linux"
32+
33+
version "0.0.1,2"
34+
35+
url "https://brew.sh/test-0.0.1.dmg"
36+
name "Test"
37+
desc "Test cask"
38+
homepage "https://brew.sh"
39+
40+
on_macos do
41+
depends_on arch: :x86_64
42+
end
43+
end
44+
end
45+
let(:c_on_linux_depends_on_intel) do
46+
Cask::Cask.new("test-on-linux-depends-on-intel") do
47+
os macos: "darwin", linux: "linux"
48+
49+
version "0.0.1,2"
50+
51+
url "https://brew.sh/test-0.0.1.dmg"
52+
name "Test"
53+
desc "Test cask"
54+
homepage "https://brew.sh"
55+
56+
on_linux do
57+
depends_on arch: :x86_64
58+
end
59+
end
60+
end
61+
let(:c_on_system_depends_on_intel) do
62+
Cask::Cask.new("test-on-system-depends-on-intel") do
63+
os macos: "darwin", linux: "linux"
64+
65+
version "0.0.1,2"
66+
67+
url "https://brew.sh/test-0.0.1.dmg"
68+
name "Test"
69+
desc "Test cask"
70+
homepage "https://brew.sh"
71+
72+
depends_on arch: :x86_64
73+
end
74+
end
75+
let(:c_on_system) do
76+
Cask::Cask.new("test-on-system") do
77+
os macos: "darwin", linux: "linux"
78+
79+
version "0.0.1,2"
80+
81+
url "https://brew.sh/test-0.0.1.dmg"
82+
name "Test"
83+
desc "Test cask"
84+
homepage "https://brew.sh"
85+
end
86+
end
87+
let(:c_depends_macos_on_intel) do
88+
Cask::Cask.new("test-depends-on-intel") do
89+
version "0.0.1,2"
90+
91+
url "https://brew.sh/test-0.0.1.dmg"
92+
name "Test"
93+
desc "Test cask"
94+
homepage "https://brew.sh"
95+
96+
depends_on arch: :x86_64
97+
98+
app "Test.app"
99+
end
100+
end
101+
let(:c_app) do
102+
Cask::Cask.new("test-app") do
103+
version "0.0.1,2"
104+
105+
url "https://brew.sh/test-0.0.1.dmg"
106+
name "Test"
107+
desc "Test cask"
108+
homepage "https://brew.sh"
109+
110+
app "Test.app"
111+
end
112+
end
113+
let(:c_app_only_macos) do
114+
Cask::Cask.new("test-on-macos-guarded-stanza") do
115+
os macos: "darwin", linux: "linux"
116+
version "0.0.1,2"
117+
118+
url "https://brew.sh/test-0.0.1.dmg"
119+
name "Test"
120+
desc "Test cask"
121+
homepage "https://brew.sh"
122+
123+
on_macos do
124+
app "Test.app"
125+
end
126+
end
127+
end
128+
let(:c) do
129+
Cask::Cask.new("test-font") do
130+
version "0.0.1,2"
131+
132+
url "https://brew.sh/test-0.0.1.dmg"
133+
name "Test"
134+
desc "Test cask"
135+
homepage "https://brew.sh"
136+
137+
font "Test.ttf"
138+
end
139+
end
140+
let(:newest_macos) { MacOSVersion.new(HOMEBREW_MACOS_NEWEST_SUPPORTED).to_sym }
141+
7142
it_behaves_like "parseable arguments"
143+
144+
describe "::filter_runners" do
145+
# We simulate a macOS version older than the newest, as the method will use
146+
# the host macOS version instead of the default (the newest macOS version).
147+
let(:older_macos) { :big_sur }
148+
149+
context "when cask does not have on_system blocks/calls or `depends_on arch`" do
150+
it "returns an array including everything" do
151+
expect(generate_matrix.send(:filter_runners, c))
152+
.to eq({
153+
{ arch: :arm, name: "macos-14", symbol: :sonoma } => 0.0,
154+
{ arch: :arm, name: "macos-15", symbol: :sequoia } => 0.0,
155+
{ arch: :arm, name: "macos-26", symbol: :tahoe } => 1.0,
156+
{ arch: :arm, name: "ubuntu-22.04-arm", symbol: :linux } => 1.0,
157+
{ arch: :intel, name: "macos-15-intel", symbol: :sequoia } => 1.0,
158+
{ arch: :intel, name: "ubuntu-22.04", symbol: :linux } => 1.0,
159+
})
160+
161+
expect(generate_matrix.send(:filter_runners, c_app_only_macos))
162+
.to eq({
163+
{ arch: :arm, name: "macos-14", symbol: :sonoma } => 0.0,
164+
{ arch: :arm, name: "macos-15", symbol: :sequoia } => 0.0,
165+
{ arch: :arm, name: "macos-26", symbol: :tahoe } => 1.0,
166+
{ arch: :arm, name: "ubuntu-22.04-arm", symbol: :linux } => 1.0,
167+
{ arch: :intel, name: "macos-15-intel", symbol: :sequoia } => 1.0,
168+
{ arch: :intel, name: "ubuntu-22.04", symbol: :linux } => 1.0,
169+
})
170+
end
171+
end
172+
173+
context "when cask does not have on_system blocks/calls but has macOS specific stanza" do
174+
it "returns an array including all macOS" do
175+
expect(generate_matrix.send(:filter_runners, c_app))
176+
.to eq({
177+
{ arch: :arm, name: "macos-14", symbol: :sonoma } => 0.0,
178+
{ arch: :arm, name: "macos-15", symbol: :sequoia } => 0.0,
179+
{ arch: :arm, name: "macos-26", symbol: :tahoe } => 1.0,
180+
{ arch: :intel, name: "macos-15-intel", symbol: :sequoia } => 1.0,
181+
})
182+
end
183+
end
184+
185+
context "when cask does not have on_system blocks/calls but has `depends_on arch`" do
186+
it "returns an array only including macOS/`depends_on arch` value" do
187+
expect(generate_matrix.send(:filter_runners, c_depends_macos_on_intel))
188+
.to eq({ { arch: :intel, name: "macos-15-intel", symbol: :sequoia } => 1.0 })
189+
end
190+
end
191+
192+
context "when cask has on_system blocks/calls but does not have `depends_on arch`" do
193+
it "returns an array with combinations of OS and architectures" do
194+
expect(generate_matrix.send(:filter_runners, c_on_system))
195+
.to eq({
196+
{ arch: :arm, name: "macos-14", symbol: :sonoma } => 0.0,
197+
{ arch: :arm, name: "macos-15", symbol: :sequoia } => 0.0,
198+
{ arch: :arm, name: "macos-26", symbol: :tahoe } => 1.0,
199+
{ arch: :arm, name: "ubuntu-22.04-arm", symbol: :linux } => 1.0,
200+
{ arch: :intel, name: "macos-15-intel", symbol: :sequoia } => 1.0,
201+
{ arch: :intel, name: "ubuntu-22.04", symbol: :linux } => 1.0,
202+
})
203+
end
204+
end
205+
206+
context "when cask has on_system blocks/calls and `depends_on arch`" do
207+
it "returns an array with combinations of OS and `depends_on arch` value" do
208+
expect(generate_matrix.send(:filter_runners, c_on_system_depends_on_intel))
209+
.to eq({
210+
{ arch: :intel, name: "macos-15-intel", symbol: :sequoia } => 1.0,
211+
{ arch: :intel, name: "ubuntu-22.04", symbol: :linux } => 1.0,
212+
})
213+
214+
expect(generate_matrix.send(:filter_runners, c_on_linux_depends_on_intel))
215+
.to eq({
216+
{ arch: :arm, name: "macos-14", symbol: :sonoma } => 0.0,
217+
{ arch: :arm, name: "macos-15", symbol: :sequoia } => 0.0,
218+
{ arch: :arm, name: "macos-26", symbol: :tahoe } => 1.0,
219+
{ arch: :intel, name: "macos-15-intel", symbol: :sequoia } => 1.0,
220+
{ arch: :intel, name: "ubuntu-22.04", symbol: :linux } => 1.0,
221+
})
222+
223+
expect(generate_matrix.send(:filter_runners, c_on_macos_depends_on_intel))
224+
.to eq({
225+
{ arch: :intel, name: "macos-15-intel", symbol: :sequoia } => 1.0,
226+
{ arch: :intel, name: "ubuntu-22.04", symbol: :linux } => 1.0,
227+
{ arch: :arm, name: "ubuntu-22.04-arm", symbol: :linux } => 1.0,
228+
})
229+
230+
expect(generate_matrix.send(:filter_runners, c_on_system_depends_on_mixed))
231+
.to eq({
232+
{ arch: :arm, name: "ubuntu-22.04-arm", symbol: :linux } => 1.0,
233+
{ arch: :intel, name: "macos-15-intel", symbol: :sequoia } => 1.0,
234+
})
235+
end
236+
end
237+
end
8238
end

0 commit comments

Comments
 (0)