Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Library/Homebrew/cask/artifact.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,7 @@ module Artifact
::Cask::Artifact::VstPlugin,
::Cask::Artifact::Vst3Plugin,
].freeze

LINUX_ONLY_ARTIFACTS = [].freeze
end
end
33 changes: 30 additions & 3 deletions Library/Homebrew/cask/cask.rb
Original file line number Diff line number Diff line change
Expand Up @@ -167,12 +167,39 @@ def supports_macos? = true
sig { returns(T::Boolean) }
def supports_linux?
return true if font?
return false if contains_os_specific_artifacts?

return false if artifacts.any? do |artifact|
::Cask::Artifact::MACOS_ONLY_ARTIFACTS.include?(artifact.class)
@dsl.os.present?
end

sig { returns(T::Boolean) }
def contains_os_specific_artifacts?
return false unless @dsl.on_system_blocks_exist?

any_loaded = false
@contains_os_specific_artifacts ||= begin
OnSystem::VALID_OS_ARCH_TAGS.each do |bottle_tag|
begin
Homebrew::SimulateSystem.with_tag(bottle_tag) do
refresh

any_loaded = true if artifacts.any? do |artifact|
(bottle_tag.linux? && ::Cask::Artifact::MACOS_ONLY_ARTIFACTS.include?(artifact.class)) ||
(bottle_tag.macos? && ::Cask::Artifact::LINUX_ONLY_ARTIFACTS.include?(artifact.class))
end
end
rescue CaskInvalidError
# Invalid for this OS/arch tag; treat as having no OS-specific artifacts.
next
ensure
refresh
end
end

any_loaded
end

@dsl.os.present?
@contains_os_specific_artifacts
end

# The caskfile is needed during installation when there are
Expand Down
42 changes: 31 additions & 11 deletions Library/Homebrew/dev-cmd/generate-cask-ci-matrix.rb
Original file line number Diff line number Diff line change
Expand Up @@ -139,21 +139,41 @@ def filter_runners(cask)
RUNNERS.dup
end

filtered_runners = filtered_runners.merge(LINUX_RUNNERS) if cask.supports_linux?

archs = architectures(cask:)
macos_archs = architectures(cask:, os: :macos)
filtered_runners.select! do |runner, _|
archs.include?(runner.fetch(:arch))
macos_archs.include?(runner.fetch(:arch))
end

return filtered_runners unless cask.supports_linux?

linux_archs = architectures(cask:, os: :linux)
linux_runners = LINUX_RUNNERS.select do |runner, _|
linux_archs.include?(runner.fetch(:arch))
end

filtered_runners
filtered_runners.merge(linux_runners)
end

sig { params(cask: Cask::Cask).returns(T::Array[Symbol]) }
def architectures(cask:)
return RUNNERS.keys.map { |r| r.fetch(:arch).to_sym }.uniq.sort if cask.depends_on.arch.blank?
sig { params(cask: Cask::Cask, os: Symbol).returns(T::Array[Symbol]) }
def architectures(cask:, os: :macos)
architectures = []
[:arm, :intel].each do |arch|
tag = Utils::Bottles::Tag.new(system: os, arch: arch)
Homebrew::SimulateSystem.with_tag(tag) do
cask.refresh

if cask.depends_on.arch.blank?
architectures = RUNNERS.keys.map { |r| r.fetch(:arch).to_sym }.uniq.sort
next
end

architectures = cask.depends_on.arch.map { |arch| arch[:type] }
end
rescue ::Cask::CaskInvalidError
# Can't read cask for this system-arch combination.
end

cask.depends_on.arch.map { |arch| arch[:type] }.uniq.sort
architectures
end

sig {
Expand Down Expand Up @@ -253,9 +273,9 @@ def generate_matrix(tap, labels: [], cask_names: [], skip_install: false, new_ca
runners, multi_os = runners(cask:)
runners.product(architectures(cask:)).filter_map do |runner, arch|
native_runner_arch = arch == runner.fetch(:arch)
# we don't need to run simulated archs on Linux
# we don't need to run simulated archs on Linux or macOS Sequoia
# because they exist as real GitHub hosted runner
next if runner.fetch(:symbol) == :linux && !native_runner_arch
# we don't need to run simulated archs on macOS
next if runner.fetch(:symbol) == :sequoia && !native_runner_arch

# If it's just a single OS test then we can just use the two real arch runners.
Expand Down
230 changes: 230 additions & 0 deletions Library/Homebrew/test/dev-cmd/generate-cask-ci-matrix_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,235 @@
require "dev-cmd/generate-cask-ci-matrix"

RSpec.describe Homebrew::DevCmd::GenerateCaskCiMatrix do
subject(:generate_matrix) { described_class.new(["test"]) }

let(:c_on_system_depends_on_mixed) do
Cask::Cask.new("test-on-system-depends-on-mixed") do
os macos: "darwin", linux: "linux"

version "0.0.1,2"

url "https://brew.sh/test-0.0.1.dmg"
name "Test"
desc "Test cask"
homepage "https://brew.sh"

on_macos do
depends_on arch: :x86_64
end

on_linux do
depends_on arch: :arm64
end
end
end
let(:c_on_macos_depends_on_intel) do
Cask::Cask.new("test-on-macos-depends-on-intel") do
os macos: "darwin", linux: "linux"

version "0.0.1,2"

url "https://brew.sh/test-0.0.1.dmg"
name "Test"
desc "Test cask"
homepage "https://brew.sh"

on_macos do
depends_on arch: :x86_64
end
end
end
let(:c_on_linux_depends_on_intel) do
Cask::Cask.new("test-on-linux-depends-on-intel") do
os macos: "darwin", linux: "linux"

version "0.0.1,2"

url "https://brew.sh/test-0.0.1.dmg"
name "Test"
desc "Test cask"
homepage "https://brew.sh"

on_linux do
depends_on arch: :x86_64
end
end
end
let(:c_on_system_depends_on_intel) do
Cask::Cask.new("test-on-system-depends-on-intel") do
os macos: "darwin", linux: "linux"

version "0.0.1,2"

url "https://brew.sh/test-0.0.1.dmg"
name "Test"
desc "Test cask"
homepage "https://brew.sh"

depends_on arch: :x86_64
end
end
let(:c_on_system) do
Cask::Cask.new("test-on-system") do
os macos: "darwin", linux: "linux"

version "0.0.1,2"

url "https://brew.sh/test-0.0.1.dmg"
name "Test"
desc "Test cask"
homepage "https://brew.sh"
end
end
let(:c_depends_macos_on_intel) do
Cask::Cask.new("test-depends-on-intel") do
version "0.0.1,2"

url "https://brew.sh/test-0.0.1.dmg"
name "Test"
desc "Test cask"
homepage "https://brew.sh"

depends_on arch: :x86_64

app "Test.app"
end
end
let(:c_app) do
Cask::Cask.new("test-app") do
version "0.0.1,2"

url "https://brew.sh/test-0.0.1.dmg"
name "Test"
desc "Test cask"
homepage "https://brew.sh"

app "Test.app"
end
end
let(:c_app_only_macos) do
Cask::Cask.new("test-on-macos-guarded-stanza") do
os macos: "darwin", linux: "linux"
version "0.0.1,2"

url "https://brew.sh/test-0.0.1.dmg"
name "Test"
desc "Test cask"
homepage "https://brew.sh"

on_macos do
app "Test.app"
end
end
end
let(:c) do
Cask::Cask.new("test-font") do
version "0.0.1,2"

url "https://brew.sh/test-0.0.1.dmg"
name "Test"
desc "Test cask"
homepage "https://brew.sh"

font "Test.ttf"
end
end
let(:newest_macos) { MacOSVersion.new(HOMEBREW_MACOS_NEWEST_SUPPORTED).to_sym }

it_behaves_like "parseable arguments"

describe "::filter_runners" do
# We simulate a macOS version older than the newest, as the method will use
# the host macOS version instead of the default (the newest macOS version).
let(:older_macos) { :big_sur }

context "when cask does not have on_system blocks/calls or `depends_on arch`" do
it "returns an array including everything" do
expect(generate_matrix.send(:filter_runners, c))
.to eq({
{ arch: :arm, name: "macos-14", symbol: :sonoma } => 0.0,
{ arch: :arm, name: "macos-15", symbol: :sequoia } => 0.0,
{ arch: :arm, name: "macos-26", symbol: :tahoe } => 1.0,
{ arch: :arm, name: "ubuntu-22.04-arm", symbol: :linux } => 1.0,
{ arch: :intel, name: "macos-15-intel", symbol: :sequoia } => 1.0,
{ arch: :intel, name: "ubuntu-22.04", symbol: :linux } => 1.0,
})

expect(generate_matrix.send(:filter_runners, c_app_only_macos))
.to eq({
{ arch: :arm, name: "macos-14", symbol: :sonoma } => 0.0,
{ arch: :arm, name: "macos-15", symbol: :sequoia } => 0.0,
{ arch: :arm, name: "macos-26", symbol: :tahoe } => 1.0,
{ arch: :arm, name: "ubuntu-22.04-arm", symbol: :linux } => 1.0,
{ arch: :intel, name: "macos-15-intel", symbol: :sequoia } => 1.0,
{ arch: :intel, name: "ubuntu-22.04", symbol: :linux } => 1.0,
})
end
end

context "when cask does not have on_system blocks/calls but has macOS specific stanza" do
it "returns an array including all macOS" do
expect(generate_matrix.send(:filter_runners, c_app))
.to eq({
{ arch: :arm, name: "macos-14", symbol: :sonoma } => 0.0,
{ arch: :arm, name: "macos-15", symbol: :sequoia } => 0.0,
{ arch: :arm, name: "macos-26", symbol: :tahoe } => 1.0,
{ arch: :intel, name: "macos-15-intel", symbol: :sequoia } => 1.0,
})
end
end

context "when cask does not have on_system blocks/calls but has `depends_on arch`" do
it "returns an array only including macOS/`depends_on arch` value" do
expect(generate_matrix.send(:filter_runners, c_depends_macos_on_intel))
.to eq({ { arch: :intel, name: "macos-15-intel", symbol: :sequoia } => 1.0 })
end
end

context "when cask has on_system blocks/calls but does not have `depends_on arch`" do
it "returns an array with combinations of OS and architectures" do
expect(generate_matrix.send(:filter_runners, c_on_system))
.to eq({
{ arch: :arm, name: "macos-14", symbol: :sonoma } => 0.0,
{ arch: :arm, name: "macos-15", symbol: :sequoia } => 0.0,
{ arch: :arm, name: "macos-26", symbol: :tahoe } => 1.0,
{ arch: :arm, name: "ubuntu-22.04-arm", symbol: :linux } => 1.0,
{ arch: :intel, name: "macos-15-intel", symbol: :sequoia } => 1.0,
{ arch: :intel, name: "ubuntu-22.04", symbol: :linux } => 1.0,
})
end
end

context "when cask has on_system blocks/calls and `depends_on arch`" do
it "returns an array with combinations of OS and `depends_on arch` value" do
expect(generate_matrix.send(:filter_runners, c_on_system_depends_on_intel))
.to eq({
{ arch: :intel, name: "macos-15-intel", symbol: :sequoia } => 1.0,
{ arch: :intel, name: "ubuntu-22.04", symbol: :linux } => 1.0,
})

expect(generate_matrix.send(:filter_runners, c_on_linux_depends_on_intel))
.to eq({
{ arch: :arm, name: "macos-14", symbol: :sonoma } => 0.0,
{ arch: :arm, name: "macos-15", symbol: :sequoia } => 0.0,
{ arch: :arm, name: "macos-26", symbol: :tahoe } => 1.0,
{ arch: :intel, name: "macos-15-intel", symbol: :sequoia } => 1.0,
{ arch: :intel, name: "ubuntu-22.04", symbol: :linux } => 1.0,
})

expect(generate_matrix.send(:filter_runners, c_on_macos_depends_on_intel))
.to eq({
{ arch: :intel, name: "macos-15-intel", symbol: :sequoia } => 1.0,
{ arch: :intel, name: "ubuntu-22.04", symbol: :linux } => 1.0,
{ arch: :arm, name: "ubuntu-22.04-arm", symbol: :linux } => 1.0,
})

expect(generate_matrix.send(:filter_runners, c_on_system_depends_on_mixed))
.to eq({
{ arch: :arm, name: "ubuntu-22.04-arm", symbol: :linux } => 1.0,
{ arch: :intel, name: "macos-15-intel", symbol: :sequoia } => 1.0,
})
end
end
end
end
Loading