dependabot-core 0.94.13 → 0.95.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,77 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "dependabot/dependency"
|
4
|
-
require "dependabot/file_parsers/base"
|
5
|
-
require "dependabot/utils"
|
6
|
-
|
7
|
-
module Dependabot
|
8
|
-
module FileParsers
|
9
|
-
class Base
|
10
|
-
class DependencySet
|
11
|
-
def initialize(dependencies = [])
|
12
|
-
unless dependencies.is_a?(Array) &&
|
13
|
-
dependencies.all? { |dep| dep.is_a?(Dependency) }
|
14
|
-
raise ArgumentError, "must be an array of Dependency objects"
|
15
|
-
end
|
16
|
-
|
17
|
-
@dependencies = dependencies
|
18
|
-
end
|
19
|
-
|
20
|
-
attr_reader :dependencies
|
21
|
-
|
22
|
-
def <<(dep)
|
23
|
-
unless dep.is_a?(Dependency)
|
24
|
-
raise ArgumentError, "must be a Dependency object"
|
25
|
-
end
|
26
|
-
|
27
|
-
existing_dependency = dependencies.find { |d| d.name == dep.name }
|
28
|
-
|
29
|
-
return self if existing_dependency&.to_h == dep.to_h
|
30
|
-
|
31
|
-
if existing_dependency
|
32
|
-
dependencies[dependencies.index(existing_dependency)] =
|
33
|
-
combined_dependency(existing_dependency, dep)
|
34
|
-
else
|
35
|
-
dependencies << dep
|
36
|
-
end
|
37
|
-
|
38
|
-
self
|
39
|
-
end
|
40
|
-
|
41
|
-
def +(other)
|
42
|
-
unless other.is_a?(DependencySet)
|
43
|
-
raise ArgumentError, "must be a DependencySet"
|
44
|
-
end
|
45
|
-
|
46
|
-
other.dependencies.each { |dep| self << dep }
|
47
|
-
self
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
def combined_dependency(old_dep, new_dep)
|
53
|
-
package_manager = old_dep.package_manager
|
54
|
-
v_cls = Utils.version_class_for_package_manager(package_manager)
|
55
|
-
|
56
|
-
# If we already have a requirement use the existing version
|
57
|
-
# (if present). Otherwise, use whatever the lowest version is
|
58
|
-
new_version =
|
59
|
-
if old_dep.requirements.any? then old_dep.version || new_dep.version
|
60
|
-
elsif !v_cls.correct?(new_dep.version) then old_dep.version
|
61
|
-
elsif !v_cls.correct?(old_dep.version) then new_dep.version
|
62
|
-
elsif v_cls.new(new_dep.version) > v_cls.new(old_dep.version)
|
63
|
-
old_dep.version
|
64
|
-
else new_dep.version
|
65
|
-
end
|
66
|
-
|
67
|
-
Dependency.new(
|
68
|
-
name: old_dep.name,
|
69
|
-
version: new_version,
|
70
|
-
requirements: (old_dep.requirements + new_dep.requirements).uniq,
|
71
|
-
package_manager: package_manager
|
72
|
-
)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Dependabot
|
4
|
-
module FileParsers
|
5
|
-
class Base
|
6
|
-
attr_reader :dependency_files, :credentials, :source
|
7
|
-
|
8
|
-
def initialize(dependency_files:, source:, credentials: [])
|
9
|
-
@dependency_files = dependency_files
|
10
|
-
@credentials = credentials
|
11
|
-
@source = source
|
12
|
-
|
13
|
-
check_required_files
|
14
|
-
end
|
15
|
-
|
16
|
-
def parse
|
17
|
-
raise NotImplementedError
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
def check_required_files
|
23
|
-
raise NotImplementedError
|
24
|
-
end
|
25
|
-
|
26
|
-
def get_original_file(filename)
|
27
|
-
dependency_files.find { |f| f.name == filename }
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Dependabot
|
4
|
-
module FileParsers
|
5
|
-
@file_parsers = {}
|
6
|
-
|
7
|
-
def self.for_package_manager(package_manager)
|
8
|
-
file_parser = @file_parsers[package_manager]
|
9
|
-
return file_parser if file_parser
|
10
|
-
|
11
|
-
raise "Unsupported package_manager #{package_manager}"
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.register(package_manager, file_parser)
|
15
|
-
@file_parsers[package_manager] = file_parser
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,58 +0,0 @@
|
|
1
|
-
# File updaters
|
2
|
-
|
3
|
-
File updaters update a dependency file to use the latest version of a given
|
4
|
-
dependency. They rely on information provided to them by update checkers.
|
5
|
-
|
6
|
-
There is a `Dependabot::FileUpdaters` class for each language Dependabot
|
7
|
-
supports.
|
8
|
-
|
9
|
-
## Public API
|
10
|
-
|
11
|
-
Each `Dependabot::FileUpdaters` class implements the following methods:
|
12
|
-
|
13
|
-
| Method | Description |
|
14
|
-
|------------------------------|-----------------------------------------------------------------------------------------------|
|
15
|
-
| `.updated_files_regex` | An array of regular expressions matching the names of the files this class updates. Intended to be used by integrators when checking whether a commit may cause merge-conflicts with a dependency update pull request. |
|
16
|
-
| `#updated_dependency_files` | Returns an array of updated `Dependabot::DependencyFile` instances, with their content updated to include the updated dependency. |
|
17
|
-
|
18
|
-
An integration might look as follows:
|
19
|
-
|
20
|
-
```ruby
|
21
|
-
require 'dependabot/file_updaters'
|
22
|
-
|
23
|
-
unless update_checker.can_update?(requirements_to_update: :own)
|
24
|
-
raise "Dependency doesn't need update!"
|
25
|
-
end
|
26
|
-
dependencies = update_checker.updated_dependencies(requirements_to_update: :own)
|
27
|
-
|
28
|
-
file_updater_class = Dependabot::FileUpdaters::Ruby::Bundler
|
29
|
-
file_updater = file_updater_class.new(
|
30
|
-
dependencies: dependencies,
|
31
|
-
dependency_files: files,
|
32
|
-
credentials: [{
|
33
|
-
"type" => "git_source",
|
34
|
-
"host" => "github.com",
|
35
|
-
"username" => "x-access-token",
|
36
|
-
"password" => "token"
|
37
|
-
}]
|
38
|
-
)
|
39
|
-
|
40
|
-
file_updater.updated_dependency_files.each do |file|
|
41
|
-
puts "Updated #{file.name} with new content:\n\n#{file.content}"
|
42
|
-
end
|
43
|
-
```
|
44
|
-
|
45
|
-
## Writing a file updater for a new language
|
46
|
-
|
47
|
-
All new file updaters should inherit from `Dependabot::FileUpdaters::Base` and
|
48
|
-
implement the following methods:
|
49
|
-
|
50
|
-
| Method | Description |
|
51
|
-
|-----------------------------|-------------------------|
|
52
|
-
| `.updated_files_regex` | See Public API section. |
|
53
|
-
| `#updated_dependency_files` | See Public API section. |
|
54
|
-
|
55
|
-
To ensure the above are implemented, you should include
|
56
|
-
`it_behaves_like "a dependency file updater"` in your specs for the new file
|
57
|
-
updater.
|
58
|
-
|
@@ -1,52 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Dependabot
|
4
|
-
module FileUpdaters
|
5
|
-
class Base
|
6
|
-
attr_reader :dependencies, :dependency_files, :credentials
|
7
|
-
|
8
|
-
def self.updated_files_regex
|
9
|
-
raise NotImplementedError
|
10
|
-
end
|
11
|
-
|
12
|
-
def initialize(dependencies:, dependency_files:, credentials:)
|
13
|
-
@dependencies = dependencies
|
14
|
-
@dependency_files = dependency_files
|
15
|
-
@credentials = credentials
|
16
|
-
|
17
|
-
check_required_files
|
18
|
-
end
|
19
|
-
|
20
|
-
def updated_dependency_files
|
21
|
-
raise NotImplementedError
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def check_required_files
|
27
|
-
raise NotImplementedError
|
28
|
-
end
|
29
|
-
|
30
|
-
def get_original_file(filename)
|
31
|
-
dependency_files.find { |f| f.name == filename }
|
32
|
-
end
|
33
|
-
|
34
|
-
def file_changed?(file)
|
35
|
-
dependencies.any? { |dep| requirement_changed?(file, dep) }
|
36
|
-
end
|
37
|
-
|
38
|
-
def requirement_changed?(file, dependency)
|
39
|
-
changed_requirements =
|
40
|
-
dependency.requirements - dependency.previous_requirements
|
41
|
-
|
42
|
-
changed_requirements.any? { |f| f[:file] == file.name }
|
43
|
-
end
|
44
|
-
|
45
|
-
def updated_file(file:, content:)
|
46
|
-
updated_file = file.dup
|
47
|
-
updated_file.content = content
|
48
|
-
updated_file
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Dependabot
|
4
|
-
module FileUpdaters
|
5
|
-
@file_updaters = {}
|
6
|
-
|
7
|
-
def self.for_package_manager(package_manager)
|
8
|
-
file_updater = @file_updaters[package_manager]
|
9
|
-
return file_updater if file_updater
|
10
|
-
|
11
|
-
raise "Unsupported package_manager #{package_manager}"
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.register(package_manager, file_updater)
|
15
|
-
@file_updaters[package_manager] = file_updater
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,412 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "excon"
|
4
|
-
require "gitlab"
|
5
|
-
require "dependabot/clients/github_with_retries"
|
6
|
-
require "dependabot/metadata_finders"
|
7
|
-
require "dependabot/errors"
|
8
|
-
require "dependabot/utils"
|
9
|
-
require "dependabot/source"
|
10
|
-
|
11
|
-
# rubocop:disable Metrics/ClassLength
|
12
|
-
module Dependabot
|
13
|
-
class GitCommitChecker
|
14
|
-
VERSION_REGEX = /(?<version>[0-9]+\.[0-9]+(?:\.[a-zA-Z0-9\-]+)*)$/.freeze
|
15
|
-
KNOWN_HOSTS = /github\.com|bitbucket\.org|gitlab.com/.freeze
|
16
|
-
|
17
|
-
def initialize(dependency:, credentials:, ignored_versions: [],
|
18
|
-
requirement_class: nil, version_class: nil)
|
19
|
-
@dependency = dependency
|
20
|
-
@credentials = credentials
|
21
|
-
@ignored_versions = ignored_versions
|
22
|
-
@requirement_class = requirement_class
|
23
|
-
@version_class = version_class
|
24
|
-
end
|
25
|
-
|
26
|
-
def git_dependency?
|
27
|
-
return false if dependency_source_details.nil?
|
28
|
-
|
29
|
-
dependency_source_details.fetch(:type) == "git"
|
30
|
-
end
|
31
|
-
|
32
|
-
def pinned?
|
33
|
-
raise "Not a git dependency!" unless git_dependency?
|
34
|
-
|
35
|
-
ref = dependency_source_details.fetch(:ref)
|
36
|
-
branch = dependency_source_details.fetch(:branch)
|
37
|
-
|
38
|
-
return false if ref.nil?
|
39
|
-
return false if branch == ref
|
40
|
-
return true if branch
|
41
|
-
return true if dependency.version&.start_with?(ref)
|
42
|
-
|
43
|
-
# Check the specified `ref` isn't actually a branch
|
44
|
-
!local_upload_pack.match?("refs/heads/#{ref}")
|
45
|
-
end
|
46
|
-
|
47
|
-
def pinned_ref_looks_like_version?
|
48
|
-
return false unless pinned?
|
49
|
-
|
50
|
-
dependency_source_details.fetch(:ref).match?(VERSION_REGEX)
|
51
|
-
end
|
52
|
-
|
53
|
-
def branch_or_ref_in_release?(version)
|
54
|
-
pinned_ref_in_release?(version) || branch_behind_release?(version)
|
55
|
-
end
|
56
|
-
|
57
|
-
def head_commit_for_current_branch
|
58
|
-
return dependency.version if pinned?
|
59
|
-
|
60
|
-
branch_ref = ref_or_branch ? "refs/heads/#{ref_or_branch}" : "HEAD"
|
61
|
-
|
62
|
-
# Remove the opening clause of the upload pack as this isn't always
|
63
|
-
# followed by a line break. When it isn't (e.g., with Bitbucket) it causes
|
64
|
-
# problems for our `sha_for_update_pack_line` logic
|
65
|
-
line = local_upload_pack.
|
66
|
-
gsub(/.*git-upload-pack/, "").
|
67
|
-
lines.find { |l| l.include?(" #{branch_ref}") }
|
68
|
-
|
69
|
-
return sha_for_update_pack_line(line) if line
|
70
|
-
|
71
|
-
raise Dependabot::GitDependencyReferenceNotFound, dependency.name
|
72
|
-
end
|
73
|
-
|
74
|
-
def local_tag_for_latest_version
|
75
|
-
tag =
|
76
|
-
local_tags.
|
77
|
-
select { |t| t.name.match?(VERSION_REGEX) }.
|
78
|
-
reject { |t| tag_included_in_ignore_reqs?(t) }.
|
79
|
-
reject { |t| tag_is_prerelease?(t) && !wants_prerelease? }.
|
80
|
-
max_by do |t|
|
81
|
-
version = t.name.match(VERSION_REGEX).named_captures.fetch("version")
|
82
|
-
version_class.new(version)
|
83
|
-
end
|
84
|
-
|
85
|
-
return unless tag
|
86
|
-
|
87
|
-
{
|
88
|
-
tag: tag.name,
|
89
|
-
commit_sha: tag.commit_sha,
|
90
|
-
tag_sha: tag.tag_sha
|
91
|
-
}
|
92
|
-
end
|
93
|
-
|
94
|
-
private
|
95
|
-
|
96
|
-
attr_reader :dependency, :credentials, :ignored_versions
|
97
|
-
|
98
|
-
def pinned_ref_in_release?(version)
|
99
|
-
raise "Not a git dependency!" unless git_dependency?
|
100
|
-
|
101
|
-
return false unless pinned?
|
102
|
-
return false if listing_source_url.nil?
|
103
|
-
|
104
|
-
tag = listing_tag_for_version(version.to_s)
|
105
|
-
return false unless tag
|
106
|
-
|
107
|
-
commit_included_in_tag?(
|
108
|
-
commit: dependency_source_details.fetch(:ref),
|
109
|
-
tag: tag,
|
110
|
-
allow_identical: true
|
111
|
-
)
|
112
|
-
end
|
113
|
-
|
114
|
-
def branch_behind_release?(version)
|
115
|
-
raise "Not a git dependency!" unless git_dependency?
|
116
|
-
|
117
|
-
return false if ref_or_branch.nil?
|
118
|
-
return false if listing_source_url.nil?
|
119
|
-
|
120
|
-
tag = listing_tag_for_version(version.to_s)
|
121
|
-
return false unless tag
|
122
|
-
|
123
|
-
# Check if behind, excluding the case where it's identical, because
|
124
|
-
# we normally wouldn't switch you from tracking master to a release.
|
125
|
-
commit_included_in_tag?(
|
126
|
-
commit: ref_or_branch,
|
127
|
-
tag: tag,
|
128
|
-
allow_identical: false
|
129
|
-
)
|
130
|
-
end
|
131
|
-
|
132
|
-
def local_upload_pack
|
133
|
-
@local_upload_pack ||=
|
134
|
-
fetch_upload_pack_for(dependency_source_details.fetch(:url))
|
135
|
-
end
|
136
|
-
|
137
|
-
def local_tags
|
138
|
-
return [] unless local_upload_pack
|
139
|
-
|
140
|
-
tags_for_upload_pack(local_upload_pack)
|
141
|
-
end
|
142
|
-
|
143
|
-
def tags_for_upload_pack(upload_pack)
|
144
|
-
peeled_lines = []
|
145
|
-
unpeeled_lines = []
|
146
|
-
|
147
|
-
upload_pack.lines.each do |line|
|
148
|
-
next unless line.split(" ").last.start_with?("refs/tags")
|
149
|
-
|
150
|
-
if line.strip.end_with?("^{}") then peeled_lines << line
|
151
|
-
else unpeeled_lines << line
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
unpeeled_lines.map do |line|
|
156
|
-
tag_name = line.split(" refs/tags/").last.strip
|
157
|
-
tag_sha = sha_for_update_pack_line(line)
|
158
|
-
peeled_line = peeled_lines.find do |pl|
|
159
|
-
pl.split(" refs/tags/").last.strip == "#{tag_name}^{}"
|
160
|
-
end
|
161
|
-
|
162
|
-
commit_sha =
|
163
|
-
peeled_line ? sha_for_update_pack_line(peeled_line) : tag_sha
|
164
|
-
|
165
|
-
if dependency_source_details&.fetch(:ref, nil)&.start_with?("tags/")
|
166
|
-
tag_name = "tags/#{tag_name}"
|
167
|
-
end
|
168
|
-
|
169
|
-
OpenStruct.new(name: tag_name, tag_sha: tag_sha, commit_sha: commit_sha)
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
174
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
175
|
-
def fetch_upload_pack_for(uri)
|
176
|
-
response = Excon.get(
|
177
|
-
service_pack_uri(uri),
|
178
|
-
idempotent: true,
|
179
|
-
**SharedHelpers.excon_defaults
|
180
|
-
)
|
181
|
-
|
182
|
-
return response.body if response.status == 200
|
183
|
-
if response.status >= 500 && uri.match?(KNOWN_HOSTS)
|
184
|
-
raise "Server error at #{uri}: #{response.body}"
|
185
|
-
end
|
186
|
-
|
187
|
-
raise Dependabot::GitDependenciesNotReachable, [uri]
|
188
|
-
rescue Excon::Error::Socket, Excon::Error::Timeout
|
189
|
-
retry_count ||= 0
|
190
|
-
retry_count += 1
|
191
|
-
|
192
|
-
sleep(rand(0.9)) && retry if retry_count < 2 && uri.match?(KNOWN_HOSTS)
|
193
|
-
raise if uri.match?(KNOWN_HOSTS)
|
194
|
-
|
195
|
-
raise Dependabot::GitDependenciesNotReachable, [uri]
|
196
|
-
end
|
197
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
198
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
199
|
-
|
200
|
-
def service_pack_uri(uri)
|
201
|
-
service_pack_uri = uri_with_auth(uri)
|
202
|
-
service_pack_uri = service_pack_uri.gsub(%r{/$}, "")
|
203
|
-
service_pack_uri += ".git" unless service_pack_uri.end_with?(".git")
|
204
|
-
service_pack_uri + "/info/refs?service=git-upload-pack"
|
205
|
-
end
|
206
|
-
|
207
|
-
def uri_with_auth(uri)
|
208
|
-
bare_uri =
|
209
|
-
if uri.include?("git@") then uri.split("git@").last.sub(":", "/")
|
210
|
-
else uri.sub(%r{.*?://}, "")
|
211
|
-
end
|
212
|
-
cred = credentials.select { |c| c["type"] == "git_source" }.
|
213
|
-
find { |c| bare_uri.start_with?(c["host"]) }
|
214
|
-
|
215
|
-
if bare_uri.match?(%r{[^/]+:[^/]+@})
|
216
|
-
# URI already has authentication details
|
217
|
-
"https://#{bare_uri}"
|
218
|
-
elsif cred
|
219
|
-
# URI doesn't have authentication details, but we have credentials
|
220
|
-
auth_string = "#{cred.fetch('username')}:#{cred.fetch('password')}"
|
221
|
-
"https://#{auth_string}@#{bare_uri}"
|
222
|
-
else
|
223
|
-
# No credentials, so just return the https URI
|
224
|
-
"https://#{bare_uri}"
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
def commit_included_in_tag?(tag:, commit:, allow_identical: false)
|
229
|
-
status =
|
230
|
-
case Source.from_url(listing_source_url)&.provider
|
231
|
-
when "github" then github_commit_comparison_status(tag, commit)
|
232
|
-
when "gitlab" then gitlab_commit_comparison_status(tag, commit)
|
233
|
-
when "bitbucket" then bitbucket_commit_comparison_status(tag, commit)
|
234
|
-
else raise "Unknown source"
|
235
|
-
end
|
236
|
-
|
237
|
-
return true if status == "behind"
|
238
|
-
|
239
|
-
allow_identical && status == "identical"
|
240
|
-
rescue Octokit::NotFound, Gitlab::Error::NotFound,
|
241
|
-
Octokit::InternalServerError
|
242
|
-
false
|
243
|
-
end
|
244
|
-
|
245
|
-
def github_commit_comparison_status(ref1, ref2)
|
246
|
-
client = Clients::GithubWithRetries.
|
247
|
-
for_github_dot_com(credentials: credentials)
|
248
|
-
|
249
|
-
client.compare(listing_source_repo, ref1, ref2).status
|
250
|
-
end
|
251
|
-
|
252
|
-
def gitlab_commit_comparison_status(ref1, ref2)
|
253
|
-
access_token = credentials.
|
254
|
-
select { |cred| cred["type"] == "git_source" }.
|
255
|
-
find { |cred| cred["host"] == "gitlab.com" }&.
|
256
|
-
fetch("token")
|
257
|
-
|
258
|
-
client = Gitlab.client(endpoint: "https://gitlab.com/api/v4",
|
259
|
-
private_token: access_token.to_s)
|
260
|
-
|
261
|
-
comparison = client.compare(listing_source_repo, ref1, ref2)
|
262
|
-
|
263
|
-
if comparison.commits.none? then "behind"
|
264
|
-
elsif comparison.compare_same_ref then "identical"
|
265
|
-
else "ahead"
|
266
|
-
end
|
267
|
-
end
|
268
|
-
|
269
|
-
def bitbucket_commit_comparison_status(ref1, ref2)
|
270
|
-
url = "https://api.bitbucket.org/2.0/repositories/"\
|
271
|
-
"#{listing_source_repo}/commits/?"\
|
272
|
-
"include=#{ref2}&exclude=#{ref1}"
|
273
|
-
|
274
|
-
response = Excon.get(url,
|
275
|
-
headers: bitbucket_auth_header,
|
276
|
-
idempotent: true,
|
277
|
-
**SharedHelpers.excon_defaults)
|
278
|
-
|
279
|
-
# Conservatively assume that ref2 is ahead in the equality case, of
|
280
|
-
# if we get an unexpected format (e.g., due to a 404)
|
281
|
-
if JSON.parse(response.body).fetch("values", ["x"]).none? then "behind"
|
282
|
-
else "ahead"
|
283
|
-
end
|
284
|
-
end
|
285
|
-
|
286
|
-
def bitbucket_auth_header
|
287
|
-
token = credentials.
|
288
|
-
select { |cred| cred["type"] == "git_source" }.
|
289
|
-
find { |cred| cred["host"] == "bitbucket.org" }&.
|
290
|
-
fetch("token")
|
291
|
-
|
292
|
-
if token.nil? then {}
|
293
|
-
elsif token.include?(":")
|
294
|
-
encoded_token = Base64.encode64(token).delete("\n")
|
295
|
-
{ "Authorization" => "Basic #{encoded_token}" }
|
296
|
-
elsif Base64.decode64(token).ascii_only? &&
|
297
|
-
Base64.decode64(token).include?(":")
|
298
|
-
{ "Authorization" => "Basic #{token.delete("\n")}" }
|
299
|
-
else
|
300
|
-
{ "Authorization" => "Bearer #{token}" }
|
301
|
-
end
|
302
|
-
end
|
303
|
-
|
304
|
-
def dependency_source_details
|
305
|
-
sources =
|
306
|
-
dependency.requirements.map { |r| r.fetch(:source) }.uniq.compact
|
307
|
-
|
308
|
-
return sources.first if sources.count <= 1
|
309
|
-
|
310
|
-
# If there are multiple source types, or multiple source URLs, then it's
|
311
|
-
# unclear how we should proceed
|
312
|
-
if sources.map { |s| [s.fetch(:type), s.fetch(:url, nil)] }.uniq.count > 1
|
313
|
-
raise "Multiple sources! #{sources.join(', ')}"
|
314
|
-
end
|
315
|
-
|
316
|
-
# Otherwise it's reasonable to take the first source and use that. This
|
317
|
-
# will happen if we have multiple git sources with difference references
|
318
|
-
# specified. In that case it's fine to update them all.
|
319
|
-
sources.first
|
320
|
-
end
|
321
|
-
|
322
|
-
def ref_or_branch
|
323
|
-
dependency_source_details.fetch(:ref) ||
|
324
|
-
dependency_source_details.fetch(:branch)
|
325
|
-
end
|
326
|
-
|
327
|
-
def listing_source_url
|
328
|
-
@listing_source_url ||=
|
329
|
-
begin
|
330
|
-
# Remove the git source, so the metadata finder looks on the
|
331
|
-
# registry
|
332
|
-
candidate_dep = Dependency.new(
|
333
|
-
name: dependency.name,
|
334
|
-
version: dependency.version,
|
335
|
-
requirements: [],
|
336
|
-
package_manager: dependency.package_manager
|
337
|
-
)
|
338
|
-
|
339
|
-
MetadataFinders.
|
340
|
-
for_package_manager(dependency.package_manager).
|
341
|
-
new(dependency: candidate_dep, credentials: credentials).
|
342
|
-
source_url
|
343
|
-
end
|
344
|
-
end
|
345
|
-
|
346
|
-
def listing_source_repo
|
347
|
-
return unless listing_source_url
|
348
|
-
|
349
|
-
Source.from_url(listing_source_url)&.repo
|
350
|
-
end
|
351
|
-
|
352
|
-
def listing_tag_for_version(version)
|
353
|
-
listing_tags.
|
354
|
-
find { |t| t.name =~ /(?:[^0-9\.]|\A)#{Regexp.escape(version)}\z/ }&.
|
355
|
-
name
|
356
|
-
end
|
357
|
-
|
358
|
-
def listing_tags
|
359
|
-
return [] unless listing_upload_pack
|
360
|
-
|
361
|
-
tags_for_upload_pack(listing_upload_pack)
|
362
|
-
rescue GitDependenciesNotReachable
|
363
|
-
[]
|
364
|
-
end
|
365
|
-
|
366
|
-
def listing_upload_pack
|
367
|
-
return unless listing_source_url
|
368
|
-
|
369
|
-
@listing_upload_pack ||= fetch_upload_pack_for(listing_source_url)
|
370
|
-
end
|
371
|
-
|
372
|
-
def ignore_reqs
|
373
|
-
ignored_versions.map { |req| requirement_class.new(req.split(",")) }
|
374
|
-
end
|
375
|
-
|
376
|
-
def wants_prerelease?
|
377
|
-
return false unless dependency_source_details&.fetch(:ref, nil)
|
378
|
-
return false unless pinned_ref_looks_like_version?
|
379
|
-
|
380
|
-
version = dependency_source_details.fetch(:ref).match(VERSION_REGEX).
|
381
|
-
named_captures.fetch("version")
|
382
|
-
version_class.new(version).prerelease?
|
383
|
-
end
|
384
|
-
|
385
|
-
def tag_included_in_ignore_reqs?(tag)
|
386
|
-
version = tag.name.match(VERSION_REGEX).named_captures.fetch("version")
|
387
|
-
ignore_reqs.any? { |r| r.satisfied_by?(version_class.new(version)) }
|
388
|
-
end
|
389
|
-
|
390
|
-
def tag_is_prerelease?(tag)
|
391
|
-
version = tag.name.match(VERSION_REGEX).named_captures.fetch("version")
|
392
|
-
version_class.new(version).prerelease?
|
393
|
-
end
|
394
|
-
|
395
|
-
def version_class
|
396
|
-
return @version_class if @version_class
|
397
|
-
|
398
|
-
Utils.version_class_for_package_manager(dependency.package_manager)
|
399
|
-
end
|
400
|
-
|
401
|
-
def requirement_class
|
402
|
-
return @requirement_class if @requirement_class
|
403
|
-
|
404
|
-
Utils.requirement_class_for_package_manager(dependency.package_manager)
|
405
|
-
end
|
406
|
-
|
407
|
-
def sha_for_update_pack_line(line)
|
408
|
-
line.split(" ").first.chars.last(40).join
|
409
|
-
end
|
410
|
-
end
|
411
|
-
end
|
412
|
-
# rubocop:enable Metrics/ClassLength
|