dependabot-common 0.95.1 → 0.95.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/lib/dependabot.rb +4 -0
  3. data/lib/dependabot/clients/bitbucket.rb +105 -0
  4. data/lib/dependabot/clients/github_with_retries.rb +121 -0
  5. data/lib/dependabot/clients/gitlab.rb +72 -0
  6. data/lib/dependabot/dependency.rb +115 -0
  7. data/lib/dependabot/dependency_file.rb +60 -0
  8. data/lib/dependabot/errors.rb +179 -0
  9. data/lib/dependabot/file_fetchers.rb +18 -0
  10. data/lib/dependabot/file_fetchers/README.md +65 -0
  11. data/lib/dependabot/file_fetchers/base.rb +368 -0
  12. data/lib/dependabot/file_parsers.rb +18 -0
  13. data/lib/dependabot/file_parsers/README.md +45 -0
  14. data/lib/dependabot/file_parsers/base.rb +31 -0
  15. data/lib/dependabot/file_parsers/base/dependency_set.rb +77 -0
  16. data/lib/dependabot/file_updaters.rb +18 -0
  17. data/lib/dependabot/file_updaters/README.md +58 -0
  18. data/lib/dependabot/file_updaters/base.rb +52 -0
  19. data/lib/dependabot/git_commit_checker.rb +412 -0
  20. data/lib/dependabot/metadata_finders.rb +18 -0
  21. data/lib/dependabot/metadata_finders/README.md +53 -0
  22. data/lib/dependabot/metadata_finders/base.rb +117 -0
  23. data/lib/dependabot/metadata_finders/base/changelog_finder.rb +321 -0
  24. data/lib/dependabot/metadata_finders/base/changelog_pruner.rb +177 -0
  25. data/lib/dependabot/metadata_finders/base/commits_finder.rb +221 -0
  26. data/lib/dependabot/metadata_finders/base/release_finder.rb +255 -0
  27. data/lib/dependabot/pull_request_creator.rb +155 -0
  28. data/lib/dependabot/pull_request_creator/branch_namer.rb +170 -0
  29. data/lib/dependabot/pull_request_creator/commit_signer.rb +63 -0
  30. data/lib/dependabot/pull_request_creator/github.rb +277 -0
  31. data/lib/dependabot/pull_request_creator/gitlab.rb +162 -0
  32. data/lib/dependabot/pull_request_creator/labeler.rb +373 -0
  33. data/lib/dependabot/pull_request_creator/message_builder.rb +906 -0
  34. data/lib/dependabot/pull_request_updater.rb +43 -0
  35. data/lib/dependabot/pull_request_updater/github.rb +165 -0
  36. data/lib/dependabot/shared_helpers.rb +224 -0
  37. data/lib/dependabot/source.rb +120 -0
  38. data/lib/dependabot/update_checkers.rb +18 -0
  39. data/lib/dependabot/update_checkers/README.md +67 -0
  40. data/lib/dependabot/update_checkers/base.rb +220 -0
  41. data/lib/dependabot/utils.rb +33 -0
  42. data/lib/dependabot/version.rb +5 -0
  43. data/lib/rubygems_version_patch.rb +14 -0
  44. metadata +44 -2
@@ -0,0 +1,155 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dependabot/metadata_finders"
4
+
5
+ module Dependabot
6
+ class PullRequestCreator
7
+ require "dependabot/pull_request_creator/github"
8
+ require "dependabot/pull_request_creator/gitlab"
9
+ require "dependabot/pull_request_creator/message_builder"
10
+ require "dependabot/pull_request_creator/branch_namer"
11
+ require "dependabot/pull_request_creator/labeler"
12
+
13
+ class RepoNotFound < StandardError; end
14
+ class RepoArchived < StandardError; end
15
+ class NoHistoryInCommon < StandardError; end
16
+
17
+ attr_reader :source, :dependencies, :files, :base_commit,
18
+ :credentials, :pr_message_footer, :custom_labels,
19
+ :author_details, :signature_key, :vulnerabilities_fixed,
20
+ :reviewers, :assignees, :milestone, :branch_name_separator
21
+
22
+ def initialize(source:, base_commit:, dependencies:, files:, credentials:,
23
+ pr_message_footer: nil, custom_labels: nil,
24
+ author_details: nil, signature_key: nil,
25
+ reviewers: nil, assignees: nil, milestone: nil,
26
+ vulnerabilities_fixed: {}, branch_name_separator: "/",
27
+ label_language: false)
28
+ @dependencies = dependencies
29
+ @source = source
30
+ @base_commit = base_commit
31
+ @files = files
32
+ @credentials = credentials
33
+ @pr_message_footer = pr_message_footer
34
+ @author_details = author_details
35
+ @signature_key = signature_key
36
+ @custom_labels = custom_labels
37
+ @reviewers = reviewers
38
+ @assignees = assignees
39
+ @milestone = milestone
40
+ @vulnerabilities_fixed = vulnerabilities_fixed
41
+ @branch_name_separator = branch_name_separator
42
+ @label_language = label_language
43
+
44
+ check_dependencies_have_previous_version
45
+ end
46
+
47
+ def check_dependencies_have_previous_version
48
+ return if library? && dependencies.all? { |d| requirements_changed?(d) }
49
+ return if dependencies.all?(&:previous_version)
50
+
51
+ raise "Dependencies must have a previous version or changed " \
52
+ "requirement to have a pull request created for them!"
53
+ end
54
+
55
+ def create
56
+ case source.provider
57
+ when "github" then github_creator.create
58
+ when "gitlab" then gitlab_creator.create
59
+ else raise "Unsupported provider #{source.provider}"
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ def label_language?
66
+ @label_language
67
+ end
68
+
69
+ def github_creator
70
+ Github.new(
71
+ source: source,
72
+ branch_name: branch_namer.new_branch_name,
73
+ base_commit: base_commit,
74
+ credentials: credentials,
75
+ files: files,
76
+ commit_message: message_builder.commit_message,
77
+ pr_description: message_builder.pr_message,
78
+ pr_name: message_builder.pr_name,
79
+ author_details: author_details,
80
+ signature_key: signature_key,
81
+ labeler: labeler,
82
+ reviewers: reviewers,
83
+ assignees: assignees,
84
+ milestone: milestone
85
+ )
86
+ end
87
+
88
+ def gitlab_creator
89
+ Gitlab.new(
90
+ source: source,
91
+ branch_name: branch_namer.new_branch_name,
92
+ base_commit: base_commit,
93
+ credentials: credentials,
94
+ files: files,
95
+ commit_message: message_builder.commit_message,
96
+ pr_description: message_builder.pr_message,
97
+ pr_name: message_builder.pr_name,
98
+ author_details: author_details,
99
+ labeler: labeler,
100
+ approvers: reviewers,
101
+ assignee: assignees&.first,
102
+ milestone: milestone
103
+ )
104
+ end
105
+
106
+ def message_builder
107
+ @message_builder ||
108
+ MessageBuilder.new(
109
+ source: source,
110
+ dependencies: dependencies,
111
+ files: files,
112
+ credentials: credentials,
113
+ author_details: author_details,
114
+ pr_message_footer: pr_message_footer,
115
+ vulnerabilities_fixed: vulnerabilities_fixed
116
+ )
117
+ end
118
+
119
+ def branch_namer
120
+ @branch_namer ||=
121
+ BranchNamer.new(
122
+ dependencies: dependencies,
123
+ files: files,
124
+ target_branch: source.branch,
125
+ separator: branch_name_separator
126
+ )
127
+ end
128
+
129
+ def labeler
130
+ @labeler ||=
131
+ Labeler.new(
132
+ source: source,
133
+ custom_labels: custom_labels,
134
+ credentials: credentials,
135
+ includes_security_fixes: includes_security_fixes?,
136
+ dependencies: dependencies,
137
+ label_language: label_language?
138
+ )
139
+ end
140
+
141
+ def library?
142
+ return true if files.any? { |file| file.name.end_with?(".gemspec") }
143
+
144
+ dependencies.none?(&:appears_in_lockfile?)
145
+ end
146
+
147
+ def includes_security_fixes?
148
+ vulnerabilities_fixed.values.flatten.any?
149
+ end
150
+
151
+ def requirements_changed?(dependency)
152
+ (dependency.requirements - dependency.previous_requirements).any?
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,170 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dependabot/metadata_finders"
4
+ require "dependabot/pull_request_creator"
5
+
6
+ module Dependabot
7
+ class PullRequestCreator
8
+ class BranchNamer
9
+ attr_reader :dependencies, :files, :target_branch, :separator
10
+
11
+ def initialize(dependencies:, files:, target_branch:, separator: "/")
12
+ @dependencies = dependencies
13
+ @files = files
14
+ @target_branch = target_branch
15
+ @separator = separator
16
+ end
17
+
18
+ # rubocop:disable Metrics/AbcSize
19
+ # rubocop:disable Metrics/PerceivedComplexity
20
+ # rubocop:disable Metrics/CyclomaticComplexity
21
+ def new_branch_name
22
+ @name ||=
23
+ if dependencies.count > 1 && updating_a_property?
24
+ property_name
25
+ elsif dependencies.count > 1 && updating_a_dependency_set?
26
+ dependency_set.fetch(:group)
27
+ elsif dependencies.count > 1
28
+ dependencies.map(&:name).join("-and-").tr(":", "-")
29
+ elsif library? && ref_changed?(dependencies.first)
30
+ dep = dependencies.first
31
+ "#{dep.name.tr(':', '-')}-#{new_ref(dep)}"
32
+ elsif library?
33
+ dep = dependencies.first
34
+ "#{dep.name.tr(':', '-')}-#{sanitized_requirement(dep)}"
35
+ else
36
+ dep = dependencies.first
37
+ "#{dep.name.tr(':', '-')}-#{new_version(dep)}"
38
+ end
39
+
40
+ branch_name = File.join(prefixes, @name).gsub(%r{/\.}, "/dot-")
41
+
42
+ # Some users need branch names without slashes
43
+ branch_name.gsub("/", separator)
44
+ end
45
+ # rubocop:enable Metrics/AbcSize
46
+ # rubocop:enable Metrics/PerceivedComplexity
47
+ # rubocop:enable Metrics/CyclomaticComplexity
48
+
49
+ private
50
+
51
+ def prefixes
52
+ [
53
+ "dependabot",
54
+ package_manager,
55
+ files.first.directory.tr(" ", "-"),
56
+ target_branch
57
+ ].compact
58
+ end
59
+
60
+ def package_manager
61
+ dependencies.first.package_manager
62
+ end
63
+
64
+ def updating_a_property?
65
+ dependencies.first.
66
+ requirements.
67
+ any? { |r| r.dig(:metadata, :property_name) }
68
+ end
69
+
70
+ def updating_a_dependency_set?
71
+ dependencies.first.
72
+ requirements.
73
+ any? { |r| r.dig(:metadata, :dependency_set) }
74
+ end
75
+
76
+ def property_name
77
+ @property_name ||= dependencies.first.requirements.
78
+ find { |r| r.dig(:metadata, :property_name) }&.
79
+ dig(:metadata, :property_name)
80
+
81
+ raise "No property name!" unless @property_name
82
+
83
+ @property_name
84
+ end
85
+
86
+ def dependency_set
87
+ @dependency_set ||= dependencies.first.requirements.
88
+ find { |r| r.dig(:metadata, :dependency_set) }&.
89
+ dig(:metadata, :dependency_set)
90
+
91
+ raise "No dependency set!" unless @dependency_set
92
+
93
+ @dependency_set
94
+ end
95
+
96
+ def sanitized_requirement(dependency)
97
+ new_library_requirement(dependency).
98
+ delete(" ").
99
+ gsub("!=", "neq-").
100
+ gsub(">=", "gte-").
101
+ gsub("<=", "lte-").
102
+ gsub("~>", "tw-").
103
+ gsub("^", "tw-").
104
+ gsub("||", "or-").
105
+ gsub("~", "approx-").
106
+ gsub("~=", "tw-").
107
+ gsub(/==*/, "eq-").
108
+ gsub(">", "gt-").
109
+ gsub("<", "lt-").
110
+ gsub("*", "star").
111
+ gsub(",", "-and-")
112
+ end
113
+
114
+ def new_version(dependency)
115
+ if dependency.version.match?(/^[0-9a-f]{40}$/)
116
+ return new_ref(dependency) if ref_changed?(dependency)
117
+
118
+ dependency.version[0..6]
119
+ elsif dependency.version == dependency.previous_version &&
120
+ package_manager == "docker"
121
+ dependency.requirements.
122
+ map { |r| r.dig(:source, "digest") || r.dig(:source, :digest) }.
123
+ compact.first.split(":").last[0..6]
124
+ else
125
+ dependency.version
126
+ end
127
+ end
128
+
129
+ def previous_ref(dependency)
130
+ dependency.previous_requirements.map do |r|
131
+ r.dig(:source, "ref") || r.dig(:source, :ref)
132
+ end.compact.first
133
+ end
134
+
135
+ def new_ref(dependency)
136
+ dependency.requirements.map do |r|
137
+ r.dig(:source, "ref") || r.dig(:source, :ref)
138
+ end.compact.first
139
+ end
140
+
141
+ def ref_changed?(dependency)
142
+ previous_ref(dependency) && new_ref(dependency) &&
143
+ previous_ref(dependency) != new_ref(dependency)
144
+ end
145
+
146
+ def new_library_requirement(dependency)
147
+ updated_reqs =
148
+ dependency.requirements - dependency.previous_requirements
149
+
150
+ gemspec =
151
+ updated_reqs.find { |r| r[:file].match?(%r{^[^/]*\.gemspec$}) }
152
+ return gemspec[:requirement] if gemspec
153
+
154
+ updated_reqs.first[:requirement]
155
+ end
156
+
157
+ def library?
158
+ if files.map(&:name).any? { |name| name.end_with?(".gemspec") }
159
+ return true
160
+ end
161
+
162
+ dependencies.none?(&:appears_in_lockfile?)
163
+ end
164
+
165
+ def requirements_changed?(dependency)
166
+ (dependency.requirements - dependency.previous_requirements).any?
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "time"
4
+ require "gpgme"
5
+ require "tmpdir"
6
+ require "dependabot/pull_request_creator"
7
+
8
+ module Dependabot
9
+ class PullRequestCreator
10
+ class CommitSigner
11
+ attr_reader :author_details, :commit_message, :tree_sha, :parent_sha,
12
+ :signature_key
13
+
14
+ def initialize(author_details:, commit_message:, tree_sha:, parent_sha:,
15
+ signature_key:)
16
+ @author_details = author_details
17
+ @commit_message = commit_message
18
+ @tree_sha = tree_sha
19
+ @parent_sha = parent_sha
20
+ @signature_key = signature_key
21
+ end
22
+
23
+ def signature
24
+ email = author_details[:email]
25
+
26
+ dir = Dir.mktmpdir
27
+
28
+ GPGME::Engine.home_dir = dir
29
+ GPGME::Key.import(signature_key)
30
+
31
+ crypto = GPGME::Crypto.new(armor: true)
32
+ opts = { mode: GPGME::SIG_MODE_DETACH, signer: email }
33
+ crypto.sign(commit_object, opts).to_s
34
+ rescue Errno::ENOTEMPTY
35
+ FileUtils.remove_entry(dir, true)
36
+ # This appears to be a Ruby bug which occurs very rarely
37
+ raise if @retrying
38
+
39
+ @retrying = true
40
+ retry
41
+ ensure
42
+ FileUtils.remove_entry(dir, true)
43
+ end
44
+
45
+ private
46
+
47
+ def commit_object
48
+ time_str = Time.parse(author_details[:date]).strftime("%s %z")
49
+ name = author_details[:name]
50
+ email = author_details[:email]
51
+
52
+ [
53
+ "tree #{tree_sha}",
54
+ "parent #{parent_sha}",
55
+ "author #{name} <#{email}> #{time_str}",
56
+ "committer #{name} <#{email}> #{time_str}",
57
+ "",
58
+ commit_message
59
+ ].join("\n")
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,277 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "octokit"
4
+ require "securerandom"
5
+ require "dependabot/clients/github_with_retries"
6
+ require "dependabot/pull_request_creator"
7
+ require "dependabot/pull_request_creator/commit_signer"
8
+
9
+ module Dependabot
10
+ class PullRequestCreator
11
+ class Github
12
+ attr_reader :source, :branch_name, :base_commit, :credentials,
13
+ :files, :pr_description, :pr_name, :commit_message,
14
+ :author_details, :signature_key,
15
+ :labeler, :reviewers, :assignees, :milestone
16
+
17
+ def initialize(source:, branch_name:, base_commit:, credentials:,
18
+ files:, commit_message:, pr_description:, pr_name:,
19
+ author_details:, signature_key:,
20
+ labeler:, reviewers:, assignees:, milestone:)
21
+ @source = source
22
+ @branch_name = branch_name
23
+ @base_commit = base_commit
24
+ @credentials = credentials
25
+ @files = files
26
+ @commit_message = commit_message
27
+ @pr_description = pr_description
28
+ @pr_name = pr_name
29
+ @author_details = author_details
30
+ @signature_key = signature_key
31
+ @labeler = labeler
32
+ @reviewers = reviewers
33
+ @assignees = assignees
34
+ @milestone = milestone
35
+ end
36
+
37
+ def create
38
+ return if branch_exists? && pull_request_exists?
39
+
40
+ commit = create_commit
41
+ branch = create_or_update_branch(commit)
42
+ return unless branch
43
+
44
+ pull_request = create_pull_request
45
+ return unless pull_request
46
+
47
+ annotate_pull_request(pull_request)
48
+
49
+ pull_request
50
+ rescue Octokit::Error => error
51
+ handle_error(error)
52
+ end
53
+
54
+ private
55
+
56
+ def github_client_for_source
57
+ @github_client_for_source ||=
58
+ Dependabot::Clients::GithubWithRetries.for_source(
59
+ source: source,
60
+ credentials: credentials
61
+ )
62
+ end
63
+
64
+ def branch_exists?
65
+ @branch_ref ||=
66
+ github_client_for_source.ref(source.repo, "heads/#{branch_name}")
67
+ if @branch_ref.is_a?(Array)
68
+ @branch_ref.any? { |r| r.ref == "refs/heads/#{branch_name}" }
69
+ else
70
+ @branch_ref.ref == "refs/heads/#{branch_name}"
71
+ end
72
+ rescue Octokit::NotFound
73
+ false
74
+ end
75
+
76
+ def pull_request_exists?
77
+ github_client_for_source.pull_requests(
78
+ source.repo,
79
+ head: "#{source.repo.split('/').first}:#{branch_name}",
80
+ state: "all"
81
+ ).any?
82
+ rescue Octokit::InternalServerError
83
+ # A GitHub bug sometimes means adding `state: all` causes problems.
84
+ # In that case, fall back to making two separate requests.
85
+ open_prs = github_client_for_source.pull_requests(
86
+ source.repo,
87
+ head: "#{source.repo.split('/').first}:#{branch_name}",
88
+ state: "open"
89
+ )
90
+
91
+ closed_prs = github_client_for_source.pull_requests(
92
+ source.repo,
93
+ head: "#{source.repo.split('/').first}:#{branch_name}",
94
+ state: "closed"
95
+ )
96
+
97
+ [*open_prs, *closed_prs].any?
98
+ end
99
+
100
+ def repo_exists?
101
+ github_client_for_source.repo(source.repo)
102
+ true
103
+ rescue Octokit::NotFound
104
+ false
105
+ end
106
+
107
+ def create_commit
108
+ tree = create_tree
109
+
110
+ options = author_details&.any? ? { author: author_details } : {}
111
+
112
+ if options[:author]&.any? && signature_key
113
+ options[:author][:date] = Time.now.utc.iso8601
114
+ options[:signature] = commit_signature(tree, options[:author])
115
+ end
116
+
117
+ github_client_for_source.create_commit(
118
+ source.repo,
119
+ commit_message,
120
+ tree.sha,
121
+ base_commit,
122
+ options
123
+ )
124
+ end
125
+
126
+ def create_tree
127
+ file_trees = files.map do |file|
128
+ if file.type == "submodule"
129
+ {
130
+ path: file.path.sub(%r{^/}, ""),
131
+ mode: "160000",
132
+ type: "commit",
133
+ sha: file.content
134
+ }
135
+ else
136
+ {
137
+ path: file.path.sub(%r{^/}, ""),
138
+ mode: "100644",
139
+ type: "blob",
140
+ content: file.content
141
+ }
142
+ end
143
+ end
144
+
145
+ github_client_for_source.create_tree(
146
+ source.repo,
147
+ file_trees,
148
+ base_tree: base_commit
149
+ )
150
+ end
151
+
152
+ def create_or_update_branch(commit)
153
+ branch_exists? ? update_branch(commit) : create_branch(commit)
154
+ rescue Octokit::UnprocessableEntity
155
+ # A race condition may cause GitHub to fail here, in which case we retry
156
+ retry_count ||= 0
157
+ retry_count += 1
158
+ retry unless retry_count >= 2
159
+ end
160
+
161
+ def create_branch(commit)
162
+ github_client_for_source.create_ref(
163
+ source.repo,
164
+ "heads/#{branch_name}",
165
+ commit.sha
166
+ )
167
+ rescue Octokit::UnprocessableEntity => error
168
+ # Return quietly in the case of a race
169
+ return nil if error.message.match?(/Reference already exists/i)
170
+ raise if @retrying_branch_creation
171
+
172
+ @retrying_branch_creation = true
173
+
174
+ # Branch creation will fail if a branch called `dependabot` already
175
+ # exists, since git won't be able to create a folder with the same name
176
+ @branch_name = SecureRandom.hex[0..3] + @branch_name
177
+ retry
178
+ end
179
+
180
+ def update_branch(commit)
181
+ github_client_for_source.update_ref(
182
+ source.repo,
183
+ "heads/#{branch_name}",
184
+ commit.sha,
185
+ true
186
+ )
187
+ end
188
+
189
+ def annotate_pull_request(pull_request)
190
+ labeler.label_pull_request(pull_request.number)
191
+ add_reviewers_to_pull_request(pull_request) if reviewers&.any?
192
+ add_assignees_to_pull_request(pull_request) if assignees&.any?
193
+ add_milestone_to_pull_request(pull_request) if milestone
194
+ end
195
+
196
+ def add_reviewers_to_pull_request(pull_request)
197
+ reviewers_hash =
198
+ Hash[reviewers.keys.map { |k| [k.to_sym, reviewers[k]] }]
199
+
200
+ github_client_for_source.request_pull_request_review(
201
+ source.repo,
202
+ pull_request.number,
203
+ reviewers: reviewers_hash[:reviewers] || [],
204
+ team_reviewers: reviewers_hash[:team_reviewers] || []
205
+ )
206
+ rescue Octokit::UnprocessableEntity => error
207
+ return if error.message.include?("not a collaborator")
208
+ return if error.message.include?("Could not resolve to a node")
209
+
210
+ raise
211
+ end
212
+
213
+ def add_assignees_to_pull_request(pull_request)
214
+ github_client_for_source.add_assignees(
215
+ source.repo,
216
+ pull_request.number,
217
+ assignees
218
+ )
219
+ end
220
+
221
+ def add_milestone_to_pull_request(pull_request)
222
+ github_client_for_source.update_issue(
223
+ source.repo,
224
+ pull_request.number,
225
+ milestone: milestone
226
+ )
227
+ end
228
+
229
+ def create_pull_request
230
+ github_client_for_source.create_pull_request(
231
+ source.repo,
232
+ source.branch || default_branch,
233
+ branch_name,
234
+ pr_name,
235
+ pr_description
236
+ )
237
+ rescue Octokit::UnprocessableEntity => error
238
+ # Ignore races that we lose
239
+ raise unless error.message.include?("pull request already exists")
240
+ end
241
+
242
+ def default_branch
243
+ @default_branch ||=
244
+ github_client_for_source.repository(source.repo).default_branch
245
+ end
246
+
247
+ def commit_signature(tree, author_details_with_date)
248
+ CommitSigner.new(
249
+ author_details: author_details_with_date,
250
+ commit_message: commit_message,
251
+ tree_sha: tree.sha,
252
+ parent_sha: base_commit,
253
+ signature_key: signature_key
254
+ ).signature
255
+ end
256
+
257
+ def handle_error(error)
258
+ case error
259
+ when Octokit::Forbidden
260
+ raise error unless error.message.include?("Repository was archived")
261
+
262
+ raise RepoArchived, error.message
263
+ when Octokit::NotFound
264
+ raise error if repo_exists?
265
+
266
+ raise RepoNotFound, error.message
267
+ when Octokit::UnprocessableEntity
268
+ raise error unless error.message.include?("no history in common")
269
+
270
+ raise NoHistoryInCommon, error.message
271
+ else
272
+ raise error
273
+ end
274
+ end
275
+ end
276
+ end
277
+ end