dev-cmd/determine-test-runner: add --all-supported

This commit is contained in:
Bo Anderson 2023-11-17 01:38:10 +00:00
parent 25d1f1064a
commit ca549fa10d
No known key found for this signature in database
GPG Key ID: 3DB94E204E137D65
3 changed files with 93 additions and 47 deletions

View File

@ -10,17 +10,23 @@ module Homebrew
def self.determine_test_runners_args def self.determine_test_runners_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
usage_banner <<~EOS usage_banner <<~EOS
`determine-test-runners` <testing-formulae> [<deleted-formulae>] `determine-test-runners` {<testing-formulae> [<deleted-formulae>]|--all-supported}
Determines the runners used to test formulae or their dependents. Determines the runners used to test formulae or their dependents. For internal use in Homebrew taps.
EOS EOS
switch "--all-supported",
description: "Instead of selecting runners based on the chosen formula, return all supported runners."
switch "--eval-all", switch "--eval-all",
description: "Evaluate all available formulae, whether installed or not, to determine testing " \ description: "Evaluate all available formulae, whether installed or not, to determine testing " \
"dependents." "dependents.",
env: :eval_all
switch "--dependents", switch "--dependents",
description: "Determine runners for testing dependents. Requires `--eval-all` or `HOMEBREW_EVAL_ALL`." description: "Determine runners for testing dependents. Requires `--eval-all` or `HOMEBREW_EVAL_ALL`.",
depends_on: "--eval-all"
named_args min: 1, max: 2 named_args max: 2
conflicts "--all-supported", "--dependents"
hide_from_man_page! hide_from_man_page!
end end
@ -30,16 +36,19 @@ module Homebrew
def self.determine_test_runners def self.determine_test_runners
args = determine_test_runners_args.parse args = determine_test_runners_args.parse
eval_all = args.eval_all? || Homebrew::EnvConfig.eval_all? if args.no_named? && !args.all_supported?
raise Homebrew::CLI::MinNamedArgumentsError, 1
elsif args.all_supported? && !args.no_named?
raise UsageError, "`--all-supported` is mutually exclusive to other arguments."
end
odie "`--dependents` requires `--eval-all` or `HOMEBREW_EVAL_ALL`!" if args.dependents? && !eval_all testing_formulae = args.named.first&.split(",").to_a
testing_formulae.map! { |name| TestRunnerFormula.new(Formulary.factory(name), eval_all: args.eval_all?) }
testing_formulae = args.named.first.split(",")
testing_formulae.map! { |name| TestRunnerFormula.new(Formulary.factory(name), eval_all: eval_all) }
.freeze .freeze
deleted_formulae = args.named.second&.split(",").freeze deleted_formulae = args.named.second&.split(",").to_a.freeze
runner_matrix = GitHubRunnerMatrix.new(testing_formulae, deleted_formulae,
runner_matrix = GitHubRunnerMatrix.new(testing_formulae, deleted_formulae, dependent_matrix: args.dependents?) all_supported: args.all_supported?,
dependent_matrix: args.dependents?)
runners = runner_matrix.active_runner_specs_hash runners = runner_matrix.active_runner_specs_hash
ohai "Runners", JSON.pretty_generate(runners) ohai "Runners", JSON.pretty_generate(runners)

View File

@ -7,9 +7,6 @@ require "github_runner"
class GitHubRunnerMatrix class GitHubRunnerMatrix
# FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed. # FIXME: Enable cop again when https://github.com/sorbet/sorbet/issues/3532 is fixed.
# rubocop:disable Style/MutableConstant # rubocop:disable Style/MutableConstant
MaybeStringArray = T.type_alias { T.nilable(T::Array[String]) }
private_constant :MaybeStringArray
RunnerSpec = T.type_alias { T.any(LinuxRunnerSpec, MacOSRunnerSpec) } RunnerSpec = T.type_alias { T.any(LinuxRunnerSpec, MacOSRunnerSpec) }
private_constant :RunnerSpec private_constant :RunnerSpec
@ -38,13 +35,19 @@ class GitHubRunnerMatrix
sig { sig {
params( params(
testing_formulae: T::Array[TestRunnerFormula], testing_formulae: T::Array[TestRunnerFormula],
deleted_formulae: MaybeStringArray, deleted_formulae: T::Array[String],
all_supported: T::Boolean,
dependent_matrix: T::Boolean, dependent_matrix: T::Boolean,
).void ).void
} }
def initialize(testing_formulae, deleted_formulae, dependent_matrix:) def initialize(testing_formulae, deleted_formulae, all_supported:, dependent_matrix:)
if all_supported && (testing_formulae.present? || deleted_formulae.present? || dependent_matrix)
raise ArgumentError, "all_supported is mutually exclusive to other arguments"
end
@testing_formulae = T.let(testing_formulae, T::Array[TestRunnerFormula]) @testing_formulae = T.let(testing_formulae, T::Array[TestRunnerFormula])
@deleted_formulae = T.let(deleted_formulae, MaybeStringArray) @deleted_formulae = T.let(deleted_formulae, T::Array[String])
@all_supported = T.let(all_supported, T::Boolean)
@dependent_matrix = T.let(dependent_matrix, T::Boolean) @dependent_matrix = T.let(dependent_matrix, T::Boolean)
@runners = T.let([], T::Array[GitHubRunner]) @runners = T.let([], T::Array[GitHubRunner])
@ -103,13 +106,16 @@ class GitHubRunnerMatrix
end end
NEWEST_GITHUB_ACTIONS_MACOS_RUNNER = :ventura NEWEST_GITHUB_ACTIONS_MACOS_RUNNER = :ventura
OLDEST_GITHUB_ACTIONS_MACOS_RUNNER = :big_sur
GITHUB_ACTIONS_RUNNER_TIMEOUT = 360 GITHUB_ACTIONS_RUNNER_TIMEOUT = 360
sig { void } sig { void }
def generate_runners! def generate_runners!
return if @runners.present? return if @runners.present?
if !@all_supported || ENV.key?("HOMEBREW_LINUX_RUNNER")
@runners << create_runner(:linux, :x86_64, linux_runner_spec) @runners << create_runner(:linux, :x86_64, linux_runner_spec)
end
github_run_id = ENV.fetch("GITHUB_RUN_ID") github_run_id = ENV.fetch("GITHUB_RUN_ID")
timeout = ENV.fetch("HOMEBREW_MACOS_TIMEOUT").to_i timeout = ENV.fetch("HOMEBREW_MACOS_TIMEOUT").to_i
@ -132,6 +138,7 @@ class GitHubRunnerMatrix
# Use GitHub Actions macOS Runner for testing dependents if compatible with timeout. # Use GitHub Actions macOS Runner for testing dependents if compatible with timeout.
runner, runner_timeout = if (@dependent_matrix || use_github_runner) && runner, runner_timeout = if (@dependent_matrix || use_github_runner) &&
macos_version <= NEWEST_GITHUB_ACTIONS_MACOS_RUNNER && macos_version <= NEWEST_GITHUB_ACTIONS_MACOS_RUNNER &&
macos_version >= OLDEST_GITHUB_ACTIONS_MACOS_RUNNER &&
runner_timeout <= GITHUB_ACTIONS_RUNNER_TIMEOUT runner_timeout <= GITHUB_ACTIONS_RUNNER_TIMEOUT
["macos-#{version}", GITHUB_ACTIONS_RUNNER_TIMEOUT] ["macos-#{version}", GITHUB_ACTIONS_RUNNER_TIMEOUT]
else else
@ -149,6 +156,7 @@ class GitHubRunnerMatrix
next if macos_version < :big_sur next if macos_version < :big_sur
runner = +"#{version}-arm64" runner = +"#{version}-arm64"
runner_timeout = timeout
# Use bare metal runner when testing dependents on ARM64 Monterey. # Use bare metal runner when testing dependents on ARM64 Monterey.
use_ephemeral = macos_version >= (@dependent_matrix ? :ventura : :monterey) use_ephemeral = macos_version >= (@dependent_matrix ? :ventura : :monterey)
@ -174,9 +182,7 @@ class GitHubRunnerMatrix
def active_runner?(runner) def active_runner?(runner)
if @dependent_matrix if @dependent_matrix
formulae_have_untested_dependents?(runner) formulae_have_untested_dependents?(runner)
else elsif !@all_supported && @deleted_formulae.empty?
return true if @deleted_formulae.present?
compatible_formulae = @testing_formulae.dup compatible_formulae = @testing_formulae.dup
platform = runner.platform platform = runner.platform
@ -191,6 +197,8 @@ class GitHubRunnerMatrix
end end
compatible_formulae.present? compatible_formulae.present?
else
true
end end
end end

View File

@ -31,7 +31,7 @@ describe GitHubRunnerMatrix do
describe "#active_runner_specs_hash" do describe "#active_runner_specs_hash" do
it "returns an object that responds to `#to_json`" do it "returns an object that responds to `#to_json`" do
expect( expect(
described_class.new([], ["deleted"], dependent_matrix: false) described_class.new([], ["deleted"], all_supported: false, dependent_matrix: false)
.active_runner_specs_hash .active_runner_specs_hash
.respond_to?(:to_json), .respond_to?(:to_json),
).to be(true) ).to be(true)
@ -40,7 +40,7 @@ describe GitHubRunnerMatrix do
describe "#generate_runners!" do describe "#generate_runners!" do
it "is idempotent" do it "is idempotent" do
matrix = described_class.new([], [], dependent_matrix: false) matrix = described_class.new([], [], all_supported: false, dependent_matrix: false)
runners = matrix.runners.dup runners = matrix.runners.dup
matrix.send(:generate_runners!) matrix.send(:generate_runners!)
@ -50,28 +50,39 @@ describe GitHubRunnerMatrix do
context "when there are no testing formulae and no deleted formulae" do context "when there are no testing formulae and no deleted formulae" do
it "activates no test runners" do it "activates no test runners" do
expect(described_class.new([], [], dependent_matrix: false).runners.any?(&:active)) expect(described_class.new([], [], all_supported: false, dependent_matrix: false).runners.any?(&:active))
.to be(false) .to be(false)
end end
it "activates no dependent runners" do it "activates no dependent runners" do
expect(described_class.new([], [], dependent_matrix: true).runners.any?(&:active)) expect(described_class.new([], [], all_supported: false, dependent_matrix: true).runners.any?(&:active))
.to be(false) .to be(false)
end end
end end
context "when passed `--all-supported`" do
it "activates all runners" do
expect(described_class.new([], [], all_supported: true, dependent_matrix: false).runners.all?(&:active))
.to be(true)
end
end
context "when there are testing formulae and no deleted formulae" do context "when there are testing formulae and no deleted formulae" do
context "when it is a matrix for the `tests` job" do context "when it is a matrix for the `tests` job" do
context "when testing formulae have no requirements" do context "when testing formulae have no requirements" do
it "activates all runners" do it "activates all runners" do
expect(described_class.new([testball], [], dependent_matrix: false).runners.all?(&:active)) expect(described_class.new([testball], [], all_supported: false, dependent_matrix: false)
.runners
.all?(&:active))
.to be(true) .to be(true)
end end
end end
context "when testing formulae require Linux" do context "when testing formulae require Linux" do
it "activates only the Linux runner" do it "activates only the Linux runner" do
runner_matrix = described_class.new([testball_depender_linux], [], dependent_matrix: false) runner_matrix = described_class.new([testball_depender_linux], [],
all_supported: false,
dependent_matrix: false)
expect(runner_matrix.runners.all?(&:active)).to be(false) expect(runner_matrix.runners.all?(&:active)).to be(false)
expect(runner_matrix.runners.any?(&:active)).to be(true) expect(runner_matrix.runners.any?(&:active)).to be(true)
@ -81,7 +92,9 @@ describe GitHubRunnerMatrix do
context "when testing formulae require macOS" do context "when testing formulae require macOS" do
it "activates only the macOS runners" do it "activates only the macOS runners" do
runner_matrix = described_class.new([testball_depender_macos], [], dependent_matrix: false) runner_matrix = described_class.new([testball_depender_macos], [],
all_supported: false,
dependent_matrix: false)
expect(runner_matrix.runners.all?(&:active)).to be(false) expect(runner_matrix.runners.all?(&:active)).to be(false)
expect(runner_matrix.runners.any?(&:active)).to be(true) expect(runner_matrix.runners.any?(&:active)).to be(true)
@ -91,7 +104,9 @@ describe GitHubRunnerMatrix do
context "when testing formulae require Intel" do context "when testing formulae require Intel" do
it "activates only the Intel runners" do it "activates only the Intel runners" do
runner_matrix = described_class.new([testball_depender_intel], [], dependent_matrix: false) runner_matrix = described_class.new([testball_depender_intel], [],
all_supported: false,
dependent_matrix: false)
expect(runner_matrix.runners.all?(&:active)).to be(false) expect(runner_matrix.runners.all?(&:active)).to be(false)
expect(runner_matrix.runners.any?(&:active)).to be(true) expect(runner_matrix.runners.any?(&:active)).to be(true)
@ -101,7 +116,9 @@ describe GitHubRunnerMatrix do
context "when testing formulae require ARM" do context "when testing formulae require ARM" do
it "activates only the ARM runners" do it "activates only the ARM runners" do
runner_matrix = described_class.new([testball_depender_arm], [], dependent_matrix: false) runner_matrix = described_class.new([testball_depender_arm], [],
all_supported: false,
dependent_matrix: false)
expect(runner_matrix.runners.all?(&:active)).to be(false) expect(runner_matrix.runners.all?(&:active)).to be(false)
expect(runner_matrix.runners.any?(&:active)).to be(true) expect(runner_matrix.runners.any?(&:active)).to be(true)
@ -112,7 +129,9 @@ describe GitHubRunnerMatrix do
context "when testing formulae require a macOS version" do context "when testing formulae require a macOS version" do
it "activates the Linux runner and suitable macOS runners" do it "activates the Linux runner and suitable macOS runners" do
_, v = newest_supported_macos _, v = newest_supported_macos
runner_matrix = described_class.new([testball_depender_newest], [], dependent_matrix: false) runner_matrix = described_class.new([testball_depender_newest], [],
all_supported: false,
dependent_matrix: false)
expect(runner_matrix.runners.all?(&:active)).to be(false) expect(runner_matrix.runners.all?(&:active)).to be(false)
expect(runner_matrix.runners.any?(&:active)).to be(true) expect(runner_matrix.runners.any?(&:active)).to be(true)
@ -127,7 +146,9 @@ describe GitHubRunnerMatrix do
allow(Homebrew::EnvConfig).to receive(:eval_all?).and_return(true) allow(Homebrew::EnvConfig).to receive(:eval_all?).and_return(true)
allow(Formula).to receive(:all).and_return([testball].map(&:formula)) allow(Formula).to receive(:all).and_return([testball].map(&:formula))
expect(described_class.new([testball], [], dependent_matrix: true).runners.any?(&:active)) expect(described_class.new([testball], [], all_supported: false, dependent_matrix: true)
.runners
.any?(&:active))
.to be(false) .to be(false)
end end
end end
@ -138,7 +159,9 @@ describe GitHubRunnerMatrix do
allow(Homebrew::EnvConfig).to receive(:eval_all?).and_return(true) allow(Homebrew::EnvConfig).to receive(:eval_all?).and_return(true)
allow(Formula).to receive(:all).and_return([testball, testball_depender].map(&:formula)) allow(Formula).to receive(:all).and_return([testball, testball_depender].map(&:formula))
expect(described_class.new([testball], [], dependent_matrix: true).runners.all?(&:active)) expect(described_class.new([testball], [], all_supported: false, dependent_matrix: true)
.runners
.all?(&:active))
.to be(true) .to be(true)
end end
end end
@ -148,7 +171,7 @@ describe GitHubRunnerMatrix do
allow(Homebrew::EnvConfig).to receive(:eval_all?).and_return(true) allow(Homebrew::EnvConfig).to receive(:eval_all?).and_return(true)
allow(Formula).to receive(:all).and_return([testball, testball_depender_linux].map(&:formula)) allow(Formula).to receive(:all).and_return([testball, testball_depender_linux].map(&:formula))
runner_matrix = described_class.new([testball], [], dependent_matrix: true) runner_matrix = described_class.new([testball], [], all_supported: false, dependent_matrix: true)
expect(runner_matrix.runners.all?(&:active)).to be(false) expect(runner_matrix.runners.all?(&:active)).to be(false)
expect(runner_matrix.runners.any?(&:active)).to be(true) expect(runner_matrix.runners.any?(&:active)).to be(true)
expect(get_runner_names(runner_matrix)).to eq(get_runner_names(runner_matrix, :linux?)) expect(get_runner_names(runner_matrix)).to eq(get_runner_names(runner_matrix, :linux?))
@ -160,7 +183,7 @@ describe GitHubRunnerMatrix do
allow(Homebrew::EnvConfig).to receive(:eval_all?).and_return(true) allow(Homebrew::EnvConfig).to receive(:eval_all?).and_return(true)
allow(Formula).to receive(:all).and_return([testball, testball_depender_macos].map(&:formula)) allow(Formula).to receive(:all).and_return([testball, testball_depender_macos].map(&:formula))
runner_matrix = described_class.new([testball], [], dependent_matrix: true) runner_matrix = described_class.new([testball], [], all_supported: false, dependent_matrix: true)
expect(runner_matrix.runners.all?(&:active)).to be(false) expect(runner_matrix.runners.all?(&:active)).to be(false)
expect(runner_matrix.runners.any?(&:active)).to be(true) expect(runner_matrix.runners.any?(&:active)).to be(true)
expect(get_runner_names(runner_matrix)).to eq(get_runner_names(runner_matrix, :macos?)) expect(get_runner_names(runner_matrix)).to eq(get_runner_names(runner_matrix, :macos?))
@ -172,7 +195,7 @@ describe GitHubRunnerMatrix do
allow(Homebrew::EnvConfig).to receive(:eval_all?).and_return(true) allow(Homebrew::EnvConfig).to receive(:eval_all?).and_return(true)
allow(Formula).to receive(:all).and_return([testball, testball_depender_intel].map(&:formula)) allow(Formula).to receive(:all).and_return([testball, testball_depender_intel].map(&:formula))
runner_matrix = described_class.new([testball], [], dependent_matrix: true) runner_matrix = described_class.new([testball], [], all_supported: false, dependent_matrix: true)
expect(runner_matrix.runners.all?(&:active)).to be(false) expect(runner_matrix.runners.all?(&:active)).to be(false)
expect(runner_matrix.runners.any?(&:active)).to be(true) expect(runner_matrix.runners.any?(&:active)).to be(true)
expect(get_runner_names(runner_matrix)).to eq(get_runner_names(runner_matrix, :x86_64?)) expect(get_runner_names(runner_matrix)).to eq(get_runner_names(runner_matrix, :x86_64?))
@ -184,7 +207,7 @@ describe GitHubRunnerMatrix do
allow(Homebrew::EnvConfig).to receive(:eval_all?).and_return(true) allow(Homebrew::EnvConfig).to receive(:eval_all?).and_return(true)
allow(Formula).to receive(:all).and_return([testball, testball_depender_arm].map(&:formula)) allow(Formula).to receive(:all).and_return([testball, testball_depender_arm].map(&:formula))
runner_matrix = described_class.new([testball], [], dependent_matrix: true) runner_matrix = described_class.new([testball], [], all_supported: false, dependent_matrix: true)
expect(runner_matrix.runners.all?(&:active)).to be(false) expect(runner_matrix.runners.all?(&:active)).to be(false)
expect(runner_matrix.runners.any?(&:active)).to be(true) expect(runner_matrix.runners.any?(&:active)).to be(true)
expect(get_runner_names(runner_matrix)).to eq(get_runner_names(runner_matrix, :arm64?)) expect(get_runner_names(runner_matrix)).to eq(get_runner_names(runner_matrix, :arm64?))
@ -197,7 +220,9 @@ describe GitHubRunnerMatrix do
context "when there are deleted formulae" do context "when there are deleted formulae" do
context "when it is a matrix for the `tests` job" do context "when it is a matrix for the `tests` job" do
it "activates all runners" do it "activates all runners" do
expect(described_class.new([], ["deleted"], dependent_matrix: false).runners.all?(&:active)) expect(described_class.new([], ["deleted"], all_supported: false, dependent_matrix: false)
.runners
.all?(&:active))
.to be(true) .to be(true)
end end
end end
@ -205,7 +230,9 @@ describe GitHubRunnerMatrix do
context "when it is a matrix for the `test_deps` job" do context "when it is a matrix for the `test_deps` job" do
context "when there are no testing formulae" do context "when there are no testing formulae" do
it "activates no runners" do it "activates no runners" do
expect(described_class.new([], ["deleted"], dependent_matrix: true).runners.any?(&:active)) expect(described_class.new([], ["deleted"], all_supported: false, dependent_matrix: true)
.runners
.any?(&:active))
.to be(false) .to be(false)
end end
end end
@ -213,7 +240,9 @@ describe GitHubRunnerMatrix do
context "when there are testing formulae with no dependents" do context "when there are testing formulae with no dependents" do
it "activates no runners" do it "activates no runners" do
testing_formulae = [testball] testing_formulae = [testball]
runner_matrix = described_class.new(testing_formulae, ["deleted"], dependent_matrix: true) runner_matrix = described_class.new(testing_formulae, ["deleted"],
all_supported: false,
dependent_matrix: true)
allow(Homebrew::EnvConfig).to receive(:eval_all?).and_return(true) allow(Homebrew::EnvConfig).to receive(:eval_all?).and_return(true)
allow(Formula).to receive(:all).and_return(testing_formulae.map(&:formula)) allow(Formula).to receive(:all).and_return(testing_formulae.map(&:formula))
@ -229,7 +258,9 @@ describe GitHubRunnerMatrix do
allow(Formula).to receive(:all).and_return([testball, testball_depender].map(&:formula)) allow(Formula).to receive(:all).and_return([testball, testball_depender].map(&:formula))
testing_formulae = [testball] testing_formulae = [testball]
expect(described_class.new(testing_formulae, ["deleted"], dependent_matrix: true).runners.all?(&:active)) expect(described_class.new(testing_formulae, ["deleted"], all_supported: false, dependent_matrix: true)
.runners
.all?(&:active))
.to be(true) .to be(true)
end end
end end
@ -240,8 +271,7 @@ describe GitHubRunnerMatrix do
allow(Homebrew::EnvConfig).to receive(:eval_all?).and_return(true) allow(Homebrew::EnvConfig).to receive(:eval_all?).and_return(true)
allow(Formula).to receive(:all).and_return([testball, testball_depender_linux].map(&:formula)) allow(Formula).to receive(:all).and_return([testball, testball_depender_linux].map(&:formula))
testing_formulae = [testball] matrix = described_class.new([testball], ["deleted"], all_supported: false, dependent_matrix: true)
matrix = described_class.new(testing_formulae, ["deleted"], dependent_matrix: true)
expect(get_runner_names(matrix)).to eq(["Linux"]) expect(get_runner_names(matrix)).to eq(["Linux"])
end end
end end
@ -251,8 +281,7 @@ describe GitHubRunnerMatrix do
allow(Homebrew::EnvConfig).to receive(:eval_all?).and_return(true) allow(Homebrew::EnvConfig).to receive(:eval_all?).and_return(true)
allow(Formula).to receive(:all).and_return([testball, testball_depender_macos].map(&:formula)) allow(Formula).to receive(:all).and_return([testball, testball_depender_macos].map(&:formula))
testing_formulae = [testball] matrix = described_class.new([testball], ["deleted"], all_supported: false, dependent_matrix: true)
matrix = described_class.new(testing_formulae, ["deleted"], dependent_matrix: true)
expect(get_runner_names(matrix)).to eq(get_runner_names(matrix, :macos?)) expect(get_runner_names(matrix)).to eq(get_runner_names(matrix, :macos?))
end end
end end