Class: Dependabot::Source

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/dependabot/source.rb

Constant Summary collapse

GITHUB_SOURCE =
%r{
  (?<provider>github)
  (?:\.com)[/:]
  (?<repo>[\w.-]+/(?:[\w.-])+)
  (?:(?:/tree|/blob)/(?<branch>[^/]+)/(?<directory>.*)[\#|/])?
}x
GITHUB_ENTERPRISE_SOURCE =
%r{
  (?<protocol>(http://|https://|git://|ssh://))*
  (?<username>[^@]+@)*
  (?<host>[^/]+)
  [/:]
  (?<repo>[\w.-]+/(?:[\w.-])+)
  (?:(?:/tree|/blob)/(?<branch>[^/]+)/(?<directory>.*)[\#|/])?
}x
GITLAB_SOURCE =
%r{
  (?<provider>gitlab)
  (?:\.com)[/:]
  (?<repo>[^/]+/(?:[^/])+((?!/tree|/blob/|/-)/[^/]+)?)
  (?:(?:/tree|/blob)/(?<branch>[^/]+)/(?<directory>.*)[\#|/].*)?
}x
BITBUCKET_SOURCE =
%r{
  (?<provider>bitbucket)
  (?:\.org)[/:]
  (?<repo>[\w.-]+/(?:[\w.-])+)
  (?:(?:/src)/(?<branch>[^/]+)/(?<directory>.*)[\#|/])?
}x
AZURE_SOURCE =
%r{
  (?<provider>azure)
  (?:\.com)[/:]
  (?<repo>[\w.-]+/([\w.-]+/)?(?:_git/)(?:[\w.-])+)
}x
CODECOMMIT_SOURCE =
%r{
  (?<protocol>(http://|https://|git://|ssh://))
  git[-]
  (?<provider>codecommit)
  (?:.*)
  (?:\.com/v1/repos/)
  (?<repo>([^/]*))
  (?:/)?(?<directory>[^?]*)?
  [?]?
  (?<ref>.*)?
}x
SOURCE_REGEX =
/
  (?:#{GITHUB_SOURCE})|
  (?:#{GITLAB_SOURCE})|
  (?:#{BITBUCKET_SOURCE})|
  (?:#{AZURE_SOURCE})|
  (?:#{CODECOMMIT_SOURCE})
/x
IGNORED_PROVIDER_HOSTS =
%w(gitbox.apache.org svn.apache.org fuchsia.googlesource.com).freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(provider:, repo:, directory: nil, directories: nil, branch: nil, commit: nil, hostname: nil, api_endpoint: nil) ⇒ Source

Returns a new instance of Source.



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/dependabot/source.rb', line 169

def initialize(
  provider:,
  repo:,
  directory: nil,
  directories: nil,
  branch: nil,
  commit: nil,
  hostname: nil,
  api_endpoint: nil
)
  if (hostname.nil? ^ api_endpoint.nil?) && (provider != "codecommit")
    msg = "Both hostname and api_endpoint must be specified if either " \
          "are. Alternatively, both may be left blank to use the " \
          "provider's defaults."
    raise msg
  end

  @provider = provider
  @repo = repo
  @directory = directory
  @directories = directories
  @branch = branch
  @commit = commit
  @hostname = T.let(hostname || default_hostname(provider), String)
  @api_endpoint = T.let(api_endpoint || default_api_endpoint(provider), T.nilable(String))
end

Instance Attribute Details

#api_endpointObject

Returns the value of attribute api_endpoint.



90
91
92
# File 'lib/dependabot/source.rb', line 90

def api_endpoint
  @api_endpoint
end

#branchObject

Returns the value of attribute branch.



81
82
83
# File 'lib/dependabot/source.rb', line 81

def branch
  @branch
end

#commitObject

Returns the value of attribute commit.



84
85
86
# File 'lib/dependabot/source.rb', line 84

def commit
  @commit
end

#directoriesObject

Returns the value of attribute directories.



78
79
80
# File 'lib/dependabot/source.rb', line 78

def directories
  @directories
end

#directoryObject

Returns the value of attribute directory.



75
76
77
# File 'lib/dependabot/source.rb', line 75

def directory
  @directory
end

#hostnameObject

Returns the value of attribute hostname.



87
88
89
# File 'lib/dependabot/source.rb', line 87

def hostname
  @hostname
end

#providerObject

Returns the value of attribute provider.



69
70
71
# File 'lib/dependabot/source.rb', line 69

def provider
  @provider
end

#repoObject

Returns the value of attribute repo.



72
73
74
# File 'lib/dependabot/source.rb', line 72

def repo
  @repo
end

Class Method Details

.from_url(url_string) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/dependabot/source.rb', line 93

def self.from_url(url_string)
  return github_enterprise_from_url(url_string) unless url_string&.match?(SOURCE_REGEX)

  captures = T.must(url_string.match(SOURCE_REGEX)).named_captures

  new(
    provider: T.must(captures.fetch("provider")),
    repo: T.must(captures.fetch("repo")).delete_suffix(".git").delete_suffix("."),
    directory: captures.fetch("directory"),
    branch: captures.fetch("branch")
  )
end

.github_enterprise?(base_url) ⇒ Boolean

Returns:

  • (Boolean)


134
135
136
137
138
139
140
# File 'lib/dependabot/source.rb', line 134

def self.github_enterprise?(base_url)
  return T.must(@github_enterprise_cache[base_url]) if @github_enterprise_cache.key?(base_url)

  result = detect_github_enterprise(base_url)
  @github_enterprise_cache[base_url] = result unless result.nil?
  result || false
end

.github_enterprise_from_url(url_string) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/dependabot/source.rb', line 107

def self.github_enterprise_from_url(url_string)
  captures = url_string&.match(GITHUB_ENTERPRISE_SOURCE)&.named_captures
  return unless captures
  return if IGNORED_PROVIDER_HOSTS.include?(captures.fetch("host"))

  base_url = "https://#{captures.fetch('host')}"

  return unless github_enterprise?(base_url)

  new(
    provider: "github",
    repo: T.must(captures.fetch("repo")).delete_suffix(".git").delete_suffix("."),
    directory: captures.fetch("directory"),
    branch: captures.fetch("branch"),
    hostname: captures.fetch("host"),
    api_endpoint: File.join(base_url, "api", "v3")
  )
end

.reset_github_enterprise_cache!Object



129
130
131
# File 'lib/dependabot/source.rb', line 129

def self.reset_github_enterprise_cache!
  @github_enterprise_cache.clear
end

Instance Method Details

#organizationObject



223
224
225
226
227
228
229
230
231
# File 'lib/dependabot/source.rb', line 223

def organization
  case provider
  when "azure"
    parts = repo.split("/_git/")
    T.must(T.must(parts.first).split("/").last(2).first)
  else
    T.must(repo.split("/").first)
  end
end

#projectObject



234
235
236
237
238
239
240
241
# File 'lib/dependabot/source.rb', line 234

def project
  raise "Project is an Azure DevOps concept only" unless provider == "azure"

  parts = repo.split("/_git/")
  return T.must(T.must(parts.first).split("/").last) if parts.first&.split("/")&.count&.>=(2)

  T.must(parts.last)
end

#unscoped_repoObject



244
245
246
# File 'lib/dependabot/source.rb', line 244

def unscoped_repo
  T.must(repo.split("/").last)
end

#urlObject



197
198
199
# File 'lib/dependabot/source.rb', line 197

def url
  "https://" + hostname + "/" + repo
end

#url_with_directoryObject



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

def url_with_directory
  return url if [nil, ".", "/"].include?(directory)

  case provider
  when "github", "gitlab"
    path = Pathname.new(File.join("tree/#{branch || 'HEAD'}", directory))
                   .cleanpath.to_path
    url + "/" + path
  when "bitbucket"
    path = Pathname.new(File.join("src/#{branch || 'default'}", directory))
                   .cleanpath.to_path
    url + "/" + path
  when "azure"
    url + "?path=#{directory}"
  when "codecommit"
    raise "The codecommit provider does not utilize URLs"
  else raise "Unexpected repo provider '#{provider}'"
  end
end