Add audit for livecheck in casks.
This commit is contained in:
parent
7331a9ba51
commit
f711352cfd
@ -4,6 +4,7 @@
|
|||||||
require "cask/denylist"
|
require "cask/denylist"
|
||||||
require "cask/download"
|
require "cask/download"
|
||||||
require "digest"
|
require "digest"
|
||||||
|
require "livecheck/livecheck"
|
||||||
require "utils/curl"
|
require "utils/curl"
|
||||||
require "utils/git"
|
require "utils/git"
|
||||||
require "utils/shared_audits"
|
require "utils/shared_audits"
|
||||||
@ -66,10 +67,11 @@ module Cask
|
|||||||
check_single_uninstall_zap
|
check_single_uninstall_zap
|
||||||
check_untrusted_pkg
|
check_untrusted_pkg
|
||||||
check_hosting_with_appcast
|
check_hosting_with_appcast
|
||||||
check_latest_with_appcast
|
check_latest_with_appcast_or_livecheck
|
||||||
check_latest_with_auto_updates
|
check_latest_with_auto_updates
|
||||||
check_stanza_requires_uninstall
|
check_stanza_requires_uninstall
|
||||||
check_appcast_contains_version
|
check_appcast_contains_version
|
||||||
|
check_livecheck_version
|
||||||
check_gitlab_repository
|
check_gitlab_repository
|
||||||
check_gitlab_repository_archived
|
check_gitlab_repository_archived
|
||||||
check_gitlab_prerelease_version
|
check_gitlab_prerelease_version
|
||||||
@ -274,11 +276,11 @@ module Cask
|
|||||||
add_error "cannot use the sha256 for an empty string: #{empty_sha256}"
|
add_error "cannot use the sha256 for an empty string: #{empty_sha256}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_latest_with_appcast
|
def check_latest_with_appcast_or_livecheck
|
||||||
return unless cask.version.latest?
|
return unless cask.version.latest?
|
||||||
return unless cask.appcast
|
|
||||||
|
|
||||||
add_error "Casks with an appcast should not use version :latest"
|
add_error "Casks with an appcast should not use version :latest" if cask.appcast
|
||||||
|
add_error "Casks with a livecheck should not use version :latest" if cask.livecheckable?
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_latest_with_auto_updates
|
def check_latest_with_auto_updates
|
||||||
@ -511,6 +513,18 @@ module Cask
|
|||||||
add_error "download not possible: #{e}"
|
add_error "download not possible: #{e}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def check_livecheck_version
|
||||||
|
return unless appcast?
|
||||||
|
return unless cask.livecheckable?
|
||||||
|
return if cask.livecheck.skip?
|
||||||
|
return if cask.version.latest?
|
||||||
|
|
||||||
|
latest_version = Homebrew::Livecheck.latest_version(cask)&.fetch(:latest)
|
||||||
|
return if cask.version.to_s == latest_version.to_s
|
||||||
|
|
||||||
|
add_error "Version '#{cask.version}' differs from '#{latest_version}' retrieved by livecheck."
|
||||||
|
end
|
||||||
|
|
||||||
def check_appcast_contains_version
|
def check_appcast_contains_version
|
||||||
return unless appcast?
|
return unless appcast?
|
||||||
return if cask.appcast.to_s.empty?
|
return if cask.appcast.to_s.empty?
|
||||||
|
|||||||
@ -24,6 +24,15 @@ module Homebrew
|
|||||||
sig { returns(T.nilable(T::Boolean)) }
|
sig { returns(T.nilable(T::Boolean)) }
|
||||||
def force_bottle?; end
|
def force_bottle?; end
|
||||||
|
|
||||||
|
sig { returns(T.nilable(T::Boolean)) }
|
||||||
|
def newer_only?; end
|
||||||
|
|
||||||
|
sig { returns(T.nilable(T::Boolean)) }
|
||||||
|
def full_name?; end
|
||||||
|
|
||||||
|
sig { returns(T.nilable(T::Boolean)) }
|
||||||
|
def json?; end
|
||||||
|
|
||||||
sig { returns(T.nilable(T::Boolean)) }
|
sig { returns(T.nilable(T::Boolean)) }
|
||||||
def debug?; end
|
def debug?; end
|
||||||
|
|
||||||
|
|||||||
@ -101,6 +101,15 @@ module Homebrew
|
|||||||
|
|
||||||
raise UsageError, "No formulae or casks to check." if formulae_and_casks_to_check.blank?
|
raise UsageError, "No formulae or casks to check." if formulae_and_casks_to_check.blank?
|
||||||
|
|
||||||
Livecheck.run_checks(formulae_and_casks_to_check, args)
|
options = {
|
||||||
|
json: args.json?,
|
||||||
|
full_name: args.full_name?,
|
||||||
|
newer_only: args.newer_only?,
|
||||||
|
quiet: args.quiet?,
|
||||||
|
debug: args.debug?,
|
||||||
|
verbose: args.verbose?,
|
||||||
|
}.compact
|
||||||
|
|
||||||
|
Livecheck.run_checks(formulae_and_casks_to_check, **options)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -12,6 +12,8 @@ module Homebrew
|
|||||||
#
|
#
|
||||||
# @api private
|
# @api private
|
||||||
module Livecheck
|
module Livecheck
|
||||||
|
extend T::Sig
|
||||||
|
|
||||||
module_function
|
module_function
|
||||||
|
|
||||||
GITEA_INSTANCES = %w[
|
GITEA_INSTANCES = %w[
|
||||||
@ -41,10 +43,25 @@ module Homebrew
|
|||||||
rc
|
rc
|
||||||
].freeze
|
].freeze
|
||||||
|
|
||||||
|
def livecheck_strategy_names
|
||||||
|
return @livecheck_strategy_names if defined?(@livecheck_strategy_names)
|
||||||
|
|
||||||
|
# Cache demodulized strategy names, to avoid repeating this work
|
||||||
|
@livecheck_strategy_names = {}
|
||||||
|
Strategy.constants.sort.each do |strategy_symbol|
|
||||||
|
strategy = Strategy.const_get(strategy_symbol)
|
||||||
|
@livecheck_strategy_names[strategy] = strategy.name.demodulize
|
||||||
|
end
|
||||||
|
@livecheck_strategy_names.freeze
|
||||||
|
end
|
||||||
|
|
||||||
# Executes the livecheck logic for each formula/cask in the
|
# Executes the livecheck logic for each formula/cask in the
|
||||||
# `formulae_and_casks_to_check` array and prints the results.
|
# `formulae_and_casks_to_check` array and prints the results.
|
||||||
# @return [nil]
|
# @return [nil]
|
||||||
def run_checks(formulae_and_casks_to_check, args)
|
def run_checks(
|
||||||
|
formulae_and_casks_to_check,
|
||||||
|
full_name: false, json: false, newer_only: false, debug: false, quiet: false, verbose: false
|
||||||
|
)
|
||||||
# Identify any non-homebrew/core taps in use for current formulae
|
# Identify any non-homebrew/core taps in use for current formulae
|
||||||
non_core_taps = {}
|
non_core_taps = {}
|
||||||
formulae_and_casks_to_check.each do |formula_or_cask|
|
formulae_and_casks_to_check.each do |formula_or_cask|
|
||||||
@ -62,17 +79,9 @@ module Homebrew
|
|||||||
Dir["#{tap_strategy_path}/*.rb"].sort.each(&method(:require)) if Dir.exist?(tap_strategy_path)
|
Dir["#{tap_strategy_path}/*.rb"].sort.each(&method(:require)) if Dir.exist?(tap_strategy_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Cache demodulized strategy names, to avoid repeating this work
|
|
||||||
@livecheck_strategy_names = {}
|
|
||||||
Strategy.constants.sort.each do |strategy_symbol|
|
|
||||||
strategy = Strategy.const_get(strategy_symbol)
|
|
||||||
@livecheck_strategy_names[strategy] = strategy.name.demodulize
|
|
||||||
end
|
|
||||||
@livecheck_strategy_names.freeze
|
|
||||||
|
|
||||||
has_a_newer_upstream_version = false
|
has_a_newer_upstream_version = false
|
||||||
|
|
||||||
if args.json? && !args.quiet? && $stderr.tty?
|
if json && !quiet && $stderr.tty?
|
||||||
formulae_and_casks_total = if formulae_and_casks_to_check == Formula
|
formulae_and_casks_total = if formulae_and_casks_to_check == Formula
|
||||||
formulae_and_casks_to_check.count
|
formulae_and_casks_to_check.count
|
||||||
else
|
else
|
||||||
@ -96,7 +105,7 @@ module Homebrew
|
|||||||
formula = formula_or_cask if formula_or_cask.is_a?(Formula)
|
formula = formula_or_cask if formula_or_cask.is_a?(Formula)
|
||||||
cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask)
|
cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask)
|
||||||
|
|
||||||
if args.debug? && i.positive?
|
if debug && i.positive?
|
||||||
puts <<~EOS
|
puts <<~EOS
|
||||||
|
|
||||||
----------
|
----------
|
||||||
@ -104,7 +113,7 @@ module Homebrew
|
|||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
skip_result = skip_conditions(formula_or_cask, args: args)
|
skip_result = skip_conditions(formula_or_cask, json: json, full_name: full_name, quiet: quiet)
|
||||||
next skip_result if skip_result != false
|
next skip_result if skip_result != false
|
||||||
|
|
||||||
formula&.head&.downloader&.shutup!
|
formula&.head&.downloader&.shutup!
|
||||||
@ -126,17 +135,20 @@ module Homebrew
|
|||||||
latest = if formula&.head_only?
|
latest = if formula&.head_only?
|
||||||
formula.head.downloader.fetch_last_commit
|
formula.head.downloader.fetch_last_commit
|
||||||
else
|
else
|
||||||
version_info = latest_version(formula_or_cask, args: args)
|
version_info = latest_version(
|
||||||
|
formula_or_cask,
|
||||||
|
json: json, full_name: full_name, verbose: verbose, debug: debug,
|
||||||
|
)
|
||||||
version_info[:latest] if version_info.present?
|
version_info[:latest] if version_info.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
if latest.blank?
|
if latest.blank?
|
||||||
no_versions_msg = "Unable to get versions"
|
no_versions_msg = "Unable to get versions"
|
||||||
raise TypeError, no_versions_msg unless args.json?
|
raise TypeError, no_versions_msg unless json
|
||||||
|
|
||||||
next version_info if version_info.is_a?(Hash) && version_info[:status] && version_info[:messages]
|
next version_info if version_info.is_a?(Hash) && version_info[:status] && version_info[:messages]
|
||||||
|
|
||||||
next status_hash(formula_or_cask, "error", [no_versions_msg], args: args)
|
next status_hash(formula_or_cask, "error", [no_versions_msg], full_name: full_name, verbose: verbose)
|
||||||
end
|
end
|
||||||
|
|
||||||
if (m = latest.to_s.match(/(.*)-release$/)) && !current.to_s.match(/.*-release$/)
|
if (m = latest.to_s.match(/(.*)-release$/)) && !current.to_s.match(/.*-release$/)
|
||||||
@ -154,8 +166,8 @@ module Homebrew
|
|||||||
is_newer_than_upstream = (formula&.stable? || cask) && (current > latest)
|
is_newer_than_upstream = (formula&.stable? || cask) && (current > latest)
|
||||||
|
|
||||||
info = {}
|
info = {}
|
||||||
info[:formula] = formula_name(formula, args: args) if formula
|
info[:formula] = formula_name(formula, full_name: full_name) if formula
|
||||||
info[:cask] = cask_name(cask, args: args) if cask
|
info[:cask] = cask_name(cask, full_name: full_name) if cask
|
||||||
info[:version] = {
|
info[:version] = {
|
||||||
current: current.to_s,
|
current: current.to_s,
|
||||||
latest: latest.to_s,
|
latest: latest.to_s,
|
||||||
@ -168,35 +180,33 @@ module Homebrew
|
|||||||
info[:meta][:head_only] = true if formula&.head_only?
|
info[:meta][:head_only] = true if formula&.head_only?
|
||||||
info[:meta].merge!(version_info[:meta]) if version_info.present? && version_info.key?(:meta)
|
info[:meta].merge!(version_info[:meta]) if version_info.present? && version_info.key?(:meta)
|
||||||
|
|
||||||
next if args.newer_only? && !info[:version][:outdated]
|
next if newer_only && !info[:version][:outdated]
|
||||||
|
|
||||||
has_a_newer_upstream_version ||= true
|
has_a_newer_upstream_version ||= true
|
||||||
|
|
||||||
if args.json?
|
if json
|
||||||
progress&.increment
|
progress&.increment
|
||||||
info.except!(:meta) unless args.verbose?
|
info.except!(:meta) unless verbose
|
||||||
next info
|
next info
|
||||||
end
|
end
|
||||||
|
|
||||||
print_latest_version(info, args: args)
|
print_latest_version(info, verbose: verbose)
|
||||||
nil
|
nil
|
||||||
rescue => e
|
rescue => e
|
||||||
Homebrew.failed = true
|
Homebrew.failed = true
|
||||||
|
|
||||||
if args.json?
|
if json
|
||||||
progress&.increment
|
progress&.increment
|
||||||
status_hash(formula_or_cask, "error", [e.to_s], args: args)
|
status_hash(formula_or_cask, "error", [e.to_s], full_name: full_name, verbose: verbose)
|
||||||
elsif !args.quiet?
|
elsif !quiet
|
||||||
onoe "#{Tty.blue}#{formula_or_cask_name(formula_or_cask, args: args)}#{Tty.reset}: #{e}"
|
onoe "#{Tty.blue}#{formula_or_cask_name(formula_or_cask, full_name: full_name)}#{Tty.reset}: #{e}"
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if args.newer_only? && !has_a_newer_upstream_version && !args.debug? && !args.json?
|
puts "No newer upstream versions." if newer_only && !has_a_newer_upstream_version && !debug && !json
|
||||||
puts "No newer upstream versions."
|
|
||||||
end
|
|
||||||
|
|
||||||
return unless args.json?
|
return unless json
|
||||||
|
|
||||||
if progress
|
if progress
|
||||||
progress.finish
|
progress.finish
|
||||||
@ -208,45 +218,47 @@ module Homebrew
|
|||||||
puts JSON.generate(formulae_checked.compact)
|
puts JSON.generate(formulae_checked.compact)
|
||||||
end
|
end
|
||||||
|
|
||||||
def formula_or_cask_name(formula_or_cask, args:)
|
sig { params(formula_or_cask: T.any(Formula, Cask::Cask), full_name: T::Boolean).returns(String) }
|
||||||
|
def formula_or_cask_name(formula_or_cask, full_name: false)
|
||||||
case formula_or_cask
|
case formula_or_cask
|
||||||
when Formula
|
when Formula
|
||||||
formula_name(formula_or_cask, args: args)
|
formula_name(formula_or_cask, full_name: full_name)
|
||||||
when Cask::Cask
|
when Cask::Cask
|
||||||
cask_name(formula_or_cask, args: args)
|
cask_name(formula_or_cask, full_name: full_name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def cask_name(cask, args:)
|
# Returns the fully-qualified name of a cask if the `full_name` argument is
|
||||||
args.full_name? ? cask.full_name : cask.token
|
# provided; returns the name otherwise.
|
||||||
|
sig { params(cask: Cask::Cask, full_name: T::Boolean).returns(String) }
|
||||||
|
def cask_name(cask, full_name: false)
|
||||||
|
full_name ? cask.full_name : cask.token
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the fully-qualified name of a formula if the `full_name` argument is
|
# Returns the fully-qualified name of a formula if the `full_name` argument is
|
||||||
# provided; returns the name otherwise.
|
# provided; returns the name otherwise.
|
||||||
# @return [String]
|
sig { params(formula: Formula, full_name: T::Boolean).returns(String) }
|
||||||
def formula_name(formula, args:)
|
def formula_name(formula, full_name: false)
|
||||||
args.full_name? ? formula.full_name : formula.name
|
full_name ? formula.full_name : formula.name
|
||||||
end
|
end
|
||||||
|
|
||||||
def status_hash(formula_or_cask, status_str, messages = nil, args:)
|
def status_hash(formula_or_cask, status_str, messages = nil, full_name: false, verbose: false)
|
||||||
formula = formula_or_cask if formula_or_cask.is_a?(Formula)
|
formula = formula_or_cask if formula_or_cask.is_a?(Formula)
|
||||||
cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask)
|
cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask)
|
||||||
|
|
||||||
status_hash = {}
|
status_hash = {}
|
||||||
if formula
|
if formula
|
||||||
status_hash[:formula] = formula_name(formula, args: args)
|
status_hash[:formula] = formula_name(formula, full_name: full_name)
|
||||||
elsif cask
|
elsif cask
|
||||||
status_hash[:cask] = cask_name(formula_or_cask, args: args)
|
status_hash[:cask] = cask_name(formula_or_cask, full_name: full_name)
|
||||||
end
|
end
|
||||||
status_hash[:status] = status_str
|
status_hash[:status] = status_str
|
||||||
status_hash[:messages] = messages if messages.is_a?(Array)
|
status_hash[:messages] = messages if messages.is_a?(Array)
|
||||||
|
|
||||||
if args.verbose?
|
status_hash[:meta] = {
|
||||||
status_hash[:meta] = {
|
livecheckable: formula_or_cask.livecheckable?,
|
||||||
livecheckable: formula_or_cask.livecheckable?,
|
}
|
||||||
}
|
status_hash[:meta][:head_only] = true if formula&.head_only?
|
||||||
status_hash[:meta][:head_only] = true if formula&.head_only?
|
|
||||||
end
|
|
||||||
|
|
||||||
status_hash
|
status_hash
|
||||||
end
|
end
|
||||||
@ -254,54 +266,55 @@ module Homebrew
|
|||||||
# If a formula has to be skipped, it prints or returns a Hash contaning the reason
|
# If a formula has to be skipped, it prints or returns a Hash contaning the reason
|
||||||
# for doing so; returns false otherwise.
|
# for doing so; returns false otherwise.
|
||||||
# @return [Hash, nil, Boolean]
|
# @return [Hash, nil, Boolean]
|
||||||
def skip_conditions(formula_or_cask, args:)
|
def skip_conditions(formula_or_cask, json: false, full_name: false, quiet: false, verbose: false)
|
||||||
formula = formula_or_cask if formula_or_cask.is_a?(Formula)
|
formula = formula_or_cask if formula_or_cask.is_a?(Formula)
|
||||||
|
|
||||||
if formula&.deprecated? && !formula.livecheckable?
|
if formula&.deprecated? && !formula.livecheckable?
|
||||||
return status_hash(formula, "deprecated", args: args) if args.json?
|
return status_hash(formula, "deprecated", full_name: full_name, verbose: verbose) if json
|
||||||
|
|
||||||
puts "#{Tty.red}#{formula_name(formula, args: args)}#{Tty.reset} : deprecated" unless args.quiet?
|
puts "#{Tty.red}#{formula_name(formula, full_name: full_name)}#{Tty.reset} : deprecated" unless quiet
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if formula&.disabled? && !formula.livecheckable?
|
if formula&.disabled? && !formula.livecheckable?
|
||||||
return status_hash(formula, "disabled", args: args) if args.json?
|
return status_hash(formula, "disabled", full_name: full_name, verbose: verbose) if json
|
||||||
|
|
||||||
puts "#{Tty.red}#{formula_name(formula, args: args)}#{Tty.reset} : disabled" unless args.quiet?
|
puts "#{Tty.red}#{formula_name(formula, full_name: full_name)}#{Tty.reset} : disabled" unless quiet
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if formula&.versioned_formula? && !formula.livecheckable?
|
if formula&.versioned_formula? && !formula.livecheckable?
|
||||||
return status_hash(formula, "versioned", args: args) if args.json?
|
return status_hash(formula, "versioned", full_name: full_name, verbose: verbose) if json
|
||||||
|
|
||||||
puts "#{Tty.red}#{formula_name(formula, args: args)}#{Tty.reset} : versioned" unless args.quiet?
|
puts "#{Tty.red}#{formula_name(formula, full_name: full_name)}#{Tty.reset} : versioned" unless quiet
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if formula&.head_only? && !formula.any_version_installed?
|
if formula&.head_only? && !formula.any_version_installed?
|
||||||
head_only_msg = "HEAD only formula must be installed to be livecheckable"
|
head_only_msg = "HEAD only formula must be installed to be livecheckable"
|
||||||
return status_hash(formula, "error", [head_only_msg], args: args) if args.json?
|
return status_hash(formula, "error", [head_only_msg], full_name: full_name, verbose: verbose) if json
|
||||||
|
|
||||||
puts "#{Tty.red}#{formula_name(formula, args: args)}#{Tty.reset} : #{head_only_msg}" unless args.quiet?
|
puts "#{Tty.red}#{formula_name(formula, full_name: full_name)}#{Tty.reset} : #{head_only_msg}" unless quiet
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
is_gist = formula&.stable&.url&.include?("gist.github.com")
|
is_gist = formula&.stable&.url&.include?("gist.github.com")
|
||||||
if formula_or_cask.livecheck.skip? || is_gist
|
if formula_or_cask.livecheck.skip? || is_gist
|
||||||
skip_msg = if formula_or_cask.livecheck.skip_msg.is_a?(String) &&
|
skip_message = if formula_or_cask.livecheck.skip_msg.is_a?(String) &&
|
||||||
formula_or_cask.livecheck.skip_msg.present?
|
formula_or_cask.livecheck.skip_msg.present?
|
||||||
formula_or_cask.livecheck.skip_msg.to_s
|
formula_or_cask.livecheck.skip_msg.to_s.presence
|
||||||
elsif is_gist
|
elsif is_gist
|
||||||
"Stable URL is a GitHub Gist"
|
"Stable URL is a GitHub Gist"
|
||||||
else
|
|
||||||
""
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return status_hash(formula_or_cask, "skipped", (skip_msg.blank? ? nil : [skip_msg]), args: args) if args.json?
|
if json
|
||||||
|
skip_messages = skip_message ? [skip_message] : nil
|
||||||
|
return status_hash(formula_or_cask, "skipped", skip_messages, full_name: full_name, verbose: verbose)
|
||||||
|
end
|
||||||
|
|
||||||
unless args.quiet?
|
unless quiet
|
||||||
puts "#{Tty.red}#{formula_or_cask_name(formula_or_cask, args: args)}#{Tty.reset} : skipped" \
|
puts "#{Tty.red}#{formula_or_cask_name(formula_or_cask, full_name: full_name)}#{Tty.reset} : skipped" \
|
||||||
"#{" - #{skip_msg}" if skip_msg.present?}"
|
"#{" - #{skip_message}" if skip_message}"
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@ -311,9 +324,9 @@ module Homebrew
|
|||||||
|
|
||||||
# Formats and prints the livecheck result for a formula.
|
# Formats and prints the livecheck result for a formula.
|
||||||
# @return [nil]
|
# @return [nil]
|
||||||
def print_latest_version(info, args:)
|
def print_latest_version(info, verbose:)
|
||||||
formula_or_cask_s = "#{Tty.blue}#{info[:formula] || info[:cask]}#{Tty.reset}"
|
formula_or_cask_s = "#{Tty.blue}#{info[:formula] || info[:cask]}#{Tty.reset}"
|
||||||
formula_or_cask_s += " (guessed)" if !info[:meta][:livecheckable] && args.verbose?
|
formula_or_cask_s += " (guessed)" if !info[:meta][:livecheckable] && verbose
|
||||||
|
|
||||||
current_s = if info[:version][:newer_than_upstream]
|
current_s = if info[:version][:newer_than_upstream]
|
||||||
"#{Tty.red}#{info[:version][:current]}#{Tty.reset}"
|
"#{Tty.red}#{info[:version][:current]}#{Tty.reset}"
|
||||||
@ -393,7 +406,7 @@ module Homebrew
|
|||||||
# Identifies the latest version of the formula and returns a Hash containing
|
# Identifies the latest version of the formula and returns a Hash containing
|
||||||
# the version information. Returns nil if a latest version couldn't be found.
|
# the version information. Returns nil if a latest version couldn't be found.
|
||||||
# @return [Hash, nil]
|
# @return [Hash, nil]
|
||||||
def latest_version(formula_or_cask, args:)
|
def latest_version(formula_or_cask, json: false, full_name: false, verbose: false, debug: false)
|
||||||
formula = formula_or_cask if formula_or_cask.is_a?(Formula)
|
formula = formula_or_cask if formula_or_cask.is_a?(Formula)
|
||||||
cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask)
|
cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask)
|
||||||
|
|
||||||
@ -406,19 +419,19 @@ module Homebrew
|
|||||||
urls = [livecheck_url] if livecheck_url.present?
|
urls = [livecheck_url] if livecheck_url.present?
|
||||||
urls ||= checkable_urls(formula_or_cask)
|
urls ||= checkable_urls(formula_or_cask)
|
||||||
|
|
||||||
if args.debug?
|
if debug
|
||||||
puts
|
puts
|
||||||
if formula
|
if formula
|
||||||
puts "Formula: #{formula_name(formula, args: args)}"
|
puts "Formula: #{formula_name(formula, full_name: full_name)}"
|
||||||
puts "Head only?: true" if formula.head_only?
|
puts "Head only?: true" if formula.head_only?
|
||||||
elsif cask
|
elsif cask
|
||||||
puts "Cask: #{cask_name(formula_or_cask, args: args)}"
|
puts "Cask: #{cask_name(formula_or_cask, full_name: full_name)}"
|
||||||
end
|
end
|
||||||
puts "Livecheckable?: #{has_livecheckable ? "Yes" : "No"}"
|
puts "Livecheckable?: #{has_livecheckable ? "Yes" : "No"}"
|
||||||
end
|
end
|
||||||
|
|
||||||
urls.each_with_index do |original_url, i|
|
urls.each_with_index do |original_url, i|
|
||||||
if args.debug?
|
if debug
|
||||||
puts
|
puts
|
||||||
puts "URL: #{original_url}"
|
puts "URL: #{original_url}"
|
||||||
end
|
end
|
||||||
@ -443,12 +456,12 @@ module Homebrew
|
|||||||
)
|
)
|
||||||
strategy = Strategy.from_symbol(livecheck_strategy)
|
strategy = Strategy.from_symbol(livecheck_strategy)
|
||||||
strategy ||= strategies.first
|
strategy ||= strategies.first
|
||||||
strategy_name = @livecheck_strategy_names[strategy]
|
strategy_name = livecheck_strategy_names[strategy]
|
||||||
|
|
||||||
if args.debug?
|
if debug
|
||||||
puts "URL (processed): #{url}" if url != original_url
|
puts "URL (processed): #{url}" if url != original_url
|
||||||
if strategies.present? && args.verbose?
|
if strategies.present? && verbose
|
||||||
puts "Strategies: #{strategies.map { |s| @livecheck_strategy_names[s] }.join(", ")}"
|
puts "Strategies: #{strategies.map { |s| livecheck_strategy_names[s] }.join(", ")}"
|
||||||
end
|
end
|
||||||
puts "Strategy: #{strategy.blank? ? "None" : strategy_name}"
|
puts "Strategy: #{strategy.blank? ? "None" : strategy_name}"
|
||||||
puts "Regex: #{livecheck_regex.inspect}" if livecheck_regex.present?
|
puts "Regex: #{livecheck_regex.inspect}" if livecheck_regex.present?
|
||||||
@ -471,13 +484,13 @@ module Homebrew
|
|||||||
regex = strategy_data[:regex]
|
regex = strategy_data[:regex]
|
||||||
|
|
||||||
if strategy_data[:messages].is_a?(Array) && match_version_map.blank?
|
if strategy_data[:messages].is_a?(Array) && match_version_map.blank?
|
||||||
puts strategy_data[:messages] unless args.json?
|
puts strategy_data[:messages] unless json
|
||||||
next if i + 1 < urls.length
|
next if i + 1 < urls.length
|
||||||
|
|
||||||
return status_hash(formula, "error", strategy_data[:messages], args: args)
|
return status_hash(formula, "error", strategy_data[:messages], full_name: full_name, verbose: verbose)
|
||||||
end
|
end
|
||||||
|
|
||||||
if args.debug?
|
if debug
|
||||||
puts "URL (strategy): #{strategy_data[:url]}" if strategy_data[:url] != url
|
puts "URL (strategy): #{strategy_data[:url]}" if strategy_data[:url] != url
|
||||||
puts "Regex (strategy): #{strategy_data[:regex].inspect}" if strategy_data[:regex] != livecheck_regex
|
puts "Regex (strategy): #{strategy_data[:regex].inspect}" if strategy_data[:regex] != livecheck_regex
|
||||||
end
|
end
|
||||||
@ -491,11 +504,11 @@ module Homebrew
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if args.debug? && match_version_map.present?
|
if debug && match_version_map.present?
|
||||||
puts
|
puts
|
||||||
puts "Matched Versions:"
|
puts "Matched Versions:"
|
||||||
|
|
||||||
if args.verbose?
|
if verbose
|
||||||
match_version_map.each do |match, version|
|
match_version_map.each do |match, version|
|
||||||
puts "#{match} => #{version.inspect}"
|
puts "#{match} => #{version.inspect}"
|
||||||
end
|
end
|
||||||
@ -510,7 +523,7 @@ module Homebrew
|
|||||||
latest: Version.new(match_version_map.values.max),
|
latest: Version.new(match_version_map.values.max),
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.json? && args.verbose?
|
if json && verbose
|
||||||
version_info[:meta] = {
|
version_info[:meta] = {
|
||||||
url: {
|
url: {
|
||||||
original: original_url,
|
original: original_url,
|
||||||
@ -519,9 +532,7 @@ module Homebrew
|
|||||||
}
|
}
|
||||||
version_info[:meta][:url][:processed] = url if url != original_url
|
version_info[:meta][:url][:processed] = url if url != original_url
|
||||||
version_info[:meta][:url][:strategy] = strategy_data[:url] if strategy_data[:url] != url
|
version_info[:meta][:url][:strategy] = strategy_data[:url] if strategy_data[:url] != url
|
||||||
if strategies.present?
|
version_info[:meta][:strategies] = strategies.map { |s| livecheck_strategy_names[s] } if strategies.present?
|
||||||
version_info[:meta][:strategies] = strategies.map { |s| @livecheck_strategy_names[s] }
|
|
||||||
end
|
|
||||||
version_info[:meta][:regex] = regex.inspect if regex.present?
|
version_info[:meta][:regex] = regex.inspect if regex.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -91,35 +91,29 @@ describe Homebrew::Livecheck do
|
|||||||
RUBY
|
RUBY
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:args) { double("livecheck_args", full_name?: false, json?: false, quiet?: false, verbose?: true) }
|
|
||||||
|
|
||||||
describe "::formula_name" do
|
describe "::formula_name" do
|
||||||
it "returns the name of the formula" do
|
it "returns the name of the formula" do
|
||||||
expect(livecheck.formula_name(f, args: args)).to eq("test")
|
expect(livecheck.formula_name(f)).to eq("test")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns the full name" do
|
it "returns the full name" do
|
||||||
allow(args).to receive(:full_name?).and_return(true)
|
expect(livecheck.formula_name(f, full_name: true)).to eq("test")
|
||||||
|
|
||||||
expect(livecheck.formula_name(f, args: args)).to eq("test")
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "::cask_name" do
|
describe "::cask_name" do
|
||||||
it "returns the token of the cask" do
|
it "returns the token of the cask" do
|
||||||
expect(livecheck.cask_name(c, args: args)).to eq("test")
|
expect(livecheck.cask_name(c)).to eq("test")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns the full name of the cask" do
|
it "returns the full name of the cask" do
|
||||||
allow(args).to receive(:full_name?).and_return(true)
|
expect(livecheck.cask_name(c, full_name: true)).to eq("test")
|
||||||
|
|
||||||
expect(livecheck.cask_name(c, args: args)).to eq("test")
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "::status_hash" do
|
describe "::status_hash" do
|
||||||
it "returns a hash containing the livecheck status" do
|
it "returns a hash containing the livecheck status" do
|
||||||
expect(livecheck.status_hash(f, "error", ["Unable to get versions"], args: args))
|
expect(livecheck.status_hash(f, "error", ["Unable to get versions"]))
|
||||||
.to eq({
|
.to eq({
|
||||||
formula: "test",
|
formula: "test",
|
||||||
status: "error",
|
status: "error",
|
||||||
@ -133,47 +127,47 @@ describe Homebrew::Livecheck do
|
|||||||
|
|
||||||
describe "::skip_conditions" do
|
describe "::skip_conditions" do
|
||||||
it "skips a deprecated formula without a livecheckable" do
|
it "skips a deprecated formula without a livecheckable" do
|
||||||
expect { livecheck.skip_conditions(f_deprecated, args: args) }
|
expect { livecheck.skip_conditions(f_deprecated) }
|
||||||
.to output("test_deprecated : deprecated\n").to_stdout
|
.to output("test_deprecated : deprecated\n").to_stdout
|
||||||
.and not_to_output.to_stderr
|
.and not_to_output.to_stderr
|
||||||
end
|
end
|
||||||
|
|
||||||
it "skips a disabled formula without a livecheckable" do
|
it "skips a disabled formula without a livecheckable" do
|
||||||
expect { livecheck.skip_conditions(f_disabled, args: args) }
|
expect { livecheck.skip_conditions(f_disabled) }
|
||||||
.to output("test_disabled : disabled\n").to_stdout
|
.to output("test_disabled : disabled\n").to_stdout
|
||||||
.and not_to_output.to_stderr
|
.and not_to_output.to_stderr
|
||||||
end
|
end
|
||||||
|
|
||||||
it "skips a versioned formula without a livecheckable" do
|
it "skips a versioned formula without a livecheckable" do
|
||||||
expect { livecheck.skip_conditions(f_versioned, args: args) }
|
expect { livecheck.skip_conditions(f_versioned) }
|
||||||
.to output("test@0.0.1 : versioned\n").to_stdout
|
.to output("test@0.0.1 : versioned\n").to_stdout
|
||||||
.and not_to_output.to_stderr
|
.and not_to_output.to_stderr
|
||||||
end
|
end
|
||||||
|
|
||||||
it "skips a HEAD-only formula if not installed" do
|
it "skips a HEAD-only formula if not installed" do
|
||||||
expect { livecheck.skip_conditions(f_head_only, args: args) }
|
expect { livecheck.skip_conditions(f_head_only) }
|
||||||
.to output("test_head_only : HEAD only formula must be installed to be livecheckable\n").to_stdout
|
.to output("test_head_only : HEAD only formula must be installed to be livecheckable\n").to_stdout
|
||||||
.and not_to_output.to_stderr
|
.and not_to_output.to_stderr
|
||||||
end
|
end
|
||||||
|
|
||||||
it "skips a formula with a GitHub Gist stable URL" do
|
it "skips a formula with a GitHub Gist stable URL" do
|
||||||
expect { livecheck.skip_conditions(f_gist, args: args) }
|
expect { livecheck.skip_conditions(f_gist) }
|
||||||
.to output("test_gist : skipped - Stable URL is a GitHub Gist\n").to_stdout
|
.to output("test_gist : skipped - Stable URL is a GitHub Gist\n").to_stdout
|
||||||
.and not_to_output.to_stderr
|
.and not_to_output.to_stderr
|
||||||
end
|
end
|
||||||
|
|
||||||
it "skips a formula with a skip livecheckable" do
|
it "skips a formula with a skip livecheckable" do
|
||||||
expect { livecheck.skip_conditions(f_skip, args: args) }
|
expect { livecheck.skip_conditions(f_skip) }
|
||||||
.to output("test_skip : skipped - Not maintained\n").to_stdout
|
.to output("test_skip : skipped - Not maintained\n").to_stdout
|
||||||
.and not_to_output.to_stderr
|
.and not_to_output.to_stderr
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns false for a non-skippable formula" do
|
it "returns false for a non-skippable formula" do
|
||||||
expect(livecheck.skip_conditions(f, args: args)).to eq(false)
|
expect(livecheck.skip_conditions(f)).to eq(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns false for a non-skippable cask" do
|
it "returns false for a non-skippable cask" do
|
||||||
expect(livecheck.skip_conditions(c, args: args)).to eq(false)
|
expect(livecheck.skip_conditions(c)).to eq(false)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user