dependabot-core 0.94.13 → 0.95.0

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 (49) hide show
  1. checksums.yaml +4 -4
  2. metadata +13 -337
  3. data/CHANGELOG.md +0 -7079
  4. data/LICENSE +0 -39
  5. data/README.md +0 -114
  6. data/helpers/test/run.rb +0 -18
  7. data/helpers/utils/git-credential-store-immutable +0 -10
  8. data/lib/dependabot/clients/bitbucket.rb +0 -105
  9. data/lib/dependabot/clients/github_with_retries.rb +0 -121
  10. data/lib/dependabot/clients/gitlab.rb +0 -72
  11. data/lib/dependabot/dependency.rb +0 -115
  12. data/lib/dependabot/dependency_file.rb +0 -60
  13. data/lib/dependabot/errors.rb +0 -179
  14. data/lib/dependabot/file_fetchers/README.md +0 -65
  15. data/lib/dependabot/file_fetchers/base.rb +0 -368
  16. data/lib/dependabot/file_fetchers.rb +0 -18
  17. data/lib/dependabot/file_parsers/README.md +0 -45
  18. data/lib/dependabot/file_parsers/base/dependency_set.rb +0 -77
  19. data/lib/dependabot/file_parsers/base.rb +0 -31
  20. data/lib/dependabot/file_parsers.rb +0 -18
  21. data/lib/dependabot/file_updaters/README.md +0 -58
  22. data/lib/dependabot/file_updaters/base.rb +0 -52
  23. data/lib/dependabot/file_updaters.rb +0 -18
  24. data/lib/dependabot/git_commit_checker.rb +0 -412
  25. data/lib/dependabot/metadata_finders/README.md +0 -53
  26. data/lib/dependabot/metadata_finders/base/changelog_finder.rb +0 -321
  27. data/lib/dependabot/metadata_finders/base/changelog_pruner.rb +0 -177
  28. data/lib/dependabot/metadata_finders/base/commits_finder.rb +0 -221
  29. data/lib/dependabot/metadata_finders/base/release_finder.rb +0 -255
  30. data/lib/dependabot/metadata_finders/base.rb +0 -117
  31. data/lib/dependabot/metadata_finders.rb +0 -18
  32. data/lib/dependabot/pull_request_creator/branch_namer.rb +0 -170
  33. data/lib/dependabot/pull_request_creator/commit_signer.rb +0 -63
  34. data/lib/dependabot/pull_request_creator/github.rb +0 -277
  35. data/lib/dependabot/pull_request_creator/gitlab.rb +0 -136
  36. data/lib/dependabot/pull_request_creator/labeler.rb +0 -373
  37. data/lib/dependabot/pull_request_creator/message_builder.rb +0 -906
  38. data/lib/dependabot/pull_request_creator.rb +0 -153
  39. data/lib/dependabot/pull_request_updater/github.rb +0 -165
  40. data/lib/dependabot/pull_request_updater.rb +0 -43
  41. data/lib/dependabot/shared_helpers.rb +0 -224
  42. data/lib/dependabot/source.rb +0 -120
  43. data/lib/dependabot/update_checkers/README.md +0 -67
  44. data/lib/dependabot/update_checkers/base.rb +0 -220
  45. data/lib/dependabot/update_checkers.rb +0 -18
  46. data/lib/dependabot/utils.rb +0 -33
  47. data/lib/dependabot/version.rb +0 -5
  48. data/lib/dependabot.rb +0 -4
  49. data/lib/rubygems_version_patch.rb +0 -14
@@ -1,53 +0,0 @@
1
- # Metadata finders
2
-
3
- Metadata finders look up metadata about a dependency, such as its GitHub URL.
4
-
5
- There is a `Dependabot::MetadataFinders` class for each language Dependabot
6
- supports.
7
-
8
- ## Public API
9
-
10
- Each `Dependabot::MetadataFinders` class exposes the following methods:
11
-
12
- | Method | Description |
13
- |-----------------------|---------------------------------------------------------------------------------------------|
14
- | `#source_url` | A link to the source data for the dependency. |
15
- | `#homepage_url` | A link to the homepage for the dependency. |
16
- | `#commits_url` | A link to a commit diff between the previous version of the dependency and the new version. |
17
- | `#commits` | A list of commits between the previous version of the dependency and the new version. |
18
- | `#changelog_url` | A link to the changelog for the dependency. |
19
- | `#changelog_text` | The relevant text from the changelog. |
20
- | `#release_url` | A link to the release notes for this version of the dependency. |
21
- | `#release_text` | The relevant text from the release notes |
22
- | `#upgrade_guide_url` | A link to the upgrade guide for this upgrade (if it exists). |
23
- | `#upgrade_guide_text` | The text of the upgrade guide for this upgrade (if it exists). |
24
-
25
- An integration might look as follows:
26
-
27
- ```ruby
28
- require 'dependabot/metadata_finders'
29
-
30
- dependency = update_checker.updated_dependency
31
-
32
- metadata_finder_class = Dependabot::MetadataFinders::Ruby::Bundler
33
- metadata_finder = metadata_finder_class.new(
34
- dependency: dependency,
35
- credentials: credentials
36
- )
37
-
38
- puts "Changelog for #{dependency.name} is at #{metadata_finder.changelog_url}"
39
- ```
40
-
41
- ## Writing a metadata finder for a new language
42
-
43
- All new metadata finders should inherit from `Dependabot::MetadataFinders::Base`
44
- and implement the following methods:
45
-
46
- | Method | Description |
47
- |------------------------|-------------------------|
48
- | `#look_up_source` | Private method that returns a `Dependabot::Source` object. Generally the source details are extracted from a source code URL provided by the language's dependency registry, but sometimes it's already know from parsing the dependency file. |
49
-
50
- To ensure the above are implemented, you should include
51
- `it_behaves_like "a dependency metadata finder"` in your specs for the new
52
- metadata finder.
53
-
@@ -1,321 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "excon"
4
-
5
- require "dependabot/clients/github_with_retries"
6
- require "dependabot/clients/gitlab"
7
- require "dependabot/clients/bitbucket"
8
- require "dependabot/shared_helpers"
9
- require "dependabot/metadata_finders/base"
10
-
11
- module Dependabot
12
- module MetadataFinders
13
- class Base
14
- class ChangelogFinder
15
- require_relative "changelog_pruner"
16
- require_relative "commits_finder"
17
-
18
- # Earlier entries are preferred
19
- CHANGELOG_NAMES = %w(changelog history news changes release).freeze
20
-
21
- attr_reader :source, :dependency, :credentials
22
-
23
- def initialize(source:, dependency:, credentials:)
24
- @source = source
25
- @dependency = dependency
26
- @credentials = credentials
27
- end
28
-
29
- def changelog_url
30
- changelog&.html_url
31
- end
32
-
33
- def changelog_text
34
- return unless full_changelog_text
35
-
36
- ChangelogPruner.new(
37
- dependency: dependency,
38
- changelog_text: full_changelog_text
39
- ).pruned_text
40
- end
41
-
42
- def upgrade_guide_url
43
- upgrade_guide&.html_url
44
- end
45
-
46
- def upgrade_guide_text
47
- return unless upgrade_guide
48
-
49
- @upgrade_guide_text ||= fetch_file_text(upgrade_guide)
50
- end
51
-
52
- private
53
-
54
- # rubocop:disable Metrics/CyclomaticComplexity
55
- # rubocop:disable Metrics/PerceivedComplexity
56
- def changelog
57
- return unless source
58
-
59
- # Changelog won't be relevant for a git commit bump
60
- return if git_source? && !ref_changed?
61
-
62
- # If there is a changelog, and it includes the new version, return it
63
- if new_version && default_branch_changelog &&
64
- fetch_file_text(default_branch_changelog)&.include?(new_version)
65
- return default_branch_changelog
66
- end
67
-
68
- # Otherwise, look for a changelog at the tag for this version
69
- if new_version && relevant_tag_changelog &&
70
- fetch_file_text(relevant_tag_changelog)&.include?(new_version)
71
- return relevant_tag_changelog
72
- end
73
-
74
- # Fall back to the changelog (or nil) from the default branch
75
- default_branch_changelog
76
- end
77
- # rubocop:enable Metrics/CyclomaticComplexity
78
- # rubocop:enable Metrics/PerceivedComplexity
79
-
80
- def default_branch_changelog
81
- return unless source
82
-
83
- @default_branch_changelog ||= changelog_from_ref(nil)
84
- end
85
-
86
- def relevant_tag_changelog
87
- return unless source
88
- return unless tag_for_new_version
89
-
90
- @relevant_tag_changelog ||= changelog_from_ref(tag_for_new_version)
91
- end
92
-
93
- def changelog_from_ref(ref)
94
- files =
95
- dependency_file_list(ref).
96
- select { |f| f.type == "file" }.
97
- reject { |f| f.name.end_with?(".sh") }.
98
- reject { |f| f.size > 1_000_000 }
99
-
100
- CHANGELOG_NAMES.each do |name|
101
- candidates = files.select { |f| f.name =~ /#{name}/i }
102
- file = candidates.first if candidates.one?
103
- file ||=
104
- candidates.find do |f|
105
- candidates -= [f] && next if fetch_file_text(f).nil?
106
- ChangelogPruner.new(
107
- dependency: dependency,
108
- changelog_text: fetch_file_text(f)
109
- ).includes_new_version?
110
- end
111
- file ||= candidates.max_by(&:size)
112
- return file if file
113
- end
114
-
115
- nil
116
- end
117
-
118
- def tag_for_new_version
119
- @tag_for_new_version ||=
120
- CommitsFinder.new(
121
- dependency: dependency,
122
- source: source,
123
- credentials: credentials
124
- ).new_tag
125
- end
126
-
127
- def full_changelog_text
128
- return unless changelog
129
-
130
- fetch_file_text(changelog)
131
- end
132
-
133
- def fetch_file_text(file)
134
- @file_text ||= {}
135
-
136
- unless @file_text.key?(file.download_url)
137
- @file_text[file.download_url] =
138
- case source.provider
139
- when "github" then fetch_github_file(file)
140
- when "gitlab" then fetch_gitlab_file(file)
141
- when "bitbucket" then fetch_bitbucket_file(file)
142
- else raise "Unsupported provider '#{source.provider}"
143
- end
144
- end
145
-
146
- return unless @file_text[file.download_url].valid_encoding?
147
-
148
- @file_text[file.download_url].
149
- force_encoding("UTF-8").
150
- encode.sub(/\n*\z/, "")
151
- end
152
-
153
- def fetch_github_file(file)
154
- # Hitting the download URL directly causes encoding problems
155
- raw_content = github_client.get(file.url).content
156
- Base64.decode64(raw_content).force_encoding("UTF-8").encode
157
- end
158
-
159
- def fetch_gitlab_file(file)
160
- Excon.get(
161
- file.download_url,
162
- idempotent: true,
163
- **SharedHelpers.excon_defaults
164
- ).body
165
- end
166
-
167
- def fetch_bitbucket_file(file)
168
- bitbucket_client.get(file.download_url).body
169
- end
170
-
171
- def upgrade_guide
172
- return unless source
173
-
174
- # Upgrade guide usually won't be relevant for bumping anything other
175
- # than the major version
176
- return unless major_version_upgrade?
177
-
178
- dependency_file_list.
179
- select { |f| f.type == "file" }.
180
- select { |f| f.name.casecmp("upgrade.md").zero? }.
181
- reject { |f| f.size > 1_000_000 }.
182
- max_by(&:size)
183
- end
184
-
185
- def dependency_file_list(ref = nil)
186
- @dependency_file_list ||= {}
187
- @dependency_file_list[ref] ||= fetch_dependency_file_list(ref)
188
- end
189
-
190
- def fetch_dependency_file_list(ref)
191
- case source.provider
192
- when "github" then fetch_github_file_list(ref)
193
- when "bitbucket" then fetch_bitbucket_file_list
194
- when "gitlab" then fetch_gitlab_file_list
195
- when "azure" then [] # TODO: Fetch files from Azure
196
- else raise "Unexpected repo provider '#{source.provider}'"
197
- end
198
- end
199
-
200
- def fetch_github_file_list(ref)
201
- files = []
202
-
203
- if source.directory
204
- opts = { path: source.directory, ref: ref }.compact
205
- tmp_files = github_client.contents(source.repo, opts)
206
- files += tmp_files if tmp_files.is_a?(Array)
207
- end
208
-
209
- opts = { ref: ref }.compact
210
- files += github_client.contents(source.repo, opts)
211
-
212
- files.uniq.each do |f|
213
- next unless %w(doc docs).include?(f.name) && f.type == "dir"
214
-
215
- opts = { path: f.path, ref: ref }.compact
216
- files += github_client.contents(source.repo, opts)
217
- end
218
-
219
- files
220
- rescue Octokit::NotFound
221
- []
222
- end
223
-
224
- def fetch_bitbucket_file_list
225
- branch = default_bitbucket_branch
226
- bitbucket_client.fetch_repo_contents(source.repo).map do |file|
227
- OpenStruct.new(
228
- name: file.fetch("path").split("/").last,
229
- type: file.fetch("type") == "commit_file" ? "file" : file["type"],
230
- size: file.fetch("size", 0),
231
- html_url: "#{source.url}/src/#{branch}/#{file['path']}",
232
- download_url: "#{source.url}/raw/#{branch}/#{file['path']}"
233
- )
234
- end
235
- rescue Dependabot::Clients::Bitbucket::NotFound,
236
- Dependabot::Clients::Bitbucket::Unauthorized,
237
- Dependabot::Clients::Bitbucket::Forbidden
238
- []
239
- end
240
-
241
- def fetch_gitlab_file_list
242
- gitlab_client.repo_tree(source.repo).map do |file|
243
- OpenStruct.new(
244
- name: file.name,
245
- type: file.type == "blob" ? "file" : file.type,
246
- size: 0, # GitLab doesn't return file size
247
- html_url: "#{source.url}/blob/master/#{file.path}",
248
- download_url: "#{source.url}/raw/master/#{file.path}"
249
- )
250
- end
251
- rescue Gitlab::Error::NotFound
252
- []
253
- end
254
-
255
- def new_version
256
- @new_version ||= git_source? ? new_ref : dependency.version
257
- @new_version&.gsub(/^v/, "")
258
- end
259
-
260
- def previous_ref
261
- dependency.previous_requirements.map do |r|
262
- r.dig(:source, "ref") || r.dig(:source, :ref)
263
- end.compact.first
264
- end
265
-
266
- def new_ref
267
- dependency.requirements.map do |r|
268
- r.dig(:source, "ref") || r.dig(:source, :ref)
269
- end.compact.first
270
- end
271
-
272
- def ref_changed?
273
- previous_ref && new_ref && previous_ref != new_ref
274
- end
275
-
276
- # TODO: Refactor me so that Composer doesn't need to be special cased
277
- def git_source?
278
- # Special case Composer, which uses git as a source but handles tags
279
- # internally
280
- return false if dependency.package_manager == "composer"
281
-
282
- requirements = dependency.requirements
283
- sources = requirements.map { |r| r.fetch(:source) }.uniq.compact
284
- return false if sources.empty?
285
- raise "Multiple sources! #{sources.join(', ')}" if sources.count > 1
286
-
287
- source_type = sources.first[:type] || sources.first.fetch("type")
288
- source_type == "git"
289
- end
290
-
291
- def major_version_upgrade?
292
- return false unless dependency.version&.match?(/^\d/)
293
- return false unless dependency.previous_version&.match?(/^\d/)
294
-
295
- dependency.version.split(".").first.to_i -
296
- dependency.previous_version.split(".").first.to_i >= 1
297
- end
298
-
299
- def gitlab_client
300
- @gitlab_client ||= Dependabot::Clients::Gitlab.
301
- for_gitlab_dot_com(credentials: credentials)
302
- end
303
-
304
- def github_client
305
- @github_client ||= Dependabot::Clients::GithubWithRetries.
306
- for_github_dot_com(credentials: credentials)
307
- end
308
-
309
- def bitbucket_client
310
- @bitbucket_client ||= Dependabot::Clients::Bitbucket.
311
- for_bitbucket_dot_org(credentials: credentials)
312
- end
313
-
314
- def default_bitbucket_branch
315
- @default_bitbucket_branch ||=
316
- bitbucket_client.fetch_default_branch(source.repo)
317
- end
318
- end
319
- end
320
- end
321
- end
@@ -1,177 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "dependabot/metadata_finders/base"
4
-
5
- module Dependabot
6
- module MetadataFinders
7
- class Base
8
- class ChangelogPruner
9
- attr_reader :dependency, :changelog_text
10
-
11
- def initialize(dependency:, changelog_text:)
12
- @dependency = dependency
13
- @changelog_text = changelog_text
14
- end
15
-
16
- def includes_new_version?
17
- !new_version_changelog_line.nil?
18
- end
19
-
20
- # rubocop:disable Metrics/PerceivedComplexity
21
- # rubocop:disable Metrics/CyclomaticComplexity
22
- def pruned_text
23
- changelog_lines = changelog_text.split("\n")
24
-
25
- slice_range =
26
- if old_version_changelog_line && new_version_changelog_line
27
- if old_version_changelog_line < new_version_changelog_line
28
- Range.new(old_version_changelog_line, -1)
29
- else
30
- Range.new(new_version_changelog_line,
31
- old_version_changelog_line - 1)
32
- end
33
- elsif old_version_changelog_line
34
- return if old_version_changelog_line.zero?
35
-
36
- # Assumes changelog is in descending order
37
- Range.new(0, old_version_changelog_line - 1)
38
- elsif new_version_changelog_line
39
- # Assumes changelog is in descending order
40
- Range.new(new_version_changelog_line, -1)
41
- else
42
- return unless changelog_contains_relevant_versions?
43
-
44
- # If the changelog contains any relevant versions, return it in
45
- # full. We could do better here by fully parsing the changelog
46
- Range.new(0, -1)
47
- end
48
-
49
- changelog_lines.slice(slice_range).join("\n").sub(/\n*\z/, "")
50
- end
51
- # rubocop:enable Metrics/PerceivedComplexity
52
- # rubocop:enable Metrics/CyclomaticComplexity
53
-
54
- private
55
-
56
- def old_version_changelog_line
57
- old_version = git_source? ? previous_ref : dependency.previous_version
58
- return nil unless old_version
59
-
60
- changelog_line_for_version(old_version)
61
- end
62
-
63
- def new_version_changelog_line
64
- return nil unless new_version
65
-
66
- changelog_line_for_version(new_version)
67
- end
68
-
69
- # rubocop:disable Metrics/CyclomaticComplexity
70
- # rubocop:disable Metrics/PerceivedComplexity
71
- def changelog_line_for_version(version)
72
- raise "No changelog text" unless changelog_text
73
- return nil unless version
74
-
75
- version = version.gsub(/^v/, "")
76
- escaped_version = Regexp.escape(version)
77
-
78
- changelog_lines = changelog_text.split("\n")
79
-
80
- changelog_lines.find_index.with_index do |line, index|
81
- next false unless line.match?(/(?<!\.)#{escaped_version}(?![.\-])/)
82
- next false if line.match?(/#{escaped_version}\.\./)
83
- next true if line.start_with?("#", "!", "==")
84
- next true if line.match?(/^v?#{escaped_version}:?/)
85
- next true if line.match?(/^[\+\*\-] (version )?#{escaped_version}/i)
86
- next true if line.match?(/^\d{4}-\d{2}-\d{2}/)
87
- next true if changelog_lines[index + 1]&.match?(/^[=\-\+]{3,}\s*$/)
88
-
89
- false
90
- end
91
- end
92
- # rubocop:enable Metrics/CyclomaticComplexity
93
- # rubocop:enable Metrics/PerceivedComplexity
94
-
95
- def changelog_contains_relevant_versions?
96
- # Assume the changelog is relevant if we can't parse the new version
97
- return true unless version_class.correct?(dependency.version)
98
-
99
- # Assume the changelog is relevant if it mentions the new version
100
- # anywhere
101
- return true if changelog_text.include?(dependency.version)
102
-
103
- # Otherwise check if any intermediate versions are included in headers
104
- versions_in_changelog_headers.any? do |version|
105
- next false unless version <= version_class.new(dependency.version)
106
- next true unless dependency.previous_version
107
- next true unless version_class.correct?(dependency.previous_version)
108
-
109
- version > version_class.new(dependency.previous_version)
110
- end
111
- end
112
-
113
- def versions_in_changelog_headers
114
- changelog_lines = changelog_text.split("\n")
115
- header_lines =
116
- changelog_lines.select.with_index do |line, index|
117
- next true if line.start_with?("#", "!")
118
- next true if line.match?(/^v?\d\.\d/)
119
- next true if changelog_lines[index + 1]&.match?(/^[=-]+\s*$/)
120
-
121
- false
122
- end
123
-
124
- versions = []
125
- header_lines.each do |line|
126
- cleaned_line = line.gsub(/^[^0-9]*/, "").gsub(/[\s,:].*/, "")
127
- next if cleaned_line.empty? || !version_class.correct?(cleaned_line)
128
-
129
- versions << version_class.new(cleaned_line)
130
- end
131
-
132
- versions
133
- end
134
-
135
- def new_version
136
- @new_version ||= git_source? ? new_ref : dependency.version
137
- @new_version&.gsub(/^v/, "")
138
- end
139
-
140
- def previous_ref
141
- dependency.previous_requirements.map do |r|
142
- r.dig(:source, "ref") || r.dig(:source, :ref)
143
- end.compact.first
144
- end
145
-
146
- def new_ref
147
- dependency.requirements.map do |r|
148
- r.dig(:source, "ref") || r.dig(:source, :ref)
149
- end.compact.first
150
- end
151
-
152
- def ref_changed?
153
- previous_ref && new_ref && previous_ref != new_ref
154
- end
155
-
156
- # TODO: Refactor me so that Composer doesn't need to be special cased
157
- def git_source?
158
- # Special case Composer, which uses git as a source but handles tags
159
- # internally
160
- return false if dependency.package_manager == "composer"
161
-
162
- requirements = dependency.requirements
163
- sources = requirements.map { |r| r.fetch(:source) }.uniq.compact
164
- return false if sources.empty?
165
- raise "Multiple sources! #{sources.join(', ')}" if sources.count > 1
166
-
167
- source_type = sources.first[:type] || sources.first.fetch("type")
168
- source_type == "git"
169
- end
170
-
171
- def version_class
172
- Utils.version_class_for_package_manager(dependency.package_manager)
173
- end
174
- end
175
- end
176
- end
177
- end