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.
- checksums.yaml +4 -4
- metadata +13 -337
- data/CHANGELOG.md +0 -7079
- data/LICENSE +0 -39
- data/README.md +0 -114
- data/helpers/test/run.rb +0 -18
- data/helpers/utils/git-credential-store-immutable +0 -10
- data/lib/dependabot/clients/bitbucket.rb +0 -105
- data/lib/dependabot/clients/github_with_retries.rb +0 -121
- data/lib/dependabot/clients/gitlab.rb +0 -72
- data/lib/dependabot/dependency.rb +0 -115
- data/lib/dependabot/dependency_file.rb +0 -60
- data/lib/dependabot/errors.rb +0 -179
- data/lib/dependabot/file_fetchers/README.md +0 -65
- data/lib/dependabot/file_fetchers/base.rb +0 -368
- data/lib/dependabot/file_fetchers.rb +0 -18
- data/lib/dependabot/file_parsers/README.md +0 -45
- data/lib/dependabot/file_parsers/base/dependency_set.rb +0 -77
- data/lib/dependabot/file_parsers/base.rb +0 -31
- data/lib/dependabot/file_parsers.rb +0 -18
- data/lib/dependabot/file_updaters/README.md +0 -58
- data/lib/dependabot/file_updaters/base.rb +0 -52
- data/lib/dependabot/file_updaters.rb +0 -18
- data/lib/dependabot/git_commit_checker.rb +0 -412
- data/lib/dependabot/metadata_finders/README.md +0 -53
- data/lib/dependabot/metadata_finders/base/changelog_finder.rb +0 -321
- data/lib/dependabot/metadata_finders/base/changelog_pruner.rb +0 -177
- data/lib/dependabot/metadata_finders/base/commits_finder.rb +0 -221
- data/lib/dependabot/metadata_finders/base/release_finder.rb +0 -255
- data/lib/dependabot/metadata_finders/base.rb +0 -117
- data/lib/dependabot/metadata_finders.rb +0 -18
- data/lib/dependabot/pull_request_creator/branch_namer.rb +0 -170
- data/lib/dependabot/pull_request_creator/commit_signer.rb +0 -63
- data/lib/dependabot/pull_request_creator/github.rb +0 -277
- data/lib/dependabot/pull_request_creator/gitlab.rb +0 -136
- data/lib/dependabot/pull_request_creator/labeler.rb +0 -373
- data/lib/dependabot/pull_request_creator/message_builder.rb +0 -906
- data/lib/dependabot/pull_request_creator.rb +0 -153
- data/lib/dependabot/pull_request_updater/github.rb +0 -165
- data/lib/dependabot/pull_request_updater.rb +0 -43
- data/lib/dependabot/shared_helpers.rb +0 -224
- data/lib/dependabot/source.rb +0 -120
- data/lib/dependabot/update_checkers/README.md +0 -67
- data/lib/dependabot/update_checkers/base.rb +0 -220
- data/lib/dependabot/update_checkers.rb +0 -18
- data/lib/dependabot/utils.rb +0 -33
- data/lib/dependabot/version.rb +0 -5
- data/lib/dependabot.rb +0 -4
- 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
|