Merge branch 'master' into no-ostruct

This commit is contained in:
Douglas Eichelberger 2024-12-10 11:00:32 -08:00 committed by GitHub
commit 69f2d3bf32
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 74 additions and 52 deletions

View File

@ -2,8 +2,6 @@ name: actionlint
on: on:
push: push:
branches:
- master
paths: paths:
- '.github/workflows/*.ya?ml' - '.github/workflows/*.ya?ml'
- '.github/actionlint.yaml' - '.github/actionlint.yaml'
@ -11,7 +9,6 @@ on:
paths: paths:
- '.github/workflows/*.ya?ml' - '.github/workflows/*.ya?ml'
- '.github/actionlint.yaml' - '.github/actionlint.yaml'
merge_group:
env: env:
HOMEBREW_DEVELOPER: 1 HOMEBREW_DEVELOPER: 1

View File

@ -2,9 +2,6 @@ name: Docker
on: on:
pull_request: pull_request:
push:
branches:
- master
merge_group: merge_group:
release: release:
types: types:
@ -75,7 +72,7 @@ jobs:
"homebrew/brew:latest" "homebrew/brew:latest"
) )
fi fi
elif [[ "${GITHUB_EVENT_NAME}" == "push" && elif [[ "${GITHUB_EVENT_NAME}" == "merge_group" &&
"${GITHUB_REF}" == "refs/heads/master" && "${GITHUB_REF}" == "refs/heads/master" &&
"${{ matrix.version }}" == "22.04" ]]; then "${{ matrix.version }}" == "22.04" ]]; then
tags+=( tags+=(

View File

@ -1,9 +1,6 @@
name: Documentation CI name: Documentation CI
on: on:
push:
branches:
- master
pull_request: pull_request:
merge_group: merge_group:

View File

@ -133,7 +133,7 @@ jobs:
fi fi
- name: Generate build provenance - name: Generate build provenance
uses: actions/attest-build-provenance@c4fbc648846ca6f503a13a2281a5e7b98aa57202 # v2.0.1 uses: actions/attest-build-provenance@7668571508540a607bdfd90a87a560489fe372eb # v2.1.0
with: with:
subject-path: Homebrew-${{ steps.homebrew-version.outputs.version }}.pkg subject-path: Homebrew-${{ steps.homebrew-version.outputs.version }}.pkg

View File

@ -1,9 +1,6 @@
name: CI name: CI
on: on:
push:
branches:
- master
pull_request: pull_request:
merge_group: merge_group:

View File

@ -468,9 +468,7 @@ module Cask
trashed = trashed.split(":") trashed = trashed.split(":")
untrashable = untrashable.split(":") untrashable = untrashable.split(":")
return trashed, untrashable if untrashable.empty? trashed_with_permissions, untrashable = untrashable.partition do |path|
untrashable.delete_if do |path|
Utils.gain_permissions(path, ["-R"], SystemCommand) do Utils.gain_permissions(path, ["-R"], SystemCommand) do
system_command! HOMEBREW_LIBRARY_PATH/"cask/utils/trash.swift", system_command! HOMEBREW_LIBRARY_PATH/"cask/utils/trash.swift",
args: [path], args: [path],
@ -482,6 +480,10 @@ module Cask
false false
end end
trashed += trashed_with_permissions
return trashed, untrashable if untrashable.empty?
opoo "The following files could not be trashed, please do so manually:" opoo "The following files could not be trashed, please do so manually:"
$stderr.puts untrashable $stderr.puts untrashable

View File

@ -4,6 +4,7 @@
require "abstract_command" require "abstract_command"
require "fileutils" require "fileutils"
require "tap" require "tap"
require "utils/uid"
module Homebrew module Homebrew
module DevCmd module DevCmd
@ -172,16 +173,32 @@ module Homebrew
write_path(tap, ".github/workflows/publish.yml", actions_publish) write_path(tap, ".github/workflows/publish.yml", actions_publish)
unless args.no_git? unless args.no_git?
cd tap.path do cd tap.path do |path|
Utils::Git.set_name_email! Utils::Git.set_name_email!
Utils::Git.setup_gpg! Utils::Git.setup_gpg!
# Would be nice to use --initial-branch here but it's not available in # Would be nice to use --initial-branch here but it's not available in
# older versions of Git that we support. # older versions of Git that we support.
safe_system "git", "-c", "init.defaultBranch=#{branch}", "init" safe_system "git", "-c", "init.defaultBranch=#{branch}", "init"
safe_system "git", "add", "--all"
safe_system "git", "commit", "-m", "Create #{tap} tap" args = []
safe_system "git", "branch", "-m", branch git_owner = File.stat(File.join(path, ".git")).uid
if git_owner != Process.uid && git_owner == Process.euid
# Under Homebrew user model, EUID is permitted to execute commands under the UID.
# Root users are never allowed (see brew.sh).
args << "-c" << "safe.directory=#{path}"
end
# Use the configuration of the original user, which will have author information and signing keys.
Utils::UID.drop_euid do
env = { HOME: Utils::UID.uid_home }.compact
env[:TMPDIR] = nil if (tmpdir = ENV.fetch("TMPDIR", nil)) && !File.writable?(tmpdir)
with_env(env) do
safe_system "git", *args, "add", "--all"
safe_system "git", *args, "commit", "-m", "Create #{tap} tap"
safe_system "git", *args, "branch", "-m", branch
end
end
end end
end end

View File

@ -2005,6 +2005,8 @@ class Formula
# If called with no parameters, does this with all compatible # If called with no parameters, does this with all compatible
# universal binaries in a {Formula}'s {Keg}. # universal binaries in a {Formula}'s {Keg}.
# #
# Raises an error if no universal binaries are found to deuniversalize.
#
# @api public # @api public
sig { params(targets: T.nilable(T.any(Pathname, String))).void } sig { params(targets: T.nilable(T.any(Pathname, String))).void }
def deuniversalize_machos(*targets) def deuniversalize_machos(*targets)
@ -2014,6 +2016,8 @@ class Formula
end end
end end
raise "No universal binaries found to deuniversalize" if targets.blank?
targets&.each do |target| targets&.each do |target|
extract_macho_slice_from(Pathname(target), Hardware::CPU.arch) extract_macho_slice_from(Pathname(target), Hardware::CPU.arch)
end end

View File

@ -58,8 +58,10 @@ module Homebrew
end end
# Parses JSON text and identifies versions using a `strategy` block. # Parses JSON text and identifies versions using a `strategy` block.
# If a regex is provided, it will be passed as the second argument to # If the block has two parameters, the parsed JSON data will be used as
# the `strategy` block (after the parsed JSON data). # the first argument and the regex (if any) will be the second.
# Otherwise, only the parsed JSON data will be passed to the block.
#
# @param content [String] the JSON text to parse and check # @param content [String] the JSON text to parse and check
# @param regex [Regexp, nil] a regex used for matching versions in the # @param regex [Regexp, nil] a regex used for matching versions in the
# content # content
@ -77,10 +79,8 @@ module Homebrew
json = parse_json(content) json = parse_json(content)
return [] if json.blank? return [] if json.blank?
block_return_value = if regex.present? block_return_value = if block.arity == 2
yield(json, regex) yield(json, regex)
elsif block.arity == 2
raise "Two arguments found in `strategy` block but no regex provided."
else else
yield(json) yield(json)
end end

View File

@ -20,10 +20,14 @@ module Homebrew
# The default `strategy` block used to extract version information when # The default `strategy` block used to extract version information when
# a `strategy` block isn't provided. # a `strategy` block isn't provided.
DEFAULT_BLOCK = T.let(proc do |json| DEFAULT_BLOCK = T.let(proc do |json, regex|
json.dig("info", "version").presence version = json.dig("info", "version")
next if version.blank?
regex ? version[regex, 1] : version
end.freeze, T.proc.params( end.freeze, T.proc.params(
arg0: T::Hash[String, T.untyped], json: T::Hash[String, T.untyped],
regex: T.nilable(Regexp),
).returns(T.nilable(String))) ).returns(T.nilable(String)))
# The `Regexp` used to extract the package name and suffix (e.g. file # The `Regexp` used to extract the package name and suffix (e.g. file

View File

@ -107,11 +107,6 @@ RSpec.describe Homebrew::Livecheck::Strategy::Json do
expect(json.versions_from_content(content_simple, regex) { next }).to eq([]) expect(json.versions_from_content(content_simple, regex) { next }).to eq([])
end end
it "errors if a block uses two arguments but a regex is not given" do
expect { json.versions_from_content(content_simple) { |json, regex| json["version"][regex, 1] } }
.to raise_error("Two arguments found in `strategy` block but no regex provided.")
end
it "errors on an invalid return type from a block" do it "errors on an invalid return type from a block" do
expect { json.versions_from_content(content_simple, regex) { 123 } } expect { json.versions_from_content(content_simple, regex) { 123 } }
.to raise_error(TypeError, Homebrew::Livecheck::Strategy::INVALID_BLOCK_RETURN_VALUE_MSG) .to raise_error(TypeError, Homebrew::Livecheck::Strategy::INVALID_BLOCK_RETURN_VALUE_MSG)

View File

@ -8,7 +8,7 @@ RSpec.describe Homebrew::Livecheck::Strategy::Pypi do
let(:pypi_url) { "https://files.pythonhosted.org/packages/ab/cd/efg/example-package-1.2.3.tar.gz" } let(:pypi_url) { "https://files.pythonhosted.org/packages/ab/cd/efg/example-package-1.2.3.tar.gz" }
let(:non_pypi_url) { "https://brew.sh/test" } let(:non_pypi_url) { "https://brew.sh/test" }
let(:regex) { /^v?(\d+(?:\.\d+)+)$/i } let(:regex) { /^v?(\d+(?:\.\d+)+)/i }
let(:generated) do let(:generated) do
{ {
@ -17,25 +17,26 @@ RSpec.describe Homebrew::Livecheck::Strategy::Pypi do
end end
# This is a limited subset of a PyPI JSON API response object, for the sake # This is a limited subset of a PyPI JSON API response object, for the sake
# of testing. # of testing. Typical versions use a `1.2.3` format but this adds a suffix,
# so we can test regex matching.
let(:content) do let(:content) do
<<~JSON <<~JSON
{ {
"info": { "info": {
"version": "1.2.3" "version": "1.2.3-456"
} }
} }
JSON JSON
end end
let(:matches) { ["1.2.3"] } let(:matches) { ["1.2.3-456"] }
let(:find_versions_return_hash) do let(:find_versions_return_hash) do
{ {
matches: { matches: {
"1.2.3" => Version.new("1.2.3"), "1.2.3-456" => Version.new("1.2.3-456"),
}, },
regex: nil, regex:,
url: generated[:url], url: generated[:url],
} }
end end
@ -76,10 +77,17 @@ RSpec.describe Homebrew::Livecheck::Strategy::Pypi do
{ {
cached:, cached:,
cached_default: cached.merge({ matches: {} }), cached_default: cached.merge({ matches: {} }),
cached_regex: cached.merge({
matches: { "1.2.3" => Version.new("1.2.3") },
regex:,
}),
} }
end end
it "finds versions in provided content" do it "finds versions in provided content" do
expect(pypi.find_versions(url: pypi_url, regex:, provided_content: content))
.to eq(match_data[:cached_regex])
expect(pypi.find_versions(url: pypi_url, provided_content: content)) expect(pypi.find_versions(url: pypi_url, provided_content: content))
.to eq(match_data[:cached]) .to eq(match_data[:cached])
end end
@ -92,7 +100,7 @@ RSpec.describe Homebrew::Livecheck::Strategy::Pypi do
next if match.blank? next if match.blank?
match[1] match[1]
end).to eq(match_data[:cached].merge({ regex: })) end).to eq(match_data[:cached_regex])
expect(pypi.find_versions(url: pypi_url, provided_content: content) do |json| expect(pypi.find_versions(url: pypi_url, provided_content: content) do |json|
json.dig("info", "version").presence json.dig("info", "version").presence
@ -100,10 +108,14 @@ RSpec.describe Homebrew::Livecheck::Strategy::Pypi do
end end
it "returns default match_data when block doesn't return version information" do it "returns default match_data when block doesn't return version information" do
no_match_regex = /will_not_match/i
expect(pypi.find_versions(url: pypi_url, provided_content: '{"info":{"version":""}}')) expect(pypi.find_versions(url: pypi_url, provided_content: '{"info":{"version":""}}'))
.to eq(match_data[:cached_default]) .to eq(match_data[:cached_default])
expect(pypi.find_versions(url: pypi_url, provided_content: '{"other":true}')) expect(pypi.find_versions(url: pypi_url, provided_content: '{"other":true}'))
.to eq(match_data[:cached_default]) .to eq(match_data[:cached_default])
expect(pypi.find_versions(url: pypi_url, regex: no_match_regex, provided_content: content))
.to eq(match_data[:cached_default].merge({ regex: no_match_regex }))
end end
it "returns default match_data when url is blank" do it "returns default match_data when url is blank" do

View File

@ -135,15 +135,6 @@ module GitHub
JSON::ParserError, JSON::ParserError,
].freeze ].freeze
sig { returns(T.nilable(String)) }
private_class_method def self.uid_home
require "etc"
Etc.getpwuid(Process.uid)&.dir
rescue ArgumentError
# Cover for misconfigured NSS setups
nil
end
# Gets the token from the GitHub CLI for github.com. # Gets the token from the GitHub CLI for github.com.
sig { returns(T.nilable(String)) } sig { returns(T.nilable(String)) }
def self.github_cli_token def self.github_cli_token
@ -152,7 +143,7 @@ module GitHub
# Avoid `Formula["gh"].opt_bin` so this method works even with `HOMEBREW_DISABLE_LOAD_FORMULA`. # Avoid `Formula["gh"].opt_bin` so this method works even with `HOMEBREW_DISABLE_LOAD_FORMULA`.
env = { env = {
"PATH" => PATH.new(HOMEBREW_PREFIX/"opt/gh/bin", ENV.fetch("PATH")), "PATH" => PATH.new(HOMEBREW_PREFIX/"opt/gh/bin", ENV.fetch("PATH")),
"HOME" => uid_home, "HOME" => Utils::UID.uid_home,
}.compact }.compact
gh_out, _, result = system_command "gh", gh_out, _, result = system_command "gh",
args: ["auth", "token", "--hostname", "github.com"], args: ["auth", "token", "--hostname", "github.com"],
@ -173,7 +164,7 @@ module GitHub
git_credential_out, _, result = system_command "git", git_credential_out, _, result = system_command "git",
args: ["credential-osxkeychain", "get"], args: ["credential-osxkeychain", "get"],
input: ["protocol=https\n", "host=github.com\n"], input: ["protocol=https\n", "host=github.com\n"],
env: { "HOME" => uid_home }.compact, env: { "HOME" => Utils::UID.uid_home }.compact,
print_stderr: false print_stderr: false
return unless result.success? return unless result.success?

View File

@ -15,5 +15,14 @@ module Utils
Process::Sys.seteuid(original_euid) Process::Sys.seteuid(original_euid)
end end
end end
sig { returns(T.nilable(String)) }
def self.uid_home
require "etc"
Etc.getpwuid(Process.uid)&.dir
rescue ArgumentError
# Cover for misconfigured NSS setups
nil
end
end end
end end