Homebrew 4.5 deprecations/disables/removals

The usual cycle of deprecating, disabling, and removing things in
Homebrew major/minor releases.
This commit is contained in:
Mike McQuaid 2025-04-22 17:15:23 +01:00
parent a47ff13114
commit c9a7b62b1d
No known key found for this signature in database
24 changed files with 58 additions and 236 deletions

View File

@ -18,8 +18,8 @@ defaults:
shell: bash -xeuo pipefail {0}
env:
# odeprecated: remove 18.04 image in Homebrew >=4.5
VERSIONS: '["18.04", "20.04", "22.04", "24.04"]'
# odeprecated: remove 20.04 image in Homebrew >=4.7
VERSIONS: '["20.04", "22.04", "24.04"]'
jobs:
generate-tags:
@ -146,12 +146,12 @@ jobs:
strategy:
fail-fast: false
matrix:
# odeprecated: remove 18.04 image in Homebrew >=4.5
version: ["18.04", "20.04", "22.04", "24.04"]
# odeprecated: remove 20.04 image in Homebrew >=4.7
version: ["20.04", "22.04", "24.04"]
arch: ["x86_64", "arm64"]
exclude:
# odeprecated: move this to 20.04 in Homebrew >=4.5 and remove 18.04 image
- version: "18.04"
# odeprecated: remove 20.04 image in Homebrew >=4.7
- version: "20.04"
arch: "arm64"
- arch: ${{ github.event_name == 'release' && 'arm64' }}
steps:
@ -175,9 +175,9 @@ jobs:
VERSION: ${{ matrix.version }}
PUSH: ${{ needs.generate-tags.outputs.push }}
run: |
# odeprecated: move this to 20.04 in Homebrew >=4.5 and remove 18.04 image
if [[ "${VERSION}" == "18.04" ]]; then
echo "The homebrew/ubuntu18.04 image is deprecated and will soon be retired. Use homebrew/ubuntu22.04 or homebrew/ubuntu24.04 or homebrew/brew." > .docker-deprecate
# odeprecated: remove 20.04 image in Homebrew >=4.7
if [[ "${VERSION}" == "20.04" ]]; then
echo "The homebrew/ubuntu20.04 image is deprecated and will soon be retired. Use homebrew/ubuntu24.04 or homebrew/brew." > .docker-deprecate
fi
filter="$(printf '.["%s"]' "${VERSION}")"
@ -206,8 +206,8 @@ jobs:
echo "HOMEBREW_ARM64_TESTING=1" >> "$GITHUB_ENV"
fi
# odeprecated: remove 18.04 in Homebrew >=4.5
if [[ "${VERSION}" == "18.04" || "${VERSION}" == "20.04" ]]; then
# odeprecated: remove 20.04 in Homebrew >=4.7
if [[ "${VERSION}" == "20.04" ]]; then
echo "HOMEBREW_GLIBC_TESTING=1" >> "$GITHUB_ENV"
fi
env:
@ -301,8 +301,8 @@ jobs:
done <<<"$(jq --raw-output "${filter}" <<<"${TAGS}")"
image_args=("ghcr.io/homebrew/ubuntu${VERSION}@sha256:$(<"${RUNNER_TEMP}/digests/${VERSION}-x86_64")")
# odeprecated: move this to 20.04 in Homebrew >=4.5 and remove 18.04 image
if [[ "${VERSION}" != 18.04 ]]; then
# odeprecated: remove 20.04 image in Homebrew >=4.7
if [[ "${VERSION}" != 20.04 ]]; then
image_args+=("ghcr.io/homebrew/ubuntu${VERSION}@sha256:$(<"${RUNNER_TEMP}/digests/${VERSION}-arm64")")
fi

View File

@ -37,7 +37,6 @@ Style/Documentation:
- formula.rb
- formula_assertions.rb
- formula_free_port.rb
- language/go.rb
- language/java.rb
- language/node.rb
- language/perl.rb

View File

@ -109,8 +109,6 @@ module Homebrew
ENV.each do |key, value|
match = key.match(/^HOMEBREW_BUNDLE_FORMULA_VERSION_(.+)$/)
# odeprecated: get rid of this in Homebrew >=4.5
match ||= key.match(/^HOMEBREW_BUNDLE_EXEC_FORMULA_VERSION_(.+)$/)
next if match.blank?
env_formula_name = match[1]

View File

@ -11,7 +11,7 @@ module Homebrew
def self.images
return [] unless Bundle.whalebrew_installed?
# odeprecated "`brew bundle` `whalebrew` support", "using `whalebrew` directly"
odeprecated "`brew bundle` `whalebrew` support", "using `whalebrew` directly"
@images ||= `whalebrew list 2>/dev/null`.split("\n")
.reject { |line| line.start_with?("COMMAND ") }
.map { |line| line.split(/\s+/).last }

View File

@ -24,7 +24,7 @@ module Homebrew
end
def self.install(name, preinstall: true, verbose: false, force: false, **_options)
# odeprecated "`brew bundle` `whalebrew` support", "using `whalebrew` directly"
odeprecated "`brew bundle` `whalebrew` support", "using `whalebrew` directly"
return true unless preinstall
puts "Installing #{name} image. It is not currently installed." if verbose

View File

@ -489,11 +489,6 @@ module Cask
@caveats
end
def discontinued?
odisabled "`discontinued?`", "`deprecated?` or `disabled?`"
@caveats&.discontinued? == true
end
# Asserts that the cask artifacts auto-update.
#
# @api public
@ -520,7 +515,7 @@ module Cask
# for `#livecheck_defined?`.
sig { returns(T::Boolean) }
def livecheckable?
# odeprecated "`livecheckable?`", "`livecheck_defined?`"
odeprecated "`livecheckable?`", "`livecheck_defined?`"
@livecheck_defined == true
end
@ -534,14 +529,12 @@ module Cask
raise ArgumentError, "more than one of replacement, replacement_formula and/or replacement_cask specified!"
end
# TODO: deprecate in >= 4.5.0
# if replacement
# odeprecated(
# "deprecate!(:replacement)",
# "deprecate!(:replacement_formula) or deprecate!(:replacement_cask)",
# disable_on: Time.new(2025, 10, 15),
# )
# end
if replacement
odeprecated(
"deprecate!(:replacement)",
"deprecate!(:replacement_formula) or deprecate!(:replacement_cask)",
)
end
@deprecation_date = Date.parse(date)
return if @deprecation_date > Date.today
@ -562,14 +555,12 @@ module Cask
raise ArgumentError, "more than one of replacement, replacement_formula and/or replacement_cask specified!"
end
# TODO: deprecate in >= 4.5.0
# if replacement
# odeprecated(
# "disable!(:replacement)",
# "disable!(:replacement_formula) or disable!(:replacement_cask)",
# disable_on: Time.new(2025, 10, 15),
# )
# end
if replacement
odeprecated(
"disable!(:replacement)",
"disable!(:replacement_formula) or disable!(:replacement_cask)",
)
end
@disable_date = Date.parse(date)

View File

@ -160,15 +160,6 @@ module Cask
EOS
end
caveat :discontinued do
odisabled "`caveats :discontinued`", "`deprecate!`"
@discontinued = true
<<~EOS
#{@cask} has been officially discontinued upstream.
It may stop working correctly (or at all) in recent versions of macOS.
EOS
end
caveat :license do |web_page|
<<~EOS
Installing #{@cask} means you have AGREED to the license at:

View File

@ -138,7 +138,7 @@ module Cask
@dsl = T.let(dsl, ::Cask::DSL)
@block = T.let(block, T.proc.params(arg0: T.all(String, PageWithURL)).returns(BlockReturn))
odeprecated "cask `url do` blocks" if @block
odisabled "cask `url do` blocks" if @block
end
sig { returns(BlockReturn) }

View File

@ -167,7 +167,7 @@ module Homebrew
@command_name = T.let(T.must(cmd_location.label).chomp("_args").tr("_", "-"), String)
@is_dev_cmd = T.let(T.must(cmd_location.absolute_path).start_with?(Commands::HOMEBREW_DEV_CMD_PATH),
T::Boolean)
odeprecated(
odisabled(
"`brew #{@command_name}'. This command needs to be refactored, as it is written in a style that",
"inherits from `Homebrew::AbstractCommand' ( see https://docs.brew.sh/External-Commands )",
disable_for_developers: false,

View File

@ -556,7 +556,7 @@ module Homebrew
falsy_values = %w[false no off nil 0]
if falsy_values.include?(env_value&.downcase)
odeprecated "#{env}=#{env_value}", <<~EOS.chomp
odisabled "#{env}=#{env_value}", <<~EOS.chomp
#{env}=1 to enable and #{env}= (an empty value) to disable
EOS
end

View File

@ -518,7 +518,7 @@ class Pathname
# create a RuboCop autocorrect instead soon.
# This is why monkeypatching is non-ideal (but right solution to get
# Ruby 3.3 over the line).
odeprecated "rmtree", "FileUtils#rm_r"
odisabled "rmtree", "FileUtils#rm_r"
FileUtils.rm_r(@path, noop:, verbose:, secure:)
nil
end

View File

@ -1173,44 +1173,6 @@ class Formula
@active_log_type = old_log_type
end
# This method can be overridden to provide a plist.
#
# ### Example
#
# ```ruby
# def plist; <<~EOS
# <?xml version="1.0" encoding="UTF-8"?>
# <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
# <plist version="1.0">
# <dict>
# <key>Label</key>
# <string>#{plist_name}</string>
# <key>ProgramArguments</key>
# <array>
# <string>#{opt_bin}/example</string>
# <string>--do-this</string>
# </array>
# <key>RunAtLoad</key>
# <true/>
# <key>KeepAlive</key>
# <true/>
# <key>StandardErrorPath</key>
# <string>/dev/null</string>
# <key>StandardOutPath</key>
# <string>/dev/null</string>
# </dict>
# </plist>
# EOS
# end
# ```
#
# @see https://www.unix.com/man-page/all/5/plist/ <code>plist(5)</code> man page
sig { returns(NilClass) }
def plist
odisabled "`Formula#plist`", "`Homebrew::Service`"
nil
end
# The generated launchd {.plist} service name.
sig { returns(String) }
def plist_name = service.plist_name
@ -2819,13 +2781,13 @@ class Formula
).returns(Pathname)
}
def fetch(verify_download_integrity: true, timeout: nil, quiet: false)
odeprecated "Formula#fetch", "Resource#fetch on Formula#resource"
odisabled "Formula#fetch", "Resource#fetch on Formula#resource"
active_spec.fetch(verify_download_integrity:, timeout:, quiet:)
end
sig { params(filename: T.any(Pathname, String)).void }
def verify_download_integrity(filename)
odeprecated "Formula#verify_download_integrity", "Resource#verify_download_integrity on Formula#resource"
odisabled "Formula#verify_download_integrity", "Resource#verify_download_integrity on Formula#resource"
active_spec.verify_download_integrity(filename)
end
@ -2936,8 +2898,8 @@ class Formula
def inreplace(paths, before = nil, after = nil, old_audit_result = nil, audit_result: true, global: true, &block)
# NOTE: must check for `#nil?` and not `#blank?`, or else `old_audit_result = false` will not call `odeprecated`.
unless old_audit_result.nil?
odeprecated "inreplace(paths, before, after, #{old_audit_result})",
"inreplace(paths, before, after, audit_result: #{old_audit_result})"
odisabled "inreplace(paths, before, after, #{old_audit_result})",
"inreplace(paths, before, after, audit_result: #{old_audit_result})"
audit_result = old_audit_result
end
Utils::Inreplace.inreplace(paths, before, after, audit_result:, global:, &block)
@ -3564,7 +3526,7 @@ class Formula
# and `false` otherwise.
sig { returns(T::Boolean) }
def livecheckable?
# odeprecated "`livecheckable?`", "`livecheck_defined?`"
odeprecated "`livecheckable?`", "`livecheck_defined?`"
@livecheck_defined == true
end
@ -3838,15 +3800,6 @@ class Formula
end
end
# Specify a Go resource.
#
# @api public
sig { params(name: String, block: T.nilable(T.proc.void)).void }
def go_resource(name, &block)
odisabled "`Formula.go_resource`", "Go modules"
specs.each { |spec| spec.go_resource(name, &block) }
end
# The dependencies for this formula. Use strings for the names of other
# formulae. Homebrew provides some `:special` {Requirement}s for stuff
# that needs extra handling (often changing some ENV vars or
@ -4358,14 +4311,12 @@ class Formula
raise ArgumentError, "more than one of replacement, replacement_formula and/or replacement_cask specified!"
end
# TODO: deprecate in >= 4.5.0
# if replacement
# odeprecated(
# "deprecate!(:replacement)",
# "deprecate!(:replacement_formula) or deprecate!(:replacement_cask)",
# disable_on: Time.new(2025, 10, 15),
# )
# end
if replacement
odeprecated(
"deprecate!(:replacement)",
"deprecate!(:replacement_formula) or deprecate!(:replacement_cask)",
)
end
@deprecation_date = T.let(Date.parse(date), T.nilable(Date))
return if T.must(@deprecation_date) > Date.today
@ -4451,14 +4402,12 @@ class Formula
raise ArgumentError, "more than one of replacement, replacement_formula and/or replacement_cask specified!"
end
# TODO: deprecate in >= 4.5.0
# if replacement
# odeprecated(
# "disable!(:replacement)",
# "disable!(:replacement_formula) or deprecate!(:replacement_cask)",
# disable_on: Time.new(2025, 10, 15),
# )
# end
if replacement
odeprecated(
"disable!(:replacement)",
"disable!(:replacement_formula) or deprecate!(:replacement_cask)",
)
end
@disable_date = T.let(Date.parse(date), T.nilable(Date))

View File

@ -23,7 +23,7 @@ class GitRepository
sig { returns(T::Boolean) }
def git_repo?
# delete this whole function when removing odisabled
odeprecated "GitRepository#git_repo?", "GitRepository#git_repository?"
odisabled "GitRepository#git_repo?", "GitRepository#git_repository?"
git_repository?
end

View File

@ -60,13 +60,7 @@ HOMEBREW_PULL_OR_COMMIT_URL_REGEX =
%r[https://github\.com/([\w-]+)/([\w-]+)?/(?:pull/(\d+)|commit/[0-9a-fA-F]{4,40})]
HOMEBREW_BOTTLES_EXTNAME_REGEX = /\.([a-z0-9_]+)\.bottle\.(?:(\d+)\.)?tar\.gz$/
# odeprecated: remove this in next major/minor release
require "fileutils"
module Homebrew
# odeprecated: remove this in next major/minor release
extend FileUtils
DEFAULT_PREFIX = T.let(ENV.fetch("HOMEBREW_DEFAULT_PREFIX").freeze, String)
DEFAULT_REPOSITORY = T.let(ENV.fetch("HOMEBREW_DEFAULT_REPOSITORY").freeze, String)
DEFAULT_CELLAR = "#{DEFAULT_PREFIX}/Cellar".freeze

View File

@ -1,28 +0,0 @@
# typed: strict
# frozen_string_literal: true
require "resource"
module Language
# Helper functions for Go formulae.
#
# @api public
module Go
# Given a set of resources, stages them to a gopath for
# building Go software.
# The resource names should be the import name of the package,
# e.g. `resource "github.com/foo/bar"`.
sig { params(resources: T::Array[Resource], target: T.any(String, Pathname)).void }
def self.stage_deps(resources, target)
odisabled "`Language::Go.stage_deps`", "Go modules"
if resources.empty?
if Homebrew::EnvConfig.developer?
odie "Tried to stage empty Language::Go resources array"
else
opoo "Tried to stage empty Language::Go resources array"
end
end
resources.grep(Resource::Go) { |resource| resource.stage(target) }
end
end
end

View File

@ -178,7 +178,7 @@ class Resource
# and `false` otherwise.
sig { returns(T::Boolean) }
def livecheckable?
# odeprecated "`livecheckable?`", "`livecheck_defined?`"
odeprecated "`livecheckable?`", "`livecheck_defined?`"
@livecheck_defined == true
end

View File

@ -43,11 +43,9 @@ module RuboCop
end
end
unless method_called_ever?(body_node, :go_resource)
# processed_source.ast is passed instead of body_node because `require` would be outside body_node
find_method_with_args(processed_source.ast, :require, "language/go") do
problem "require \"language/go\" is unnecessary unless using `go_resource`s"
end
# processed_source.ast is passed instead of body_node because `require` would be outside body_node
find_method_with_args(processed_source.ast, :require, "language/go") do
problem "require \"language/go\" is no longer necessary or correct"
end
find_instance_method_call(body_node, "Formula", :factory) do

View File

@ -154,11 +154,6 @@ class SoftwareSpec
end
end
def go_resource(name, &block)
odisabled "`SoftwareSpec#go_resource`", "Go modules"
resource name, Resource::Go, &block
end
def option_defined?(name)
options.include?(name)
end

View File

@ -162,7 +162,7 @@ class Tap
sig { returns(T::Boolean) }
def repo
# delete this whole function when removing odisabled
odeprecated "Tap#repo", "Tap#repository"
odisabled "Tap#repo", "Tap#repository"
repository
end
@ -284,7 +284,7 @@ class Tap
sig { returns(T.nilable(String)) }
def remote_repo
# delete this whole function when removing odisabled
odeprecated "Tap#remote_repo", "Tap#remote_repository"
odisabled "Tap#remote_repo", "Tap#remote_repository"
remote_repository
end
@ -306,7 +306,7 @@ class Tap
sig { returns(String) }
def repo_var_suffix
# delete this whole function when removing odisabled
odeprecated "Tap#repo_var_suffix", "Tap#repository_var_suffix"
odisabled "Tap#repo_var_suffix", "Tap#repository_var_suffix"
repository_var_suffix
end
@ -1080,14 +1080,6 @@ class Tap
end
end
# An array of all installed {Tap} names.
sig { returns(T::Array[String]) }
def self.names
odisabled "`#{self}.names`"
map(&:name).sort
end
# An array of official taps that have been manually untapped
sig { returns(T::Array[String]) }
def self.untapped_official_taps
@ -1189,13 +1181,6 @@ class AbstractCoreTap < Tap
super
end
sig { void }
def self.ensure_installed!
odisabled "`#{self}.ensure_installed!`", "`#{self}.instance.ensure_installed!`"
instance.ensure_installed!
end
sig { params(file: Pathname).returns(String) }
def formula_file_to_name(file)
file.basename(".rb").to_s

View File

@ -23,14 +23,12 @@ RSpec.describe Homebrew::Bundle::Commands::Install do
brew 'mysql', conflicts_with: ['mysql56']
cask 'phinze/cask/google-chrome', greedy: true
mas '1Password', id: 443987910
whalebrew 'whalebrew/wget'
vscode 'GitHub.codespaces'
EOS
end
it "does not raise an error" do
allow(Homebrew::Bundle::TapInstaller).to receive(:preinstall).and_return(false)
allow(Homebrew::Bundle::WhalebrewInstaller).to receive(:preinstall).and_return(false)
allow(Homebrew::Bundle::VscodeExtensionInstaller).to receive(:preinstall).and_return(false)
allow(Homebrew::Bundle::BrewInstaller).to receive_messages(preinstall: true, install: true)
allow(Homebrew::Bundle::CaskInstaller).to receive_messages(preinstall: true, install: true)
@ -41,7 +39,6 @@ RSpec.describe Homebrew::Bundle::Commands::Install do
it "#dsl returns a valid DSL" do
allow(Homebrew::Bundle::TapInstaller).to receive(:preinstall).and_return(false)
allow(Homebrew::Bundle::WhalebrewInstaller).to receive(:preinstall).and_return(false)
allow(Homebrew::Bundle::VscodeExtensionInstaller).to receive(:preinstall).and_return(false)
allow(Homebrew::Bundle::BrewInstaller).to receive_messages(preinstall: true, install: true)
allow(Homebrew::Bundle::CaskInstaller).to receive_messages(preinstall: true, install: true)
@ -65,7 +62,6 @@ RSpec.describe Homebrew::Bundle::Commands::Install do
allow(Homebrew::Bundle::CaskInstaller).to receive_messages(preinstall: true, install: false)
allow(Homebrew::Bundle::MacAppStoreInstaller).to receive_messages(preinstall: true, install: false)
allow(Homebrew::Bundle::TapInstaller).to receive_messages(preinstall: true, install: false)
allow(Homebrew::Bundle::WhalebrewInstaller).to receive_messages(preinstall: true, install: false)
allow(Homebrew::Bundle::VscodeExtensionInstaller).to receive_messages(preinstall: true, install: false)
allow_any_instance_of(Pathname).to receive(:read).and_return(brewfile_contents)
@ -77,7 +73,6 @@ RSpec.describe Homebrew::Bundle::Commands::Install do
allow(Homebrew::Bundle::TapInstaller).to receive_messages(preinstall: true, install: false)
allow(Homebrew::Bundle::BrewInstaller).to receive_messages(preinstall: true, install: true)
allow(Homebrew::Bundle::MacAppStoreInstaller).to receive_messages(preinstall: true, install: true)
allow(Homebrew::Bundle::WhalebrewInstaller).to receive_messages(preinstall: true, install: true)
allow(Homebrew::Bundle::VscodeExtensionInstaller).to receive_messages(preinstall: true, install: true)
allow_any_instance_of(Pathname).to receive(:read).and_return(brewfile_contents)

View File

@ -6,34 +6,6 @@ require "bundle/whalebrew_dumper"
RSpec.describe Homebrew::Bundle::WhalebrewDumper do
subject(:dumper) { described_class }
describe ".images" do
before do
dumper.reset!
allow(Homebrew::Bundle).to receive(:whalebrew_installed?).and_return(true)
end
let(:whalebrew_list_single_output) do
"COMMAND IMAGE\nwget whalebrew/wget"
end
let(:whalebrew_list_duplicate_output) do
"COMMAND IMAGE\nwget whalebrew/wget\nwget whalebrew/wget"
end
it "removes the header" do
allow(dumper).to receive(:`).with("whalebrew list 2>/dev/null")
.and_return(whalebrew_list_single_output)
expect(dumper.images).not_to include("COMMAND")
expect(dumper.images).not_to include("IMAGE")
end
it "dedupes items" do
allow(dumper).to receive(:`).with("whalebrew list 2>/dev/null")
.and_return(whalebrew_list_duplicate_output)
expect(dumper.images).to eq(["whalebrew/wget"])
end
end
context "when whalebrew is not installed" do
before do
dumper.reset!

View File

@ -31,17 +31,6 @@ RSpec.describe Homebrew::Bundle::WhalebrewInstaller do
expect(described_class.image_installed?("whalebrew/wget")).to be(true)
end
end
context "when an image isn't installed" do
before do
described_class.reset!
end
it "returns false" do
allow(Homebrew::Bundle::WhalebrewDumper).to receive(:images).and_return([])
expect(described_class.image_installed?("test/doesnotexist")).to be(false)
end
end
end
context "when whalebrew isn't installed" do
@ -75,10 +64,5 @@ RSpec.describe Homebrew::Bundle::WhalebrewInstaller do
expect(described_class.preinstall("whalebrew/wget")).to be(false)
end
end
it "successfully installs an image" do
expect(described_class.preinstall("whalebrew/wget")).to be(true)
expect { described_class.install("whalebrew/wget") }.not_to raise_error
end
end
end

View File

@ -140,7 +140,7 @@ RSpec.describe RuboCop::Cop::FormulaAudit::Text do
it 'reports an offense if `require "language/go"` is present' do
expect_offense(<<~RUBY)
require "language/go"
^^^^^^^^^^^^^^^^^^^^^ FormulaAudit/Text: require "language/go" is unnecessary unless using `go_resource`s
^^^^^^^^^^^^^^^^^^^^^ FormulaAudit/Text: require "language/go" is no longer necessary or correct
class Foo < Formula
url "https://brew.sh/foo-1.0.tgz"

View File

@ -167,7 +167,6 @@ RSpec.describe Homebrew::Services::FormulaWrapper do
allow(service).to receive_messages(installed?: true,
service_file: Pathname.new(File::NULL),
formula: instance_double(Formula,
plist: nil,
opt_prefix: Pathname.new("/dfslkfhjdsolshlk")))
expect(service.plist?).to be(false)
end