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

Inherits:
Object
  • Object
show all
Extended by:
Homebrew::Livecheck::Strategic, 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 =

This constant is part of a private API. This constant may only be used in the Homebrew/brew repository. Third parties should avoid using this constant if possible, as it may be removed or changed without warning.

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

8
TAG_REGEX =

This constant is part of a private API. This constant may only be used in the Homebrew/brew repository. Third parties should avoid using this constant if possible, as it may be removed or changed without warning.

The regex used to extract tags from git ls-remote --tags output.

%r{^\h+\s+refs/tags/(.+?)(?:\^{})?$}
DEFAULT_REGEX =

This constant is part of a private API. This constant may only be used in the Homebrew/brew repository. Third parties should avoid using this constant if possible, as it may be removed or changed without warning.

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

/\D*(.+)/

Class Method Summary collapse

Methods included from Homebrew::Livecheck::Strategic

find_versions, match?

Methods included from SystemCommand::Mixin

system_command, system_command!

Class Method Details

.find_versions(url:, regex: nil, content: nil, options: Options.new, &block) ⇒ Hash{Symbol => T.anything}

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

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 for matching versions in content

  • content (String, nil) (defaults to: nil)

    content to check instead of fetching

  • options (Options) (defaults to: Options.new)

    options to modify behavior

  • block (Proc, nil)

Returns:



202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'livecheck/strategy/git.rb', line 202

def self.find_versions(url:, regex: nil, content: nil, options: Options.new, &block)
  match_data = { matches: {}, regex:, url: }
  match_data[:cached] = true if content
  return match_data if url.blank?

  unless match_data[:cached]
    match_data.merge!(ls_remote_tags(url))
    content = match_data[:content]
  end
  return match_data if content.blank?

  versions_from_content(content, regex, &block).each do |match_text|
    match_data[:matches][match_text] = Version.new(match_text)
  rescue TypeError
    next
  end

  match_data
end

.ls_remote_tags(url) ⇒ Hash{Symbol => String, Array<String>}

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Runs git ls-remote --tags with the provided URL and returns a hash containing the stdout content or any errors from stderr.

Parameters:

  • url (String)

    the URL of the Git repository to check

Returns:



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'livecheck/strategy/git.rb', line 124

def self.ls_remote_tags(url)
  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,
  ).to_a

  data = {}
  data[:content] = stdout.clone if stdout.present?
  data[:messages] = stderr.split("\n") if stderr.present?

  data
end

.match?(url) ⇒ Boolean

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Whether the strategy can be applied to the provided URL.

Parameters:

  • url (String)

    the URL to match against

Returns:

  • (Boolean)


113
114
115
116
# File 'livecheck/strategy/git.rb', line 113

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

.preprocess_url(url) ⇒ String

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Processes and returns the URL used by livecheck.

Parameters:

Returns:



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'livecheck/strategy/git.rb', line 61

def self.preprocess_url(url)
  processed_url = @processed_urls[url]
  return processed_url if processed_url

  begin
    uri = Addressable::URI.parse(url)
  rescue Addressable::URI::InvalidURIError
    return url
  end

  host = uri.host
  path = uri.path
  return url if host.nil? || path.blank?

  host = "github.com" if host == "github.s3.amazonaws.com"
  path = path.delete_prefix("/").delete_suffix(".git")
  scheme = uri.scheme

  if host == "github.com"
    return url if path.match? %r{/releases/latest/?$}

    owner, repo = path.delete_prefix("downloads/").split("/")
    processed_url = "#{scheme}://#{host}/#{owner}/#{repo}.git"
  elsif GITEA_INSTANCES.include?(host)
    return url if path.match? %r{/releases/latest/?$}

    owner, repo = path.split("/")
    processed_url = "#{scheme}://#{host}/#{owner}/#{repo}.git"
  elsif GOGS_INSTANCES.include?(host)
    owner, repo = path.split("/")
    processed_url = "#{scheme}://#{host}/#{owner}/#{repo}.git"
  # sourcehut
  elsif host == "git.sr.ht"
    owner, repo = path.split("/")
    processed_url = "#{scheme}://#{host}/#{owner}/#{repo}"
  # GitLab (gitlab.com or self-hosted)
  elsif path.include?("/-/archive/")
    processed_url = url.sub(%r{/-/archive/.*$}i, ".git")
  end

  if processed_url && (processed_url != url)
    @processed_urls[url] = processed_url
  else
    url
  end
end

.tags_from_content(content) ⇒ Array<String>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parse tags from git ls-remote --tags output.

Parameters:

  • content (String)

    Git output to parse for tags

Returns:



147
148
149
# File 'livecheck/strategy/git.rb', line 147

def self.tags_from_content(content)
  content.scan(TAG_REGEX).flatten.uniq
end

.versions_from_content(content, regex = nil, &block) ⇒ Array<String>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Identify versions from git ls-remote --tags output using a provided regex or the DEFAULT_REGEX. The regex is expected to use a capture group around the version text.

Parameters:

  • content (String)

    the content to check

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

    a regex for matching versions in content

  • block (Proc, nil)

Returns:



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'livecheck/strategy/git.rb', line 165

def self.versions_from_content(content, regex = nil, &block)
  tags = tags_from_content(content)
  return [] if tags.empty?

  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

  match_regex = regex || DEFAULT_REGEX
  tags.filter_map { |tag| tag[match_regex, 1] }.uniq
end