Class: Homebrew::Livecheck::Strategy::Git

Inherits:
Object
  • Object
show all
Extended by:
SystemCommand::Mixin
Defined in:
livecheck/strategy/git.rb

Overview

The Git strategy identifies versions of software in a Git repository by checking the tags using git ls-remote --tags.

Livecheck has historically prioritized the Git strategy over others and this behavior was continued when the priority setup was created. This is partly related to Livecheck checking formula URLs in order of head, stable, and then homepage. The higher priority here may be removed (or altered) in the future if we reevaluate this particular behavior.

This strategy does not have a default regex. Instead, it simply removes any non-digit text from the start of tags and parses the rest as a Version. This works for some simple situations but even one unusual tag can cause a bad result. It’s better to provide a regex in a livecheck block, so livecheck only matches what we really want.

Constant Summary collapse

PRIORITY =

The priority of the strategy on an informal scale of 1 to 10 (from lowest to highest).

8
DEFAULT_REGEX =

The default regex used to naively identify versions from tags when a regex isn’t provided.

/\D*(.+)/

Class Method Summary collapse

Methods included from SystemCommand::Mixin

system_command, system_command!

Class Method Details

.find_versions(url:, regex: nil, **_unused, &block) ⇒ Hash{Symbol => T.untyped}

Checks the Git tags for new versions. When a regex isn’t provided, this strategy simply removes non-digits from the start of tag strings and parses the remaining text as a Version.

Parameters:

  • url (String)

    the URL of the Git repository to check

  • regex (Regexp, nil) (defaults to: nil)

    a regex used for matching versions

  • _unused (T.untyped)
  • block (Proc, nil)

Returns:



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'livecheck/strategy/git.rb', line 132

def self.find_versions(url:, regex: nil, **_unused, &block)
  match_data = { matches: {}, regex: regex, url: url }

  tags_data = tag_info(url, regex)
  tags = tags_data[:tags]

  if tags_data.key?(:messages)
    match_data[:messages] = tags_data[:messages]
    return match_data if tags.blank?
  end

  versions_from_tags(tags, regex, &block).each do |version_text|
    match_data[:matches][version_text] = Version.new(version_text)
  rescue TypeError
    next
  end

  match_data
end

.match?(url) ⇒ Boolean

Whether the strategy can be applied to the provided URL.

Parameters:

  • url (String)

    the URL to match against

Returns:

  • (Boolean)


43
44
45
# File 'livecheck/strategy/git.rb', line 43

def self.match?(url)
  (DownloadStrategyDetector.detect(url) <= GitDownloadStrategy) == true
end

.tag_info(url, regex = nil) ⇒ Hash{Symbol => T.untyped}

Fetches a remote Git repository’s tags using git ls-remote --tags and parses the command’s output. If a regex is provided, it will be used to filter out any tags that don’t match it.

Parameters:

  • url (String)

    the URL of the Git repository to check

  • regex (Regexp, nil) (defaults to: nil)

    the regex to use for filtering tags

Returns:



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'livecheck/strategy/git.rb', line 55

def self.tag_info(url, regex = nil)
  stdout, stderr, _status = system_command(
    "git",
    args:         ["ls-remote", "--tags", url],
    env:          { "GIT_TERMINAL_PROMPT" => "0" },
    print_stdout: false,
    print_stderr: false,
    debug:        false,
    verbose:      false,
  )

  tags_data = { tags: [] }
  tags_data[:messages] = stderr.split("\n") if stderr.present?
  return tags_data if stdout.blank?

  # Isolate tag strings and filter by regex
  tags = stdout.gsub(%r{^.*\trefs/tags/|\^{}$}, "").split("\n").uniq.sort
  tags.select! { |t| regex.match?(t) } if regex
  tags_data[:tags] = tags

  tags_data
end

.versions_from_tags(tags, regex = nil, &block) ⇒ Array<String>

Identify versions from tag strings using a provided regex or the DEFAULT_REGEX. The regex is expected to use a capture group around the version text.

Parameters:

  • tags (Array<String>)

    the tags to identify versions from

  • regex (Regexp, nil) (defaults to: nil)

    a regex to identify versions

  • block (Proc, nil)

Returns:



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'livecheck/strategy/git.rb', line 92

def self.versions_from_tags(tags, regex = nil, &block)
  if block
    block_return_value = if regex.present?
      yield(tags, regex)
    elsif block.arity == 2
      yield(tags, DEFAULT_REGEX)
    else
      yield(tags)
    end
    return Strategy.handle_block_return(block_return_value)
  end

  tags.filter_map do |tag|
    if regex
      # Use the first capture group (the version)
      # This code is not typesafe unless the regex includes a capture group
      T.unsafe(tag.scan(regex).first)&.first
    else
      # Remove non-digits from the start of the tag and use that as the
      # version text
      tag[DEFAULT_REGEX, 1]
    end
  end.uniq
end