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 Attribute Summary collapse

Class Method Summary collapse

Methods included from Homebrew::Livecheck::Strategic

find_versions, match?

Methods included from SystemCommand::Mixin

system_command, system_command!

Class Attribute Details

.processed_urls=(value) ⇒ void (writeonly)

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.

This method returns an undefined value.



37
38
39
# File 'livecheck/strategy/git.rb', line 37

def processed_urls=(value)
  @processed_urls = value
end

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:



207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'livecheck/strategy/git.rb', line 207

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|
    next unless match_text.is_a?(String)

    match_data[:matches][match_text] = Version.new(match_text)
  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:



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'livecheck/strategy/git.rb', line 129

def self.ls_remote_tags(url)
  stdout, stderr, _status = system_command(
    "git",
    args:         ["ls-remote", "--tags", "--end-of-options", 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)


118
119
120
121
# File 'livecheck/strategy/git.rb', line 118

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:



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
107
108
109
110
111
# File 'livecheck/strategy/git.rb', line 66

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

  begin
    uri = URI.parse(url)
  rescue 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:



152
153
154
# File 'livecheck/strategy/git.rb', line 152

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:



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'livecheck/strategy/git.rb', line 170

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