dependabot-core 0.94.12 → 0.95.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. metadata +13 -337
  3. data/CHANGELOG.md +0 -7075
  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 -117
  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