Merge pull request #13613 from mohammadzainabbas/mohammad
Augment `brew livecheck` with a `--resources` option to check resources
This commit is contained in:
		
						commit
						639e8eb237
					
				@ -30,6 +30,9 @@ module Homebrew
 | 
			
		||||
      sig { returns(T::Boolean) }
 | 
			
		||||
      def newer_only?; end
 | 
			
		||||
 | 
			
		||||
      sig { returns(T::Boolean) }
 | 
			
		||||
      def resources?; end
 | 
			
		||||
 | 
			
		||||
      sig { returns(T::Boolean) }
 | 
			
		||||
      def full_name?; end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -72,17 +72,18 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      ambiguous_casks = []
 | 
			
		||||
      if !args.formula? && !args.cask?
 | 
			
		||||
        ambiguous_casks = formulae_and_casks.group_by { |item| Livecheck.formula_or_cask_name(item, full_name: true) }
 | 
			
		||||
                                            .values
 | 
			
		||||
                                            .select { |items| items.length > 1 }
 | 
			
		||||
                                            .flatten
 | 
			
		||||
                                            .select { |item| item.is_a?(Cask::Cask) }
 | 
			
		||||
        ambiguous_casks = formulae_and_casks \
 | 
			
		||||
                          .group_by { |item| Livecheck.package_or_resource_name(item, full_name: true) }
 | 
			
		||||
                          .values
 | 
			
		||||
                          .select { |items| items.length > 1 }
 | 
			
		||||
                          .flatten
 | 
			
		||||
                          .select { |item| item.is_a?(Cask::Cask) }
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      ambiguous_names = []
 | 
			
		||||
      unless args.full_name?
 | 
			
		||||
        ambiguous_names =
 | 
			
		||||
          (formulae_and_casks - ambiguous_casks).group_by { |item| Livecheck.formula_or_cask_name(item) }
 | 
			
		||||
          (formulae_and_casks - ambiguous_casks).group_by { |item| Livecheck.package_or_resource_name(item) }
 | 
			
		||||
                                                .values
 | 
			
		||||
                                                .select { |items| items.length > 1 }
 | 
			
		||||
                                                .flatten
 | 
			
		||||
@ -92,7 +93,7 @@ module Homebrew
 | 
			
		||||
        puts if i.positive?
 | 
			
		||||
 | 
			
		||||
        use_full_name = args.full_name? || ambiguous_names.include?(formula_or_cask)
 | 
			
		||||
        name = Livecheck.formula_or_cask_name(formula_or_cask, full_name: use_full_name)
 | 
			
		||||
        name = Livecheck.package_or_resource_name(formula_or_cask, full_name: use_full_name)
 | 
			
		||||
        repository = if formula_or_cask.is_a?(Formula)
 | 
			
		||||
          if formula_or_cask.head_only?
 | 
			
		||||
            ohai name
 | 
			
		||||
@ -157,7 +158,7 @@ module Homebrew
 | 
			
		||||
          rescue
 | 
			
		||||
            next
 | 
			
		||||
          end
 | 
			
		||||
          name = Livecheck.formula_or_cask_name(formula_or_cask)
 | 
			
		||||
          name = Livecheck.package_or_resource_name(formula_or_cask)
 | 
			
		||||
          ambiguous_cask = begin
 | 
			
		||||
            formula_or_cask.is_a?(Cask::Cask) && !args.cask? && Formula[name]
 | 
			
		||||
          rescue FormulaUnavailableError
 | 
			
		||||
@ -178,7 +179,7 @@ module Homebrew
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def livecheck_result(formula_or_cask)
 | 
			
		||||
    name = Livecheck.formula_or_cask_name(formula_or_cask)
 | 
			
		||||
    name = Livecheck.package_or_resource_name(formula_or_cask)
 | 
			
		||||
 | 
			
		||||
    referenced_formula_or_cask, =
 | 
			
		||||
      Livecheck.resolve_livecheck_reference(formula_or_cask, full_name: false, debug: false)
 | 
			
		||||
 | 
			
		||||
@ -37,6 +37,8 @@ module Homebrew
 | 
			
		||||
             description: "Show the latest version only if it's newer than the formula/cask."
 | 
			
		||||
      switch "--json",
 | 
			
		||||
             description: "Output information in JSON format."
 | 
			
		||||
      switch "-r", "--resources",
 | 
			
		||||
             description: "Also check resources for formulae."
 | 
			
		||||
      switch "-q", "--quiet",
 | 
			
		||||
             description: "Suppress warnings, don't print a progress bar for JSON output."
 | 
			
		||||
      switch "--formula", "--formulae",
 | 
			
		||||
@ -101,6 +103,7 @@ module Homebrew
 | 
			
		||||
    else
 | 
			
		||||
      raise UsageError, "A watchlist file is required when no arguments are given."
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    formulae_and_casks_to_check = formulae_and_casks_to_check.sort_by do |formula_or_cask|
 | 
			
		||||
      formula_or_cask.respond_to?(:token) ? formula_or_cask.token : formula_or_cask.name
 | 
			
		||||
    end
 | 
			
		||||
@ -111,6 +114,7 @@ module Homebrew
 | 
			
		||||
      json:                 args.json?,
 | 
			
		||||
      full_name:            args.full_name?,
 | 
			
		||||
      handle_name_conflict: !args.formula? && !args.cask?,
 | 
			
		||||
      check_resources:      args.resources?,
 | 
			
		||||
      newer_only:           args.newer_only?,
 | 
			
		||||
      quiet:                args.quiet?,
 | 
			
		||||
      debug:                args.debug?,
 | 
			
		||||
 | 
			
		||||
@ -126,11 +126,11 @@ module Homebrew
 | 
			
		||||
        if debug
 | 
			
		||||
          # Print the chain of references for debugging
 | 
			
		||||
          puts "Reference Chain:"
 | 
			
		||||
          puts formula_or_cask_name(first_formula_or_cask, full_name: full_name)
 | 
			
		||||
          puts package_or_resource_name(first_formula_or_cask, full_name: full_name)
 | 
			
		||||
 | 
			
		||||
          references << referenced_formula_or_cask
 | 
			
		||||
          references.each do |ref_formula_or_cask|
 | 
			
		||||
            puts formula_or_cask_name(ref_formula_or_cask, full_name: full_name)
 | 
			
		||||
            puts package_or_resource_name(ref_formula_or_cask, full_name: full_name)
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
@ -157,11 +157,14 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
    # Executes the livecheck logic for each formula/cask in the
 | 
			
		||||
    # `formulae_and_casks_to_check` array and prints the results.
 | 
			
		||||
    # rubocop:disable Metrics/CyclomaticComplexity
 | 
			
		||||
    # rubocop:disable Metrics/PerceivedComplexity
 | 
			
		||||
    sig {
 | 
			
		||||
      params(
 | 
			
		||||
        formulae_and_casks_to_check: T::Array[T.any(Formula, Cask::Cask)],
 | 
			
		||||
        full_name:                   T::Boolean,
 | 
			
		||||
        handle_name_conflict:        T::Boolean,
 | 
			
		||||
        check_resources:             T::Boolean,
 | 
			
		||||
        json:                        T::Boolean,
 | 
			
		||||
        newer_only:                  T::Boolean,
 | 
			
		||||
        debug:                       T::Boolean,
 | 
			
		||||
@ -171,24 +174,25 @@ module Homebrew
 | 
			
		||||
    }
 | 
			
		||||
    def run_checks(
 | 
			
		||||
      formulae_and_casks_to_check,
 | 
			
		||||
      full_name: false, handle_name_conflict: false, json: false, newer_only: false,
 | 
			
		||||
      full_name: false, handle_name_conflict: false, check_resources: false, json: false, newer_only: false,
 | 
			
		||||
      debug: false, quiet: false, verbose: false
 | 
			
		||||
    )
 | 
			
		||||
      load_other_tap_strategies(formulae_and_casks_to_check)
 | 
			
		||||
 | 
			
		||||
      ambiguous_casks = []
 | 
			
		||||
      if handle_name_conflict
 | 
			
		||||
        ambiguous_casks = formulae_and_casks_to_check.group_by { |item| formula_or_cask_name(item, full_name: true) }
 | 
			
		||||
                                                     .values
 | 
			
		||||
                                                     .select { |items| items.length > 1 }
 | 
			
		||||
                                                     .flatten
 | 
			
		||||
                                                     .select { |item| item.is_a?(Cask::Cask) }
 | 
			
		||||
        ambiguous_casks = formulae_and_casks_to_check \
 | 
			
		||||
                          .group_by { |item| package_or_resource_name(item, full_name: true) }
 | 
			
		||||
                          .values
 | 
			
		||||
                          .select { |items| items.length > 1 }
 | 
			
		||||
                          .flatten
 | 
			
		||||
                          .select { |item| item.is_a?(Cask::Cask) }
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      ambiguous_names = []
 | 
			
		||||
      unless full_name
 | 
			
		||||
        ambiguous_names =
 | 
			
		||||
          (formulae_and_casks_to_check - ambiguous_casks).group_by { |item| formula_or_cask_name(item) }
 | 
			
		||||
          (formulae_and_casks_to_check - ambiguous_casks).group_by { |item| package_or_resource_name(item) }
 | 
			
		||||
                                                         .values
 | 
			
		||||
                                                         .select { |items| items.length > 1 }
 | 
			
		||||
                                                         .flatten
 | 
			
		||||
@ -218,7 +222,7 @@ module Homebrew
 | 
			
		||||
        cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask)
 | 
			
		||||
 | 
			
		||||
        use_full_name = full_name || ambiguous_names.include?(formula_or_cask)
 | 
			
		||||
        name = formula_or_cask_name(formula_or_cask, full_name: use_full_name)
 | 
			
		||||
        name = package_or_resource_name(formula_or_cask, full_name: use_full_name)
 | 
			
		||||
 | 
			
		||||
        referenced_formula_or_cask, livecheck_references =
 | 
			
		||||
          resolve_livecheck_reference(formula_or_cask, full_name: use_full_name, debug: debug)
 | 
			
		||||
@ -282,6 +286,30 @@ module Homebrew
 | 
			
		||||
          version_info[:latest] if version_info.present?
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        check_for_resources = check_resources && formula_or_cask.is_a?(Formula) && formula_or_cask.resources.present?
 | 
			
		||||
        if check_for_resources
 | 
			
		||||
          resource_version_info = formula_or_cask.resources.map do |resource|
 | 
			
		||||
            res_skip_info ||= SkipConditions.skip_information(resource, verbose: verbose)
 | 
			
		||||
            if res_skip_info.present?
 | 
			
		||||
              res_skip_info
 | 
			
		||||
            else
 | 
			
		||||
              res_version_info = resource_version(
 | 
			
		||||
                resource,
 | 
			
		||||
                json:    json,
 | 
			
		||||
                debug:   debug,
 | 
			
		||||
                quiet:   quiet,
 | 
			
		||||
                verbose: verbose,
 | 
			
		||||
              )
 | 
			
		||||
              if res_version_info.empty?
 | 
			
		||||
                status_hash(resource, "error", ["Unable to get versions"], verbose: verbose)
 | 
			
		||||
              else
 | 
			
		||||
                res_version_info
 | 
			
		||||
              end
 | 
			
		||||
            end
 | 
			
		||||
          end.compact_blank
 | 
			
		||||
          Homebrew.failed = true if resource_version_info.any? { |info| info[:status] == "error" }
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        if latest.blank?
 | 
			
		||||
          no_versions_msg = "Unable to get versions"
 | 
			
		||||
          raise Livecheck::Error, no_versions_msg unless json
 | 
			
		||||
@ -289,7 +317,14 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
          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], full_name: use_full_name, verbose: verbose)
 | 
			
		||||
          latest_info = status_hash(formula_or_cask, "error", [no_versions_msg], full_name: use_full_name,
 | 
			
		||||
                                                                                 verbose:   verbose)
 | 
			
		||||
          if check_for_resources
 | 
			
		||||
            resource_version_info.map! { |r| r.except!(:meta) } unless verbose
 | 
			
		||||
            latest_info[:resources] = resource_version_info
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          next latest_info
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        if (m = latest.to_s.match(/(.*)-release$/)) && !current.to_s.match(/.*-release$/)
 | 
			
		||||
@ -324,6 +359,8 @@ module Homebrew
 | 
			
		||||
        info[:meta][:head_only] = true if formula&.head_only?
 | 
			
		||||
        info[:meta].merge!(version_info[:meta]) if version_info.present? && version_info.key?(:meta)
 | 
			
		||||
 | 
			
		||||
        info[:resources] = resource_version_info if check_for_resources
 | 
			
		||||
 | 
			
		||||
        next if newer_only && !info[:version][:outdated]
 | 
			
		||||
 | 
			
		||||
        has_a_newer_upstream_version ||= true
 | 
			
		||||
@ -331,10 +368,12 @@ module Homebrew
 | 
			
		||||
        if json
 | 
			
		||||
          progress&.increment
 | 
			
		||||
          info.except!(:meta) unless verbose
 | 
			
		||||
          resource_version_info.map! { |r| r.except!(:meta) } if check_for_resources && !verbose
 | 
			
		||||
          next info
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        puts if debug
 | 
			
		||||
        print_latest_version(info, verbose: verbose, ambiguous_cask: ambiguous_casks.include?(formula_or_cask))
 | 
			
		||||
        print_resources_info(resource_version_info, verbose: verbose) if check_for_resources
 | 
			
		||||
        nil
 | 
			
		||||
      rescue => e
 | 
			
		||||
        Homebrew.failed = true
 | 
			
		||||
@ -344,11 +383,12 @@ module Homebrew
 | 
			
		||||
          progress&.increment
 | 
			
		||||
          status_hash(formula_or_cask, "error", [e.to_s], full_name: use_full_name, verbose: verbose) unless quiet
 | 
			
		||||
        elsif !quiet
 | 
			
		||||
          name = formula_or_cask_name(formula_or_cask, full_name: use_full_name)
 | 
			
		||||
          name = package_or_resource_name(formula_or_cask, full_name: use_full_name)
 | 
			
		||||
          name += " (cask)" if ambiguous_casks.include?(formula_or_cask)
 | 
			
		||||
 | 
			
		||||
          onoe "#{Tty.blue}#{name}#{Tty.reset}: #{e}"
 | 
			
		||||
          $stderr.puts e.backtrace if debug && !e.is_a?(Livecheck::Error)
 | 
			
		||||
          print_resources_info(resource_version_info, verbose: verbose) if check_for_resources
 | 
			
		||||
          nil
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
@ -367,16 +407,20 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      puts JSON.pretty_generate(formulae_checked.compact)
 | 
			
		||||
    end
 | 
			
		||||
    # rubocop:enable Metrics/CyclomaticComplexity
 | 
			
		||||
    # rubocop:enable Metrics/PerceivedComplexity
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
    sig { params(package_or_resource: T.any(Formula, Cask::Cask, Resource), full_name: T::Boolean).returns(String) }
 | 
			
		||||
    def package_or_resource_name(package_or_resource, full_name: false)
 | 
			
		||||
      case package_or_resource
 | 
			
		||||
      when Formula
 | 
			
		||||
        formula_name(formula_or_cask, full_name: full_name)
 | 
			
		||||
        formula_name(package_or_resource, full_name: full_name)
 | 
			
		||||
      when Cask::Cask
 | 
			
		||||
        cask_name(formula_or_cask, full_name: full_name)
 | 
			
		||||
        cask_name(package_or_resource, full_name: full_name)
 | 
			
		||||
      when Resource
 | 
			
		||||
        package_or_resource.name
 | 
			
		||||
      else
 | 
			
		||||
        T.absurd(formula_or_cask)
 | 
			
		||||
        T.absurd(package_or_resource)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -396,40 +440,44 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
    sig {
 | 
			
		||||
      params(
 | 
			
		||||
        formula_or_cask: T.any(Formula, Cask::Cask),
 | 
			
		||||
        status_str:      String,
 | 
			
		||||
        messages:        T.nilable(T::Array[String]),
 | 
			
		||||
        full_name:       T::Boolean,
 | 
			
		||||
        verbose:         T::Boolean,
 | 
			
		||||
        package_or_resource: T.any(Formula, Cask::Cask, Resource),
 | 
			
		||||
        status_str:          String,
 | 
			
		||||
        messages:            T.nilable(T::Array[String]),
 | 
			
		||||
        full_name:           T::Boolean,
 | 
			
		||||
        verbose:             T::Boolean,
 | 
			
		||||
      ).returns(Hash)
 | 
			
		||||
    }
 | 
			
		||||
    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)
 | 
			
		||||
      cask = formula_or_cask if formula_or_cask.is_a?(Cask::Cask)
 | 
			
		||||
    def status_hash(package_or_resource, status_str, messages = nil, full_name: false, verbose: false)
 | 
			
		||||
      formula = package_or_resource if package_or_resource.is_a?(Formula)
 | 
			
		||||
      cask = package_or_resource if package_or_resource.is_a?(Cask::Cask)
 | 
			
		||||
      resource = package_or_resource if package_or_resource.is_a?(Resource)
 | 
			
		||||
 | 
			
		||||
      status_hash = {}
 | 
			
		||||
      if formula
 | 
			
		||||
        status_hash[:formula] = formula_name(formula, full_name: full_name)
 | 
			
		||||
      elsif cask
 | 
			
		||||
        status_hash[:cask] = cask_name(formula_or_cask, full_name: full_name)
 | 
			
		||||
        status_hash[:cask] = cask_name(cask, full_name: full_name)
 | 
			
		||||
      elsif resource
 | 
			
		||||
        status_hash[:resource] = resource.name
 | 
			
		||||
      end
 | 
			
		||||
      status_hash[:status] = status_str
 | 
			
		||||
      status_hash[:messages] = messages if messages.is_a?(Array)
 | 
			
		||||
 | 
			
		||||
      status_hash[:meta] = {
 | 
			
		||||
        livecheckable: formula_or_cask.livecheckable?,
 | 
			
		||||
        livecheckable: package_or_resource.livecheckable?,
 | 
			
		||||
      }
 | 
			
		||||
      status_hash[:meta][:head_only] = true if formula&.head_only?
 | 
			
		||||
 | 
			
		||||
      status_hash
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # Formats and prints the livecheck result for a formula.
 | 
			
		||||
    # Formats and prints the livecheck result for a formula/cask/resource.
 | 
			
		||||
    sig { params(info: Hash, verbose: T::Boolean, ambiguous_cask: T::Boolean).void }
 | 
			
		||||
    def print_latest_version(info, verbose:, ambiguous_cask: false)
 | 
			
		||||
      formula_or_cask_s = "#{Tty.blue}#{info[:formula] || info[:cask]}#{Tty.reset}"
 | 
			
		||||
      formula_or_cask_s += " (cask)" if ambiguous_cask
 | 
			
		||||
      formula_or_cask_s += " (guessed)" if !info[:meta][:livecheckable] && verbose
 | 
			
		||||
    def print_latest_version(info, verbose: false, ambiguous_cask: false)
 | 
			
		||||
      package_or_resource_s = info[:resource].present? ? "  " : ""
 | 
			
		||||
      package_or_resource_s += "#{Tty.blue}#{info[:formula] || info[:cask] || info[:resource]}#{Tty.reset}"
 | 
			
		||||
      package_or_resource_s += " (cask)" if ambiguous_cask
 | 
			
		||||
      package_or_resource_s += " (guessed)" if verbose && !info[:meta][:livecheckable]
 | 
			
		||||
 | 
			
		||||
      current_s = if info[:version][:newer_than_upstream]
 | 
			
		||||
        "#{Tty.red}#{info[:version][:current]}#{Tty.reset}"
 | 
			
		||||
@ -443,47 +491,61 @@ module Homebrew
 | 
			
		||||
        info[:version][:latest]
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      puts "#{formula_or_cask_s}: #{current_s} ==> #{latest_s}"
 | 
			
		||||
      puts "#{package_or_resource_s}: #{current_s} ==> #{latest_s}"
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # Prints the livecheck result for the resources of a given Formula.
 | 
			
		||||
    sig { params(info: T::Array[Hash], verbose: T::Boolean).void }
 | 
			
		||||
    def print_resources_info(info, verbose: false)
 | 
			
		||||
      info.each do |r_info|
 | 
			
		||||
        if r_info[:status] && r_info[:messages]
 | 
			
		||||
          SkipConditions.print_skip_information(r_info)
 | 
			
		||||
        else
 | 
			
		||||
          print_latest_version(r_info, verbose: verbose)
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    sig {
 | 
			
		||||
      params(
 | 
			
		||||
        livecheck_url:   T.any(String, Symbol),
 | 
			
		||||
        formula_or_cask: T.any(Formula, Cask::Cask),
 | 
			
		||||
        livecheck_url:       T.any(String, Symbol),
 | 
			
		||||
        package_or_resource: T.any(Formula, Cask::Cask, Resource),
 | 
			
		||||
      ).returns(T.nilable(String))
 | 
			
		||||
    }
 | 
			
		||||
    def livecheck_url_to_string(livecheck_url, formula_or_cask)
 | 
			
		||||
    def livecheck_url_to_string(livecheck_url, package_or_resource)
 | 
			
		||||
      case livecheck_url
 | 
			
		||||
      when String
 | 
			
		||||
        livecheck_url
 | 
			
		||||
      when :url
 | 
			
		||||
        formula_or_cask.url&.to_s if formula_or_cask.is_a?(Cask::Cask)
 | 
			
		||||
        package_or_resource.url&.to_s if package_or_resource.is_a?(Cask::Cask) || package_or_resource.is_a?(Resource)
 | 
			
		||||
      when :head, :stable
 | 
			
		||||
        formula_or_cask.send(livecheck_url)&.url if formula_or_cask.is_a?(Formula)
 | 
			
		||||
        package_or_resource.send(livecheck_url)&.url if package_or_resource.is_a?(Formula)
 | 
			
		||||
      when :homepage
 | 
			
		||||
        formula_or_cask.homepage
 | 
			
		||||
        package_or_resource.homepage unless package_or_resource.is_a?(Resource)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # Returns an Array containing the formula/cask URLs that can be used by livecheck.
 | 
			
		||||
    sig { params(formula_or_cask: T.any(Formula, Cask::Cask)).returns(T::Array[String]) }
 | 
			
		||||
    def checkable_urls(formula_or_cask)
 | 
			
		||||
    # Returns an Array containing the formula/cask/resource URLs that can be used by livecheck.
 | 
			
		||||
    sig { params(package_or_resource: T.any(Formula, Cask::Cask, Resource)).returns(T::Array[String]) }
 | 
			
		||||
    def checkable_urls(package_or_resource)
 | 
			
		||||
      urls = []
 | 
			
		||||
 | 
			
		||||
      case formula_or_cask
 | 
			
		||||
      case package_or_resource
 | 
			
		||||
      when Formula
 | 
			
		||||
        if formula_or_cask.stable
 | 
			
		||||
          urls << formula_or_cask.stable.url
 | 
			
		||||
          urls.concat(formula_or_cask.stable.mirrors)
 | 
			
		||||
        if package_or_resource.stable
 | 
			
		||||
          urls << package_or_resource.stable.url
 | 
			
		||||
          urls.concat(package_or_resource.stable.mirrors)
 | 
			
		||||
        end
 | 
			
		||||
        urls << formula_or_cask.head.url if formula_or_cask.head
 | 
			
		||||
        urls << formula_or_cask.homepage if formula_or_cask.homepage
 | 
			
		||||
        urls << package_or_resource.head.url if package_or_resource.head
 | 
			
		||||
        urls << package_or_resource.homepage if package_or_resource.homepage
 | 
			
		||||
      when Cask::Cask
 | 
			
		||||
        urls << formula_or_cask.appcast.to_s if formula_or_cask.appcast
 | 
			
		||||
        urls << formula_or_cask.url.to_s if formula_or_cask.url
 | 
			
		||||
        urls << formula_or_cask.homepage if formula_or_cask.homepage
 | 
			
		||||
        urls << package_or_resource.appcast.to_s if package_or_resource.appcast
 | 
			
		||||
        urls << package_or_resource.url.to_s if package_or_resource.url
 | 
			
		||||
        urls << package_or_resource.homepage if package_or_resource.homepage
 | 
			
		||||
      when Resource
 | 
			
		||||
        urls << package_or_resource.url
 | 
			
		||||
      else
 | 
			
		||||
        T.absurd(formula_or_cask)
 | 
			
		||||
        T.absurd(package_or_resource)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      urls.compact.uniq
 | 
			
		||||
@ -561,7 +623,7 @@ module Homebrew
 | 
			
		||||
      homebrew_curl_root_domains.include?(url_root_domain)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # Identifies the latest version of the formula and returns a Hash containing
 | 
			
		||||
    # Identifies the latest version of the formula/cask and returns a Hash containing
 | 
			
		||||
    # the version information. Returns nil if a latest version couldn't be found.
 | 
			
		||||
    # rubocop:disable Metrics/CyclomaticComplexity
 | 
			
		||||
    sig {
 | 
			
		||||
@ -713,7 +775,6 @@ module Homebrew
 | 
			
		||||
            version.to_s.include?(rejection)
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        next if match_version_map.blank?
 | 
			
		||||
 | 
			
		||||
        if debug
 | 
			
		||||
@ -770,6 +831,195 @@ module Homebrew
 | 
			
		||||
      nil
 | 
			
		||||
    end
 | 
			
		||||
    # rubocop:enable Metrics/CyclomaticComplexity
 | 
			
		||||
 | 
			
		||||
    # Identifies the latest version of a resource and returns a Hash containing the
 | 
			
		||||
    # version information. Returns nil if a latest version couldn't be found.
 | 
			
		||||
    sig {
 | 
			
		||||
      params(
 | 
			
		||||
        resource: Resource,
 | 
			
		||||
        json:     T::Boolean,
 | 
			
		||||
        debug:    T::Boolean,
 | 
			
		||||
        quiet:    T::Boolean,
 | 
			
		||||
        verbose:  T::Boolean,
 | 
			
		||||
      ).returns(Hash)
 | 
			
		||||
    }
 | 
			
		||||
    def resource_version(
 | 
			
		||||
      resource,
 | 
			
		||||
      json: false,
 | 
			
		||||
      debug: false,
 | 
			
		||||
      quiet: false,
 | 
			
		||||
      verbose: false
 | 
			
		||||
    )
 | 
			
		||||
      has_livecheckable = resource.livecheckable?
 | 
			
		||||
 | 
			
		||||
      if debug
 | 
			
		||||
        puts "\n\n"
 | 
			
		||||
        puts "Resource:         #{resource.name}"
 | 
			
		||||
        puts "Livecheckable?:   #{has_livecheckable ? "Yes" : "No"}"
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      resource_version_info = {}
 | 
			
		||||
 | 
			
		||||
      livecheck = resource.livecheck
 | 
			
		||||
      livecheck_url = livecheck.url
 | 
			
		||||
      livecheck_regex = livecheck.regex
 | 
			
		||||
      livecheck_strategy = livecheck.strategy
 | 
			
		||||
      livecheck_strategy_block = livecheck.strategy_block
 | 
			
		||||
 | 
			
		||||
      livecheck_url_string = livecheck_url_to_string(livecheck_url, resource)
 | 
			
		||||
 | 
			
		||||
      urls = [livecheck_url_string] if livecheck_url_string
 | 
			
		||||
      urls ||= checkable_urls(resource)
 | 
			
		||||
 | 
			
		||||
      checked_urls = []
 | 
			
		||||
      # rubocop:disable Metrics/BlockLength
 | 
			
		||||
      urls.each_with_index do |original_url, i|
 | 
			
		||||
        # Only preprocess the URL when it's appropriate
 | 
			
		||||
        url = if STRATEGY_SYMBOLS_TO_SKIP_PREPROCESS_URL.include?(livecheck_strategy)
 | 
			
		||||
          original_url
 | 
			
		||||
        else
 | 
			
		||||
          preprocess_url(original_url)
 | 
			
		||||
        end
 | 
			
		||||
        next if checked_urls.include?(url)
 | 
			
		||||
 | 
			
		||||
        strategies = Strategy.from_url(
 | 
			
		||||
          url,
 | 
			
		||||
          livecheck_strategy: livecheck_strategy,
 | 
			
		||||
          url_provided:       livecheck_url.present?,
 | 
			
		||||
          regex_provided:     livecheck_regex.present?,
 | 
			
		||||
          block_provided:     livecheck_strategy_block.present?,
 | 
			
		||||
        )
 | 
			
		||||
        strategy = Strategy.from_symbol(livecheck_strategy) || strategies.first
 | 
			
		||||
        strategy_name = livecheck_strategy_names[strategy]
 | 
			
		||||
 | 
			
		||||
        if debug
 | 
			
		||||
          puts
 | 
			
		||||
          if livecheck_url.is_a?(Symbol)
 | 
			
		||||
            # This assumes the URL symbol will fit within the available space
 | 
			
		||||
            puts "URL (#{livecheck_url}):".ljust(18, " ") + original_url
 | 
			
		||||
          else
 | 
			
		||||
            puts "URL:              #{original_url}"
 | 
			
		||||
          end
 | 
			
		||||
          puts "URL (processed):  #{url}" if url != original_url
 | 
			
		||||
          if strategies.present? && verbose
 | 
			
		||||
            puts "Strategies:       #{strategies.map { |s| livecheck_strategy_names[s] }.join(", ")}"
 | 
			
		||||
          end
 | 
			
		||||
          puts "Strategy:         #{strategy.blank? ? "None" : strategy_name}"
 | 
			
		||||
          puts "Regex:            #{livecheck_regex.inspect}" if livecheck_regex.present?
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        if livecheck_strategy.present?
 | 
			
		||||
          if livecheck_url.blank? && strategy.method(:find_versions).parameters.include?([:keyreq, :url])
 | 
			
		||||
            odebug "#{strategy_name} strategy requires a URL"
 | 
			
		||||
            next
 | 
			
		||||
          elsif livecheck_strategy != :page_match && strategies.exclude?(strategy)
 | 
			
		||||
            odebug "#{strategy_name} strategy does not apply to this URL"
 | 
			
		||||
            next
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
        puts if debug && strategy.blank?
 | 
			
		||||
        next if strategy.blank?
 | 
			
		||||
 | 
			
		||||
        strategy_data = strategy.find_versions(
 | 
			
		||||
          url:           url,
 | 
			
		||||
          regex:         livecheck_regex,
 | 
			
		||||
          homebrew_curl: false,
 | 
			
		||||
          &livecheck_strategy_block
 | 
			
		||||
        )
 | 
			
		||||
        match_version_map = strategy_data[:matches]
 | 
			
		||||
        regex = strategy_data[:regex]
 | 
			
		||||
        messages = strategy_data[:messages]
 | 
			
		||||
        checked_urls << url
 | 
			
		||||
 | 
			
		||||
        if messages.is_a?(Array) && match_version_map.blank?
 | 
			
		||||
          puts messages unless json
 | 
			
		||||
          next if i + 1 < urls.length
 | 
			
		||||
 | 
			
		||||
          return status_hash(resource, "error", messages, verbose: verbose)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        if debug
 | 
			
		||||
          if strategy_data[:url].present? && strategy_data[:url] != url
 | 
			
		||||
            puts "URL (strategy):   #{strategy_data[:url]}"
 | 
			
		||||
          end
 | 
			
		||||
          puts "URL (final):      #{strategy_data[:final_url]}" if strategy_data[:final_url].present?
 | 
			
		||||
          if strategy_data[:regex].present? && strategy_data[:regex] != livecheck_regex
 | 
			
		||||
            puts "Regex (strategy): #{strategy_data[:regex].inspect}"
 | 
			
		||||
          end
 | 
			
		||||
          puts "Cached?:          Yes" if strategy_data[:cached] == true
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        match_version_map.delete_if do |_match, version|
 | 
			
		||||
          next true if version.blank?
 | 
			
		||||
          next false if has_livecheckable
 | 
			
		||||
 | 
			
		||||
          UNSTABLE_VERSION_KEYWORDS.any? do |rejection|
 | 
			
		||||
            version.to_s.include?(rejection)
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
        next if match_version_map.blank?
 | 
			
		||||
 | 
			
		||||
        if debug
 | 
			
		||||
          puts
 | 
			
		||||
          puts "Matched Versions:"
 | 
			
		||||
 | 
			
		||||
          if verbose
 | 
			
		||||
            match_version_map.each do |match, version|
 | 
			
		||||
              puts "#{match} => #{version.inspect}"
 | 
			
		||||
            end
 | 
			
		||||
          else
 | 
			
		||||
            puts match_version_map.values.join(", ")
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        res_current = resource.version
 | 
			
		||||
        res_latest = Version.new(match_version_map.values.max_by { |v| LivecheckVersion.create(resource, v) })
 | 
			
		||||
 | 
			
		||||
        return status_hash(resource, "error", ["Unable to get versions"], verbose: verbose) if res_latest.blank?
 | 
			
		||||
 | 
			
		||||
        is_outdated = res_current < res_latest
 | 
			
		||||
        is_newer_than_upstream = res_current > res_latest
 | 
			
		||||
 | 
			
		||||
        resource_version_info = {
 | 
			
		||||
          resource: resource.name,
 | 
			
		||||
          version:  {
 | 
			
		||||
            current:             res_current.to_s,
 | 
			
		||||
            latest:              res_latest.to_s,
 | 
			
		||||
            outdated:            is_outdated,
 | 
			
		||||
            newer_than_upstream: is_newer_than_upstream,
 | 
			
		||||
          },
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        resource_version_info[:meta] = { livecheckable: has_livecheckable, url: {} }
 | 
			
		||||
        if livecheck_url.is_a?(Symbol) && livecheck_url_string
 | 
			
		||||
          resource_version_info[:meta][:url][:symbol] = livecheck_url
 | 
			
		||||
        end
 | 
			
		||||
        resource_version_info[:meta][:url][:original] = original_url
 | 
			
		||||
        resource_version_info[:meta][:url][:processed] = url if url != original_url
 | 
			
		||||
        if strategy_data[:url].present? && strategy_data[:url] != url
 | 
			
		||||
          resource_version_info[:meta][:url][:strategy] = strategy_data[:url]
 | 
			
		||||
        end
 | 
			
		||||
        resource_version_info[:meta][:url][:final] = strategy_data[:final_url] if strategy_data[:final_url]
 | 
			
		||||
        resource_version_info[:meta][:strategy] = strategy.present? ? strategy_name : nil
 | 
			
		||||
        if strategies.present?
 | 
			
		||||
          resource_version_info[:meta][:strategies] = strategies.map { |s| livecheck_strategy_names[s] }
 | 
			
		||||
        end
 | 
			
		||||
        resource_version_info[:meta][:regex] = regex.inspect if regex.present?
 | 
			
		||||
        resource_version_info[:meta][:cached] = true if strategy_data[:cached] == true
 | 
			
		||||
 | 
			
		||||
      rescue => e
 | 
			
		||||
        Homebrew.failed = true
 | 
			
		||||
        if json
 | 
			
		||||
          status_hash(resource, "error", [e.to_s], verbose: verbose)
 | 
			
		||||
        elsif !quiet
 | 
			
		||||
          onoe "#{Tty.blue}#{resource.name}#{Tty.reset}: #{e}"
 | 
			
		||||
          $stderr.puts e.backtrace if debug && !e.is_a?(Livecheck::Error)
 | 
			
		||||
          nil
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
      # rubocop:enable Metrics/BlockLength
 | 
			
		||||
      resource_version_info
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
  # rubocop:enable Metrics/ModuleLength
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -11,15 +11,17 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      include Comparable
 | 
			
		||||
 | 
			
		||||
      sig { params(formula_or_cask: T.any(Formula, Cask::Cask), version: Version).returns(LivecheckVersion) }
 | 
			
		||||
      def self.create(formula_or_cask, version)
 | 
			
		||||
        versions = case formula_or_cask
 | 
			
		||||
        when Formula
 | 
			
		||||
      sig {
 | 
			
		||||
        params(package_or_resource: T.any(Formula, Cask::Cask, Resource), version: Version).returns(LivecheckVersion)
 | 
			
		||||
      }
 | 
			
		||||
      def self.create(package_or_resource, version)
 | 
			
		||||
        versions = case package_or_resource
 | 
			
		||||
        when Formula, Resource
 | 
			
		||||
          [version]
 | 
			
		||||
        when Cask::Cask
 | 
			
		||||
          version.to_s.split(/[,:]/).map { |s| Version.new(s) }
 | 
			
		||||
        else
 | 
			
		||||
          T.absurd(formula_or_cask)
 | 
			
		||||
          T.absurd(package_or_resource)
 | 
			
		||||
        end
 | 
			
		||||
        new(versions)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,7 @@ require "livecheck/livecheck"
 | 
			
		||||
module Homebrew
 | 
			
		||||
  module Livecheck
 | 
			
		||||
    # The `Livecheck::SkipConditions` module primarily contains methods that
 | 
			
		||||
    # check for various formula/cask conditions where a check should be skipped.
 | 
			
		||||
    # check for various formula/cask/resource conditions where a check should be skipped.
 | 
			
		||||
    #
 | 
			
		||||
    # @api private
 | 
			
		||||
    module SkipConditions
 | 
			
		||||
@ -16,14 +16,14 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      sig {
 | 
			
		||||
        params(
 | 
			
		||||
          formula_or_cask: T.any(Formula, Cask::Cask),
 | 
			
		||||
          livecheckable:   T::Boolean,
 | 
			
		||||
          full_name:       T::Boolean,
 | 
			
		||||
          verbose:         T::Boolean,
 | 
			
		||||
          package_or_resource: T.any(Formula, Cask::Cask, Resource),
 | 
			
		||||
          livecheckable:       T::Boolean,
 | 
			
		||||
          full_name:           T::Boolean,
 | 
			
		||||
          verbose:             T::Boolean,
 | 
			
		||||
        ).returns(Hash)
 | 
			
		||||
      }
 | 
			
		||||
      def formula_or_cask_skip(formula_or_cask, livecheckable, full_name: false, verbose: false)
 | 
			
		||||
        formula = formula_or_cask if formula_or_cask.is_a?(Formula)
 | 
			
		||||
      def package_or_resource_skip(package_or_resource, livecheckable, full_name: false, verbose: false)
 | 
			
		||||
        formula = package_or_resource if package_or_resource.is_a?(Formula)
 | 
			
		||||
 | 
			
		||||
        if (stable_url = formula&.stable&.url)
 | 
			
		||||
          stable_is_gist = stable_url.match?(%r{https?://gist\.github(?:usercontent)?\.com/}i)
 | 
			
		||||
@ -33,8 +33,8 @@ module Homebrew
 | 
			
		||||
          stable_from_internet_archive = stable_url.match?(%r{https?://web\.archive\.org/}i)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        skip_message = if formula_or_cask.livecheck.skip_msg.present?
 | 
			
		||||
          formula_or_cask.livecheck.skip_msg
 | 
			
		||||
        skip_message = if package_or_resource.livecheck.skip_msg.present?
 | 
			
		||||
          package_or_resource.livecheck.skip_msg
 | 
			
		||||
        elsif !livecheckable
 | 
			
		||||
          if stable_from_google_code_archive
 | 
			
		||||
            "Stable URL is from Google Code Archive"
 | 
			
		||||
@ -45,10 +45,10 @@ module Homebrew
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        return {} if !formula_or_cask.livecheck.skip? && skip_message.blank?
 | 
			
		||||
        return {} if !package_or_resource.livecheck.skip? && skip_message.blank?
 | 
			
		||||
 | 
			
		||||
        skip_messages = skip_message ? [skip_message] : nil
 | 
			
		||||
        Livecheck.status_hash(formula_or_cask, "skipped", skip_messages, full_name: full_name, verbose: verbose)
 | 
			
		||||
        Livecheck.status_hash(package_or_resource, "skipped", skip_messages, full_name: full_name, verbose: verbose)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      sig {
 | 
			
		||||
@ -157,7 +157,7 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      # Skip conditions for formulae.
 | 
			
		||||
      FORMULA_CHECKS = [
 | 
			
		||||
        :formula_or_cask_skip,
 | 
			
		||||
        :package_or_resource_skip,
 | 
			
		||||
        :formula_head_only,
 | 
			
		||||
        :formula_deprecated,
 | 
			
		||||
        :formula_disabled,
 | 
			
		||||
@ -166,76 +166,85 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      # Skip conditions for casks.
 | 
			
		||||
      CASK_CHECKS = [
 | 
			
		||||
        :formula_or_cask_skip,
 | 
			
		||||
        :package_or_resource_skip,
 | 
			
		||||
        :cask_discontinued,
 | 
			
		||||
        :cask_version_latest,
 | 
			
		||||
        :cask_url_unversioned,
 | 
			
		||||
      ].freeze
 | 
			
		||||
 | 
			
		||||
      # If a formula/cask should be skipped, we return a hash from
 | 
			
		||||
      # Skip conditions for resources.
 | 
			
		||||
      RESOURCE_CHECKS = [
 | 
			
		||||
        :package_or_resource_skip,
 | 
			
		||||
      ].freeze
 | 
			
		||||
 | 
			
		||||
      # If a formula/cask/resource should be skipped, we return a hash from
 | 
			
		||||
      # `Livecheck#status_hash`, which contains a `status` type and sometimes
 | 
			
		||||
      # error `messages`.
 | 
			
		||||
      sig {
 | 
			
		||||
        params(
 | 
			
		||||
          formula_or_cask: T.any(Formula, Cask::Cask),
 | 
			
		||||
          full_name:       T::Boolean,
 | 
			
		||||
          verbose:         T::Boolean,
 | 
			
		||||
          package_or_resource: T.any(Formula, Cask::Cask, Resource),
 | 
			
		||||
          full_name:           T::Boolean,
 | 
			
		||||
          verbose:             T::Boolean,
 | 
			
		||||
        ).returns(Hash)
 | 
			
		||||
      }
 | 
			
		||||
      def skip_information(formula_or_cask, full_name: false, verbose: false)
 | 
			
		||||
        livecheckable = formula_or_cask.livecheckable?
 | 
			
		||||
      def skip_information(package_or_resource, full_name: false, verbose: false)
 | 
			
		||||
        livecheckable = package_or_resource.livecheckable?
 | 
			
		||||
 | 
			
		||||
        checks = case formula_or_cask
 | 
			
		||||
        checks = case package_or_resource
 | 
			
		||||
        when Formula
 | 
			
		||||
          FORMULA_CHECKS
 | 
			
		||||
        when Cask::Cask
 | 
			
		||||
          CASK_CHECKS
 | 
			
		||||
        when Resource
 | 
			
		||||
          RESOURCE_CHECKS
 | 
			
		||||
        end
 | 
			
		||||
        return {} unless checks
 | 
			
		||||
 | 
			
		||||
        checks.each do |method_name|
 | 
			
		||||
          skip_hash = send(method_name, formula_or_cask, livecheckable, full_name: full_name, verbose: verbose)
 | 
			
		||||
          skip_hash = send(method_name, package_or_resource, livecheckable, full_name: full_name, verbose: verbose)
 | 
			
		||||
          return skip_hash if skip_hash.present?
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        {}
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # Skip conditions for formulae/casks referenced in a `livecheck` block
 | 
			
		||||
      # Skip conditions for formulae/casks/resources referenced in a `livecheck` block
 | 
			
		||||
      # are treated differently than normal. We only respect certain skip
 | 
			
		||||
      # conditions (returning the related hash) and others are treated as
 | 
			
		||||
      # errors.
 | 
			
		||||
      sig {
 | 
			
		||||
        params(
 | 
			
		||||
          livecheck_formula_or_cask:     T.any(Formula, Cask::Cask),
 | 
			
		||||
          original_formula_or_cask_name: String,
 | 
			
		||||
          full_name:                     T::Boolean,
 | 
			
		||||
          verbose:                       T::Boolean,
 | 
			
		||||
          livecheck_package_or_resource:     T.any(Formula, Cask::Cask, Resource),
 | 
			
		||||
          original_package_or_resource_name: String,
 | 
			
		||||
          full_name:                         T::Boolean,
 | 
			
		||||
          verbose:                           T::Boolean,
 | 
			
		||||
        ).returns(T.nilable(Hash))
 | 
			
		||||
      }
 | 
			
		||||
      def referenced_skip_information(
 | 
			
		||||
        livecheck_formula_or_cask,
 | 
			
		||||
        original_formula_or_cask_name,
 | 
			
		||||
        livecheck_package_or_resource,
 | 
			
		||||
        original_package_or_resource_name,
 | 
			
		||||
        full_name: false,
 | 
			
		||||
        verbose: false
 | 
			
		||||
      )
 | 
			
		||||
        skip_info = SkipConditions.skip_information(
 | 
			
		||||
          livecheck_formula_or_cask,
 | 
			
		||||
          livecheck_package_or_resource,
 | 
			
		||||
          full_name: full_name,
 | 
			
		||||
          verbose:   verbose,
 | 
			
		||||
        )
 | 
			
		||||
        return if skip_info.blank?
 | 
			
		||||
 | 
			
		||||
        referenced_name = Livecheck.formula_or_cask_name(livecheck_formula_or_cask, full_name: full_name)
 | 
			
		||||
        referenced_type = case livecheck_formula_or_cask
 | 
			
		||||
        referenced_name = Livecheck.package_or_resource_name(livecheck_package_or_resource, full_name: full_name)
 | 
			
		||||
        referenced_type = case livecheck_package_or_resource
 | 
			
		||||
        when Formula
 | 
			
		||||
          :formula
 | 
			
		||||
        when Cask::Cask
 | 
			
		||||
          :cask
 | 
			
		||||
        when Resource
 | 
			
		||||
          :resource
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        if skip_info[:status] != "error" &&
 | 
			
		||||
           !(skip_info[:status] == "skipped" && livecheck_formula_or_cask.livecheck.skip?)
 | 
			
		||||
           !(skip_info[:status] == "skipped" && livecheck_package_or_resource.livecheck.skip?)
 | 
			
		||||
          error_msg_end = if skip_info[:status] == "skipped"
 | 
			
		||||
            "automatically skipped"
 | 
			
		||||
          else
 | 
			
		||||
@ -245,7 +254,7 @@ module Homebrew
 | 
			
		||||
          raise "Referenced #{referenced_type} (#{referenced_name}) is #{error_msg_end}"
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        skip_info[referenced_type] = original_formula_or_cask_name
 | 
			
		||||
        skip_info[referenced_type] = original_package_or_resource_name
 | 
			
		||||
        skip_info
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
@ -258,6 +267,8 @@ module Homebrew
 | 
			
		||||
          skip_hash[:formula]
 | 
			
		||||
        elsif skip_hash[:cask].is_a?(String)
 | 
			
		||||
          skip_hash[:cask]
 | 
			
		||||
        elsif skip_hash[:resource].is_a?(String)
 | 
			
		||||
          "  #{skip_hash[:resource]}"
 | 
			
		||||
        end
 | 
			
		||||
        return unless name
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -11,6 +11,7 @@ describe Homebrew::Livecheck do
 | 
			
		||||
  let(:homepage_url) { "https://brew.sh" }
 | 
			
		||||
  let(:livecheck_url) { "https://formulae.brew.sh/api/formula/ruby.json" }
 | 
			
		||||
  let(:stable_url) { "https://brew.sh/test-0.0.1.tgz" }
 | 
			
		||||
  let(:resource_url) { "https://brew.sh/foo-1.0.tar.gz" }
 | 
			
		||||
 | 
			
		||||
  let(:f) do
 | 
			
		||||
    formula("test") do
 | 
			
		||||
@ -23,9 +24,21 @@ describe Homebrew::Livecheck do
 | 
			
		||||
        url "https://formulae.brew.sh/api/formula/ruby.json"
 | 
			
		||||
        regex(/"stable":"(\d+(?:\.\d+)+)"/i)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      resource "foo" do
 | 
			
		||||
        url "https://brew.sh/foo-1.0.tar.gz"
 | 
			
		||||
        sha256 "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
 | 
			
		||||
 | 
			
		||||
        livecheck do
 | 
			
		||||
          url "https://brew.sh/test/releases"
 | 
			
		||||
          regex(/foo[._-]v?(\d+(?:\.\d+)+)\.t/i)
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  let(:r) { f.resources.first }
 | 
			
		||||
 | 
			
		||||
  let(:c) do
 | 
			
		||||
    Cask::CaskLoader.load(+<<-RUBY)
 | 
			
		||||
      cask "test" do
 | 
			
		||||
@ -44,15 +57,6 @@ describe Homebrew::Livecheck do
 | 
			
		||||
    RUBY
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  let(:f_duplicate_urls) do
 | 
			
		||||
    formula("test_duplicate_urls") do
 | 
			
		||||
      desc "Test formula with a duplicate URL"
 | 
			
		||||
      homepage "https://github.com/Homebrew/brew.git"
 | 
			
		||||
      url "https://brew.sh/test-0.0.1.tgz"
 | 
			
		||||
      head "https://github.com/Homebrew/brew.git"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "::resolve_livecheck_reference" do
 | 
			
		||||
    context "when a formula/cask has a livecheck block without formula/cask methods" do
 | 
			
		||||
      it "returns [nil, []]" do
 | 
			
		||||
@ -83,7 +87,7 @@ describe Homebrew::Livecheck do
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "::status_hash" do
 | 
			
		||||
    it "returns a hash containing the livecheck status" do
 | 
			
		||||
    it "returns a hash containing the livecheck status for a formula" do
 | 
			
		||||
      expect(livecheck.status_hash(f, "error", ["Unable to get versions"]))
 | 
			
		||||
        .to eq({
 | 
			
		||||
          formula:  "test",
 | 
			
		||||
@ -94,6 +98,18 @@ describe Homebrew::Livecheck do
 | 
			
		||||
          },
 | 
			
		||||
        })
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "returns a hash containing the livecheck status for a resource" do
 | 
			
		||||
      expect(livecheck.status_hash(r, "error", ["Unable to get versions"]))
 | 
			
		||||
        .to eq({
 | 
			
		||||
          resource: "foo",
 | 
			
		||||
          status:   "error",
 | 
			
		||||
          messages: ["Unable to get versions"],
 | 
			
		||||
          meta:     {
 | 
			
		||||
            livecheckable: true,
 | 
			
		||||
          },
 | 
			
		||||
        })
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "::livecheck_url_to_string" do
 | 
			
		||||
@ -101,15 +117,28 @@ describe Homebrew::Livecheck do
 | 
			
		||||
      homepage_url_s = homepage_url
 | 
			
		||||
      stable_url_s = stable_url
 | 
			
		||||
      head_url_s = head_url
 | 
			
		||||
      resource_url_s = resource_url
 | 
			
		||||
 | 
			
		||||
      formula("test_livecheck_url") do
 | 
			
		||||
        desc "Test Livecheck URL formula"
 | 
			
		||||
        homepage homepage_url_s
 | 
			
		||||
        url stable_url_s
 | 
			
		||||
        head head_url_s
 | 
			
		||||
 | 
			
		||||
        resource "foo" do
 | 
			
		||||
          url resource_url_s
 | 
			
		||||
          sha256 "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
 | 
			
		||||
 | 
			
		||||
          livecheck do
 | 
			
		||||
            url "https://brew.sh/test/releases"
 | 
			
		||||
            regex(/foo[._-]v?(\d+(?:\.\d+)+)\.t/i)
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    let(:r_livecheck_url) { f_livecheck_url.resources.first }
 | 
			
		||||
 | 
			
		||||
    let(:c_livecheck_url) do
 | 
			
		||||
      Cask::CaskLoader.load(+<<-RUBY)
 | 
			
		||||
        cask "test_livecheck_url" do
 | 
			
		||||
@ -123,30 +152,48 @@ describe Homebrew::Livecheck do
 | 
			
		||||
      RUBY
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "returns a URL string when given a livecheck_url string" do
 | 
			
		||||
    it "returns a URL string when given a livecheck_url string for a formula" do
 | 
			
		||||
      expect(livecheck.livecheck_url_to_string(livecheck_url, f_livecheck_url)).to eq(livecheck_url)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "returns a URL string when given a livecheck_url string for a resource" do
 | 
			
		||||
      expect(livecheck.livecheck_url_to_string(livecheck_url, r_livecheck_url)).to eq(livecheck_url)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "returns a URL symbol when given a valid livecheck_url symbol" do
 | 
			
		||||
      expect(livecheck.livecheck_url_to_string(:head, f_livecheck_url)).to eq(head_url)
 | 
			
		||||
      expect(livecheck.livecheck_url_to_string(:homepage, f_livecheck_url)).to eq(homepage_url)
 | 
			
		||||
      expect(livecheck.livecheck_url_to_string(:homepage, c_livecheck_url)).to eq(homepage_url)
 | 
			
		||||
      expect(livecheck.livecheck_url_to_string(:stable, f_livecheck_url)).to eq(stable_url)
 | 
			
		||||
      expect(livecheck.livecheck_url_to_string(:url, c_livecheck_url)).to eq(cask_url)
 | 
			
		||||
      expect(livecheck.livecheck_url_to_string(:url, r_livecheck_url)).to eq(resource_url)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "returns nil when not given a string or valid symbol" do
 | 
			
		||||
      expect(livecheck.livecheck_url_to_string(nil, f_livecheck_url)).to be_nil
 | 
			
		||||
      expect(livecheck.livecheck_url_to_string(nil, c_livecheck_url)).to be_nil
 | 
			
		||||
      expect(livecheck.livecheck_url_to_string(nil, r_livecheck_url)).to be_nil
 | 
			
		||||
      expect(livecheck.livecheck_url_to_string(:invalid_symbol, f_livecheck_url)).to be_nil
 | 
			
		||||
      expect(livecheck.livecheck_url_to_string(:invalid_symbol, c_livecheck_url)).to be_nil
 | 
			
		||||
      expect(livecheck.livecheck_url_to_string(:invalid_symbol, r_livecheck_url)).to be_nil
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "::checkable_urls" do
 | 
			
		||||
    let(:resource_url) { "https://brew.sh/foo-1.0.tar.gz" }
 | 
			
		||||
    let(:f_duplicate_urls) do
 | 
			
		||||
      formula("test_duplicate_urls") do
 | 
			
		||||
        desc "Test formula with a duplicate URL"
 | 
			
		||||
        homepage "https://github.com/Homebrew/brew.git"
 | 
			
		||||
        url "https://brew.sh/test-0.0.1.tgz"
 | 
			
		||||
        head "https://github.com/Homebrew/brew.git"
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it "returns the list of URLs to check" do
 | 
			
		||||
      expect(livecheck.checkable_urls(f)).to eq([stable_url, head_url, homepage_url])
 | 
			
		||||
      expect(livecheck.checkable_urls(c)).to eq([cask_url, homepage_url])
 | 
			
		||||
      expect(livecheck.checkable_urls(r)).to eq([resource_url])
 | 
			
		||||
      expect(livecheck.checkable_urls(f_duplicate_urls)).to eq([stable_url, head_url])
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@ require "livecheck/livecheck_version"
 | 
			
		||||
describe Homebrew::Livecheck::LivecheckVersion do
 | 
			
		||||
  let(:formula) { instance_double(Formula) }
 | 
			
		||||
  let(:cask) { instance_double(Cask::Cask) }
 | 
			
		||||
  let(:resource) { instance_double(Resource) }
 | 
			
		||||
 | 
			
		||||
  before do
 | 
			
		||||
    # Case statements use #=== for case equality purposes
 | 
			
		||||
@ -13,6 +14,8 @@ describe Homebrew::Livecheck::LivecheckVersion do
 | 
			
		||||
    allow(Formula).to receive(:===).with(formula).and_return(true)
 | 
			
		||||
    allow(Cask::Cask).to receive(:===).and_call_original
 | 
			
		||||
    allow(Cask::Cask).to receive(:===).with(cask).and_return(true)
 | 
			
		||||
    allow(Resource).to receive(:===).and_call_original
 | 
			
		||||
    allow(Resource).to receive(:===).with(resource).and_return(true)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  specify "::create" do
 | 
			
		||||
@ -28,5 +31,11 @@ describe Homebrew::Livecheck::LivecheckVersion do
 | 
			
		||||
      .to eq ["1.0", "100", "1426778671"]
 | 
			
		||||
    expect(described_class.create(cask, Version.new("0.17.0,20210111183933,226")).versions)
 | 
			
		||||
      .to eq ["0.17.0", "20210111183933", "226"]
 | 
			
		||||
 | 
			
		||||
    expect(described_class.create(resource, Version.new("1.1.6")).versions).to eq ["1.1.6"]
 | 
			
		||||
    expect(described_class.create(resource, Version.new("2.19.0,1.8.0")).versions).to eq ["2.19.0,1.8.0"]
 | 
			
		||||
    expect(described_class.create(resource, Version.new("1.0,100:1426778671")).versions).to eq ["1.0,100:1426778671"]
 | 
			
		||||
    expect(described_class.create(resource, Version.new("0.17.0,20210111183933,226")).versions)
 | 
			
		||||
      .to eq ["0.17.0,20210111183933,226"]
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user