Class: Dependabot::FileFetchers::Base

Inherits:
Object
  • Object
show all
Extended by:
T::Helpers, T::Sig
Defined in:
lib/dependabot/file_fetchers/base.rb

Direct Known Subclasses

Config::FileFetcher

Constant Summary collapse

CLIENT_NOT_FOUND_ERRORS =
T.let(
  [
    Octokit::NotFound,
    Gitlab::Error::NotFound,
    Dependabot::Clients::Azure::NotFound,
    Dependabot::Clients::Bitbucket::NotFound,
    Dependabot::Clients::CodeCommit::NotFound
  ].freeze,
  T::Array[T.class_of(StandardError)]
)
GIT_SUBMODULE_INACCESSIBLE_ERROR =
/^fatal: unable to access '(?<url>.*)': The requested URL returned error: (?<code>\d+)$/
GIT_SUBMODULE_CLONE_ERROR =
/^fatal: clone of '(?<url>.*)' into submodule path '.*' failed$/
GIT_SUBMODULE_ERROR_REGEX =
/(#{GIT_SUBMODULE_INACCESSIBLE_ERROR})|(#{GIT_SUBMODULE_CLONE_ERROR})/
GIT_RETRYABLE_ERRORS =
T.let(
  [
    /remote error: Internal Server Error/,
    /fatal: Couldn\'t find remote ref/,
    %r{git fetch_pack: expected ACK/NAK, got},
    /protocol error: bad pack header/,
    /The remote end hung up unexpectedly/,
    /TLS packet with unexpected length was received/,
    /RPC failed; result=\d+, HTTP code = \d+/,
    /Connection timed out/,
    /Connection reset by peer/,
    /Unable to look up/,
    /Couldn\'t resolve host/,
    /The requested URL returned error: (429|5\d{2})/
  ].freeze,
  T::Array[Regexp]
)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source:, credentials:, repo_contents_path: nil, options: {}, update_config: nil) ⇒ Base

Returns a new instance of Base.



108
109
110
111
112
113
114
115
116
117
118
# File 'lib/dependabot/file_fetchers/base.rb', line 108

def initialize(source:, credentials:, repo_contents_path: nil, options: {}, update_config: nil)
  @source = source
  @credentials = credentials
  @repo_contents_path = repo_contents_path
  @exclude_paths = T.let(update_config&.exclude_paths || [], T::Array[String])
  @linked_paths = T.let({}, T::Hash[T.untyped, T.untyped])
  @submodules = T.let([], T::Array[T.untyped])
  @options = options

  @files = T.let([], T::Array[DependencyFile])
end

Instance Attribute Details

#credentialsObject (readonly)

Returns the value of attribute credentials.



33
34
35
# File 'lib/dependabot/file_fetchers/base.rb', line 33

def credentials
  @credentials
end

#optionsObject (readonly)

Returns the value of attribute options.



39
40
41
# File 'lib/dependabot/file_fetchers/base.rb', line 39

def options
  @options
end

#repo_contents_pathObject (readonly)

Returns the value of attribute repo_contents_path.



36
37
38
# File 'lib/dependabot/file_fetchers/base.rb', line 36

def repo_contents_path
  @repo_contents_path
end

#sourceObject (readonly)

Returns the value of attribute source.



30
31
32
# File 'lib/dependabot/file_fetchers/base.rb', line 30

def source
  @source
end

Class Method Details

.required_files_in?(filenames) ⇒ Boolean

Returns:

  • (Boolean)


77
78
79
# File 'lib/dependabot/file_fetchers/base.rb', line 77

def self.required_files_in?(filenames)
  filenames.any?
end

.required_files_messageObject



82
83
84
# File 'lib/dependabot/file_fetchers/base.rb', line 82

def self.required_files_message
  "Required files are missing from configured directory"
end

Instance Method Details

#allow_beta_ecosystems?Boolean

Returns:

  • (Boolean)


143
144
145
# File 'lib/dependabot/file_fetchers/base.rb', line 143

def allow_beta_ecosystems?
  Experiments.enabled?(:enable_beta_ecosystems)
end

#clone_repo_contentsObject



177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/dependabot/file_fetchers/base.rb', line 177

def clone_repo_contents
  @clone_repo_contents ||= T.let(
    _clone_repo_contents(target_directory: repo_contents_path),
    T.nilable(String)
  )
rescue Dependabot::SharedHelpers::HelperSubprocessFailed => e
  if e.message.include?("fatal: Remote branch #{target_branch} not found in upstream origin")
    raise Dependabot::BranchNotFound, target_branch
  elsif e.message.include?("No space left on device")
    raise Dependabot::OutOfDisk
  end

  raise Dependabot::RepoNotFound.new(source, e.message)
end

#commitObject



162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/dependabot/file_fetchers/base.rb', line 162

def commit
  return T.must(cloned_commit) if cloned_commit
  return T.must(source.commit) if source.commit

  branch = target_branch || default_branch_for_repo

  @commit ||= T.let(T.unsafe(client_for_provider).fetch_commit(repo, branch), T.nilable(String))
rescue *CLIENT_NOT_FOUND_ERRORS
  raise Dependabot::BranchNotFound, branch
rescue Octokit::Conflict => e
  raise unless e.message.include?("Repository is empty")
end

#directoryObject



133
134
135
# File 'lib/dependabot/file_fetchers/base.rb', line 133

def directory
  Pathname.new(source.directory || "/").cleanpath.to_path
end

#ecosystem_versionsObject



193
# File 'lib/dependabot/file_fetchers/base.rb', line 193

def ecosystem_versions; end

#exclude_paths=(excludes) ⇒ Object



122
123
124
# File 'lib/dependabot/file_fetchers/base.rb', line 122

def exclude_paths=(excludes)
  @exclude_paths = excludes
end

#fetch_filesObject



196
# File 'lib/dependabot/file_fetchers/base.rb', line 196

def fetch_files; end

#filesObject



148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/dependabot/file_fetchers/base.rb', line 148

def files
  return @files if @files.any?

  files = fetch_files.compact
  raise Dependabot::DependencyFileNotFound.new(nil, "No files found in #{directory}") unless files.any?

  unless self.class.required_files_in?(files.map(&:name))
    raise DependencyFileNotFound.new(nil, self.class.required_files_message)
  end

  @files = files
end

#repoObject



128
129
130
# File 'lib/dependabot/file_fetchers/base.rb', line 128

def repo
  source.repo
end

#target_branchObject



138
139
140
# File 'lib/dependabot/file_fetchers/base.rb', line 138

def target_branch
  source.branch
end