Class: Vanagon::Component::Source::Git

Inherits:
Object
  • Object
show all
Defined in:
lib/vanagon/component/source/git.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(url, workdir:, **options) ⇒ Git

Constructor for the Git source type

Parameters:

  • url (String)

    url of git repo to use as source

  • ref (String)

    ref to checkout from git repo

  • workdir (String)

    working directory to clone into

Raises:



97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/vanagon/component/source/git.rb', line 97

def initialize(url, workdir:, **options) # rubocop:disable Metrics/AbcSize
  opts = default_options.merge(options.reject { |k, v| v.nil? })

  # Ensure that #url returns a URI object
  @url = Build::URI.parse(url.to_s)
  @log_url = @url.host + @url.path unless @url.host.nil? || @url.path.nil?
  @ref = opts[:ref]
  @dirname = opts[:dirname]
  @workdir = File.realpath(workdir)
  @clone_options = opts[:clone_options] ||= {}

  # We can test for Repo existence without cloning
  raise Vanagon::InvalidRepo, "\"#{url}\" is not a valid Git repo" unless valid_remote?
end

Instance Attribute Details

#clone_optionsObject

Returns the value of attribute clone_options.



16
17
18
# File 'lib/vanagon/component/source/git.rb', line 16

def clone_options
  @clone_options
end

#log_urlObject

Returns the value of attribute log_url.



16
17
18
# File 'lib/vanagon/component/source/git.rb', line 16

def log_url
  @log_url
end

#refObject

Returns the value of attribute ref.



16
17
18
# File 'lib/vanagon/component/source/git.rb', line 16

def ref
  @ref
end

#repoObject (readonly)

Returns the value of attribute repo.



17
18
19
# File 'lib/vanagon/component/source/git.rb', line 17

def repo
  @repo
end

#urlObject

Returns the value of attribute url.



16
17
18
# File 'lib/vanagon/component/source/git.rb', line 16

def url
  @url
end

#versionObject (readonly)

Use ‘git describe` to lazy-load a version for this component



143
144
145
# File 'lib/vanagon/component/source/git.rb', line 143

def version
  @version
end

#workdirObject

Returns the value of attribute workdir.



16
17
18
# File 'lib/vanagon/component/source/git.rb', line 16

def workdir
  @workdir
end

Class Method Details

.github_remote?(url) ⇒ Boolean

Returns:

  • (Boolean)


56
57
58
# File 'lib/vanagon/component/source/git.rb', line 56

def github_remote?(url)
  github_source_type(url) == :github_remote
end

.github_source_type(url) ⇒ Object

VANAGON-227 We need to be careful when guessing whether a github.com/… URL is actually a true git repo. Make some rules around it based on the github API. Decide that anything with a documented media_type is just an http url. We do this instead of talking to GitHub directly to avoid rate limiting. See: docs.github.com/en/repositories/working-with-files/using-files/downloading-source-code-archives docs.github.com/en/rest/repos/contents?apiVersion=2022-11-28#download-a-repository-archive-tar docs.github.com/en/rest/repos/contents?apiVersion=2022-11-28#download-a-repository-archive-zip



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/vanagon/component/source/git.rb', line 68

def github_source_type(url)
  url_directory = url.to_s.delete_prefix(github_url_prefix)
  url_components = url_directory.split('/')

  # Find cases of supported github media types.
  # [ owner, repo, media_type, ref ]
  path_types = ['archive', 'releases', 'tarball', 'zipball']
  if path_types.include?(url_components[2]) ||
     url_components[-1].end_with?('.tar.gz') ||
     url_components[-1].end_with?('.zip')
    :github_media
  else
    :github_remote
  end
end

.github_url_prefixObject



52
53
54
# File 'lib/vanagon/component/source/git.rb', line 52

def github_url_prefix
  'https://github.com/'
end

.valid_remote?(url, timeout = 0) ⇒ Boolean

Attempt to connect to whatever URL is provided and return true or false base on a number of guesses of whether it’s a valid Git repo.

Parameters:

  • url (#to_s)

    A URI::HTTPS, URI:HTTP, or String with the the URL of the remote git repository.

  • timeout (Number) (defaults to: 0)

    Time (in seconds) to wait before assuming the git command has failed. Useful in instances where a URL prompts for credentials despite not being a git remote

Returns:

  • (Boolean)

    whether #url is a valid Git repo or not



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/vanagon/component/source/git.rb', line 29

def valid_remote?(url, timeout = 0)
  # RE-15209. To relieve github rate-limiting, if the URL starts with
  # https://github.com/... just accept it rather than ping github over and over.
  return github_remote?(url) if url.to_s.start_with?(github_url_prefix)

  begin
    # [RE-13837] there's a bug in Git.ls_remote that when ssh prints something like
    #  Warning: Permanently added 'github.com,192.30.255.113' (RSA)
    # Git.ls_remote attempts to parse it as actual git output and fails
    # with: NoMethodError: undefined method `split' for nil:NilClass
    #
    # Work around it by calling 'git ls-remote' directly ourselves.
    Timeout.timeout(timeout) do
      Vanagon::Utilities.local_command("git ls-remote --heads #{url} > /dev/null 2>&1")
      $?.exitstatus.zero?
    end
  rescue RuntimeError
    # Either a Timeout::Error or some other execution exception that we'll just call
    # 'invalid'
    false
  end
end

Instance Method Details

#cleanupString

Return the correct incantation to cleanup the source directory for a given source

Returns:

  • (String)

    command to cleanup the source



125
126
127
# File 'lib/vanagon/component/source/git.rb', line 125

def cleanup
  "rm -rf #{dirname}"
end

#cloneObject

Perform a git clone of @url as a lazy-loaded accessor for @clone



149
150
151
152
153
154
155
# File 'lib/vanagon/component/source/git.rb', line 149

def clone
  if @clone_options.empty?
    @clone ||= ::Git.clone(url, dirname, path: workdir)
  else
    @clone ||= ::Git.clone(url, dirname, path: workdir, **clone_options)
  end
end

#dirnameString

The dirname to reference when building from the repo

Returns:

  • (String)

    the directory where the repo was cloned



138
139
140
# File 'lib/vanagon/component/source/git.rb', line 138

def dirname
  @dirname || File.basename(url.path, ".git")
end

#fetchObject

Fetch the source. In this case, clone the repository into the workdir and check out the ref. Also sets the version if there is a git tag as a side effect.



115
116
117
118
119
120
# File 'lib/vanagon/component/source/git.rb', line 115

def fetch
  clone!
  checkout!
  version
  update_submodules
end

#verifyObject

There is no md5 to manually verify here, so this is a noop.



130
131
132
133
# File 'lib/vanagon/component/source/git.rb', line 130

def verify
  # nothing to do here, so just tell users that and return
  VanagonLogger.info "Nothing to verify for '#{dirname}' (using Git reference '#{ref}')"
end