dependabot-common 0.220.0 → 0.221.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
- data/lib/dependabot/dependency_file.rb +8 -2
- data/lib/dependabot/dependency_group.rb +4 -1
- data/lib/dependabot/file_fetchers/base.rb +1 -1
- data/lib/dependabot/file_parsers/base/dependency_set.rb +1 -7
- data/lib/dependabot/file_updaters/artifact_updater.rb +102 -0
- data/lib/dependabot/file_updaters/vendor_updater.rb +16 -62
- data/lib/dependabot/pull_request_creator/branch_namer/base.rb +52 -0
- data/lib/dependabot/pull_request_creator/branch_namer/dependency_group_strategy.rb +14 -14
- data/lib/dependabot/pull_request_creator/branch_namer/solo_strategy.rb +3 -36
- data/lib/dependabot/pull_request_creator/message_builder.rb +34 -4
- data/lib/dependabot/shared_helpers.rb +16 -10
- data/lib/dependabot/workspace/base.rb +46 -0
- data/lib/dependabot/workspace/change_attempt.rb +25 -0
- data/lib/dependabot/workspace/git.rb +122 -0
- data/lib/dependabot/workspace.rb +41 -0
- data/lib/dependabot.rb +1 -1
- metadata +11 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 883ba90c6d526f51118f6fabc2082e4ddd09cd73338f103978e2c59a63c6ef67
|
4
|
+
data.tar.gz: e86edce90676becde42edc6fdc7c7a17304ddab77966905d059a3ae11934d8f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a806d1c610355284b4a98a4e3b6ae5ad7f070be18af6fadf23ed98b2ac842eeb55ccc09f4e90c5483b2ab42821ece37c1c3390133817f61e52c4fc580fda111d
|
7
|
+
data.tar.gz: 87ca2cbe54385a9ebd526ea9016ef652f183eb7b9b5d8be0849cd5ad7513ba5ce57071081c95788e3eb92600696ca801fa2abbbe020c32d537c26157bcb38d3b
|
@@ -5,7 +5,8 @@ require "pathname"
|
|
5
5
|
module Dependabot
|
6
6
|
class DependencyFile
|
7
7
|
attr_accessor :name, :content, :directory, :type, :support_file,
|
8
|
-
:
|
8
|
+
:vendored_file, :symlink_target, :content_encoding,
|
9
|
+
:operation, :mode
|
9
10
|
|
10
11
|
class ContentEncoding
|
11
12
|
UTF_8 = "utf-8"
|
@@ -19,7 +20,7 @@ module Dependabot
|
|
19
20
|
end
|
20
21
|
|
21
22
|
def initialize(name:, content:, directory: "/", type: "file",
|
22
|
-
support_file: false, symlink_target: nil,
|
23
|
+
support_file: false, vendored_file: false, symlink_target: nil,
|
23
24
|
content_encoding: ContentEncoding::UTF_8, deleted: false,
|
24
25
|
operation: Operation::UPDATE, mode: nil)
|
25
26
|
@name = name
|
@@ -27,6 +28,7 @@ module Dependabot
|
|
27
28
|
@directory = clean_directory(directory)
|
28
29
|
@symlink_target = symlink_target
|
29
30
|
@support_file = support_file
|
31
|
+
@vendored_file = vendored_file
|
30
32
|
@content_encoding = content_encoding
|
31
33
|
@operation = operation
|
32
34
|
|
@@ -94,6 +96,10 @@ module Dependabot
|
|
94
96
|
@support_file
|
95
97
|
end
|
96
98
|
|
99
|
+
def vendored_file?
|
100
|
+
@vendored_file
|
101
|
+
end
|
102
|
+
|
97
103
|
def deleted
|
98
104
|
@operation == Operation::DELETE
|
99
105
|
end
|
@@ -14,7 +14,10 @@ module Dependabot
|
|
14
14
|
|
15
15
|
def contains?(dependency)
|
16
16
|
@dependencies.include?(dependency) if @dependencies.any?
|
17
|
-
rules.any? { |rule| WildcardMatcher.match?(rule, dependency.name) }
|
17
|
+
positive_match = rules["patterns"].any? { |rule| WildcardMatcher.match?(rule, dependency.name) }
|
18
|
+
negative_match = rules["exclude-patterns"]&.any? { |rule| WildcardMatcher.match?(rule, dependency.name) }
|
19
|
+
|
20
|
+
positive_match && !negative_match
|
18
21
|
end
|
19
22
|
|
20
23
|
def to_h
|
@@ -91,13 +91,7 @@ module Dependabot
|
|
91
91
|
@combined = if @combined
|
92
92
|
combined_dependency(@combined, dep)
|
93
93
|
else
|
94
|
-
|
95
|
-
name: dep.name,
|
96
|
-
version: dep.version,
|
97
|
-
requirements: dep.requirements,
|
98
|
-
package_manager: dep.package_manager,
|
99
|
-
subdependency_metadata: dep.subdependency_metadata
|
100
|
-
)
|
94
|
+
dep
|
101
95
|
end
|
102
96
|
|
103
97
|
index_of_same_version =
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/dependency_file"
|
4
|
+
|
5
|
+
# This class provides a utility to check for arbitary modified files within a
|
6
|
+
# git directory that need to be wrapped as Dependabot::DependencyFile object
|
7
|
+
# and returned as along with anything managed by the FileUpdater itself.
|
8
|
+
module Dependabot
|
9
|
+
module FileUpdaters
|
10
|
+
class ArtifactUpdater
|
11
|
+
# @param repo_contents_path [String, nil] the path we cloned the repository into
|
12
|
+
# @param target_directory [String, nil] the path within a project directory we should inspect for changes
|
13
|
+
def initialize(repo_contents_path:, target_directory:)
|
14
|
+
@repo_contents_path = repo_contents_path
|
15
|
+
@target_directory = target_directory
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns any files that have changed within the path composed from:
|
19
|
+
# :repo_contents_path/:base_directory/:target_directory
|
20
|
+
#
|
21
|
+
# @param base_directory [String] Update config base directory
|
22
|
+
# @param only_paths [Array<String>, nil] An optional list of specific paths to check, if this is nil we will
|
23
|
+
# return every change we find within the `base_directory`
|
24
|
+
# @return [Array<Dependabot::DependencyFile>]
|
25
|
+
def updated_files(base_directory:, only_paths: nil)
|
26
|
+
return [] unless repo_contents_path && target_directory
|
27
|
+
|
28
|
+
Dir.chdir(repo_contents_path) do
|
29
|
+
# rubocop:disable Performance/DeletePrefix
|
30
|
+
relative_dir = Pathname.new(base_directory).sub(%r{\A/}, "").join(target_directory)
|
31
|
+
# rubocop:enable Performance/DeletePrefix
|
32
|
+
|
33
|
+
status = SharedHelpers.run_shell_command(
|
34
|
+
"git status --untracked-files all --porcelain v1 #{relative_dir}",
|
35
|
+
fingerprint: "git status --untracked-files all --porcelain v1 <relative_dir>"
|
36
|
+
)
|
37
|
+
changed_paths = status.split("\n").map(&:split)
|
38
|
+
changed_paths.filter_map do |type, path|
|
39
|
+
project_root = Pathname.new(File.expand_path(File.join(Dir.pwd, base_directory)))
|
40
|
+
file_path = Pathname.new(path).expand_path.relative_path_from(project_root)
|
41
|
+
|
42
|
+
# Skip this file if we are looking for specific paths and this isn't on the list
|
43
|
+
next if only_paths && !only_paths.include?(file_path.to_s)
|
44
|
+
|
45
|
+
# The following types are possible to be returned:
|
46
|
+
# M = Modified = Default for DependencyFile
|
47
|
+
# D = Deleted
|
48
|
+
# ?? = Untracked = Created
|
49
|
+
operation = Dependabot::DependencyFile::Operation::UPDATE
|
50
|
+
operation = Dependabot::DependencyFile::Operation::DELETE if type == "D"
|
51
|
+
operation = Dependabot::DependencyFile::Operation::CREATE if type == "??"
|
52
|
+
|
53
|
+
encoded_content, encoding = get_encoded_file_contents(path, operation)
|
54
|
+
|
55
|
+
create_dependency_file(
|
56
|
+
name: file_path.to_s,
|
57
|
+
content: encoded_content,
|
58
|
+
directory: base_directory,
|
59
|
+
operation: operation,
|
60
|
+
content_encoding: encoding
|
61
|
+
)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
TEXT_ENCODINGS = %w(us-ascii utf-8).freeze
|
69
|
+
|
70
|
+
attr_reader :repo_contents_path, :target_directory
|
71
|
+
|
72
|
+
def get_encoded_file_contents(path, operation)
|
73
|
+
encoded_content = nil
|
74
|
+
encoding = ""
|
75
|
+
|
76
|
+
return encoded_content, encoding if operation == Dependabot::DependencyFile::Operation::DELETE
|
77
|
+
|
78
|
+
encoded_content = File.read(path)
|
79
|
+
|
80
|
+
if binary_file?(path)
|
81
|
+
encoding = Dependabot::DependencyFile::ContentEncoding::BASE64
|
82
|
+
encoded_content = Base64.encode64(encoded_content)
|
83
|
+
end
|
84
|
+
|
85
|
+
[encoded_content, encoding]
|
86
|
+
end
|
87
|
+
|
88
|
+
def binary_file?(path)
|
89
|
+
return false unless File.exist?(path)
|
90
|
+
|
91
|
+
command = SharedHelpers.escape_command("file -b --mime-encoding #{path}")
|
92
|
+
encoding = `#{command}`.strip
|
93
|
+
|
94
|
+
!TEXT_ENCODINGS.include?(encoding)
|
95
|
+
end
|
96
|
+
|
97
|
+
def create_dependency_file(parameters)
|
98
|
+
Dependabot::DependencyFile.new(**parameters)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -1,78 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "dependabot/dependency_file"
|
4
|
-
|
4
|
+
require "dependabot/file_updaters/artifact_updater"
|
5
|
+
|
6
|
+
# This class is a specialisation of the ArtifactUpdater which should be used
|
7
|
+
# for vendored files so any DependencyFile objects it creates are properly
|
8
|
+
# flagged.
|
9
|
+
#
|
10
|
+
# This flagging ensures that the Updater will handle them correctly when
|
11
|
+
# compiling grouped updates.
|
5
12
|
module Dependabot
|
6
13
|
module FileUpdaters
|
7
|
-
class VendorUpdater
|
14
|
+
class VendorUpdater < ArtifactUpdater
|
15
|
+
# This provides backwards compatability for anyone who used this class
|
16
|
+
# before the base ArtifactUpdater class was introduced and aligns the
|
17
|
+
# method's public signatures with it's special-case domain.
|
8
18
|
def initialize(repo_contents_path:, vendor_dir:)
|
9
19
|
@repo_contents_path = repo_contents_path
|
10
20
|
@vendor_dir = vendor_dir
|
21
|
+
super(repo_contents_path: @repo_contents_path, target_directory: @vendor_dir)
|
11
22
|
end
|
12
23
|
|
13
|
-
|
14
|
-
#
|
15
|
-
# @param base_directory [String] Update config base directory
|
16
|
-
# @return [Array<Dependabot::DependencyFile>]
|
17
|
-
def updated_vendor_cache_files(base_directory:)
|
18
|
-
return [] unless repo_contents_path && vendor_dir
|
19
|
-
|
20
|
-
Dir.chdir(repo_contents_path) do
|
21
|
-
# rubocop:disable Performance/DeletePrefix
|
22
|
-
relative_dir = Pathname.new(base_directory).sub(%r{\A/}, "").join(vendor_dir)
|
23
|
-
# rubocop:enable Performance/DeletePrefix
|
24
|
-
|
25
|
-
status = SharedHelpers.run_shell_command(
|
26
|
-
"git status --untracked-files all --porcelain v1 #{relative_dir}",
|
27
|
-
fingerprint: "git status --untracked-files all --porcelain v1 <relative_dir>"
|
28
|
-
)
|
29
|
-
changed_paths = status.split("\n").map(&:split)
|
30
|
-
changed_paths.map do |type, path|
|
31
|
-
# The following types are possible to be returned:
|
32
|
-
# M = Modified = Default for DependencyFile
|
33
|
-
# D = Deleted
|
34
|
-
# ?? = Untracked = Created
|
35
|
-
operation = Dependabot::DependencyFile::Operation::UPDATE
|
36
|
-
operation = Dependabot::DependencyFile::Operation::DELETE if type == "D"
|
37
|
-
operation = Dependabot::DependencyFile::Operation::CREATE if type == "??"
|
38
|
-
encoding = ""
|
39
|
-
encoded_content = File.read(path) unless operation == Dependabot::DependencyFile::Operation::DELETE
|
40
|
-
if binary_file?(path)
|
41
|
-
encoding = Dependabot::DependencyFile::ContentEncoding::BASE64
|
42
|
-
if operation != Dependabot::DependencyFile::Operation::DELETE
|
43
|
-
encoded_content = Base64.encode64(encoded_content)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
project_root =
|
48
|
-
Pathname.new(File.expand_path(File.join(Dir.pwd, base_directory)))
|
49
|
-
file_path =
|
50
|
-
Pathname.new(path).expand_path.relative_path_from(project_root)
|
51
|
-
|
52
|
-
Dependabot::DependencyFile.new(
|
53
|
-
name: file_path.to_s,
|
54
|
-
content: encoded_content,
|
55
|
-
directory: base_directory,
|
56
|
-
operation: operation,
|
57
|
-
content_encoding: encoding
|
58
|
-
)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
24
|
+
alias updated_vendor_cache_files updated_files
|
62
25
|
|
63
26
|
private
|
64
27
|
|
65
|
-
|
66
|
-
|
67
|
-
attr_reader :repo_contents_path, :vendor_dir
|
68
|
-
|
69
|
-
def binary_file?(path)
|
70
|
-
return false unless File.exist?(path)
|
71
|
-
|
72
|
-
command = SharedHelpers.escape_command("file -b --mime-encoding #{path}")
|
73
|
-
encoding = `#{command}`.strip
|
74
|
-
|
75
|
-
!TEXT_ENCODINGS.include?(encoding)
|
28
|
+
def create_dependency_file(parameters)
|
29
|
+
Dependabot::DependencyFile.new(**parameters.merge({ vendored_file: true }))
|
76
30
|
end
|
77
31
|
end
|
78
32
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dependabot
|
4
|
+
class PullRequestCreator
|
5
|
+
class BranchNamer
|
6
|
+
class Base
|
7
|
+
attr_reader :dependencies, :files, :target_branch, :separator, :prefix, :max_length
|
8
|
+
|
9
|
+
def initialize(dependencies:, files:, target_branch:, separator: "/",
|
10
|
+
prefix: "dependabot", max_length: nil)
|
11
|
+
@dependencies = dependencies
|
12
|
+
@files = files
|
13
|
+
@target_branch = target_branch
|
14
|
+
@separator = separator
|
15
|
+
@prefix = prefix
|
16
|
+
@max_length = max_length
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def sanitize_branch_name(ref_name)
|
22
|
+
# General git ref validation
|
23
|
+
sanitized_name = sanitize_ref(ref_name)
|
24
|
+
|
25
|
+
# Some users need branch names without slashes
|
26
|
+
sanitized_name = sanitized_name.gsub("/", separator)
|
27
|
+
|
28
|
+
# Shorten the ref in case users refs have length limits
|
29
|
+
if max_length && (sanitized_name.length > max_length)
|
30
|
+
sha = Digest::SHA1.hexdigest(sanitized_name)[0, max_length]
|
31
|
+
sanitized_name[[max_length - sha.size, 0].max..] = sha
|
32
|
+
end
|
33
|
+
|
34
|
+
sanitized_name
|
35
|
+
end
|
36
|
+
|
37
|
+
def sanitize_ref(ref)
|
38
|
+
# This isn't a complete implementation of git's ref validation, but it
|
39
|
+
# covers most cases that crop up. Its list of allowed characters is a
|
40
|
+
# bit stricter than git's, but that's for cosmetic reasons.
|
41
|
+
ref.
|
42
|
+
# Remove forbidden characters (those not already replaced elsewhere)
|
43
|
+
gsub(%r{[^A-Za-z0-9/\-_.(){}]}, "").
|
44
|
+
# Slashes can't be followed by periods
|
45
|
+
gsub(%r{/\.}, "/dot-").squeeze(".").squeeze("/").
|
46
|
+
# Trailing periods are forbidden
|
47
|
+
sub(/\.$/, "")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -1,32 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "dependabot/pull_request_creator/branch_namer/base"
|
4
|
+
|
3
5
|
module Dependabot
|
4
6
|
class PullRequestCreator
|
5
7
|
class BranchNamer
|
6
|
-
class DependencyGroupStrategy
|
8
|
+
class DependencyGroupStrategy < Base
|
7
9
|
def initialize(dependencies:, files:, target_branch:, dependency_group:,
|
8
10
|
separator: "/", prefix: "dependabot", max_length: nil)
|
9
|
-
|
10
|
-
|
11
|
-
|
11
|
+
super(
|
12
|
+
dependencies: dependencies,
|
13
|
+
files: files,
|
14
|
+
target_branch: target_branch,
|
15
|
+
separator: separator,
|
16
|
+
prefix: prefix,
|
17
|
+
max_length: max_length
|
18
|
+
)
|
19
|
+
|
12
20
|
@dependency_group = dependency_group
|
13
|
-
@separator = separator
|
14
|
-
@prefix = prefix
|
15
|
-
@max_length = max_length
|
16
21
|
end
|
17
22
|
|
18
|
-
# FIXME: Incorporate max_length truncation once we allow user config
|
19
|
-
#
|
20
|
-
# For now, we are using a placeholder DependencyGroup with a
|
21
|
-
# fixed-length name, so we can punt on handling truncation until
|
22
|
-
# we determine the strict validation rules for names
|
23
23
|
def new_branch_name
|
24
|
-
File.join(prefixes, group_name_with_dependency_digest)
|
24
|
+
sanitize_branch_name(File.join(prefixes, group_name_with_dependency_digest))
|
25
25
|
end
|
26
26
|
|
27
27
|
private
|
28
28
|
|
29
|
-
attr_reader :
|
29
|
+
attr_reader :dependency_group
|
30
30
|
|
31
31
|
def prefixes
|
32
32
|
[
|
@@ -3,23 +3,12 @@
|
|
3
3
|
require "digest"
|
4
4
|
|
5
5
|
require "dependabot/metadata_finders"
|
6
|
+
require "dependabot/pull_request_creator/branch_namer/base"
|
6
7
|
|
7
8
|
module Dependabot
|
8
9
|
class PullRequestCreator
|
9
10
|
class BranchNamer
|
10
|
-
class SoloStrategy
|
11
|
-
attr_reader :dependencies, :files, :target_branch, :separator, :prefix, :max_length
|
12
|
-
|
13
|
-
def initialize(dependencies:, files:, target_branch:, separator: "/",
|
14
|
-
prefix: "dependabot", max_length: nil)
|
15
|
-
@dependencies = dependencies
|
16
|
-
@files = files
|
17
|
-
@target_branch = target_branch
|
18
|
-
@separator = separator
|
19
|
-
@prefix = prefix
|
20
|
-
@max_length = max_length
|
21
|
-
end
|
22
|
-
|
11
|
+
class SoloStrategy < Base
|
23
12
|
def new_branch_name
|
24
13
|
@name ||=
|
25
14
|
begin
|
@@ -39,16 +28,7 @@ module Dependabot
|
|
39
28
|
"#{dependency_name_part}-#{branch_version_suffix}"
|
40
29
|
end
|
41
30
|
|
42
|
-
|
43
|
-
sanitized_name = sanitize_ref(File.join(prefixes, @name).gsub("/", separator))
|
44
|
-
|
45
|
-
# Shorten the ref in case users refs have length limits
|
46
|
-
if @max_length && (sanitized_name.length > @max_length)
|
47
|
-
sha = Digest::SHA1.hexdigest(sanitized_name)[0, @max_length]
|
48
|
-
sanitized_name[[@max_length - sha.size, 0].max..] = sha
|
49
|
-
end
|
50
|
-
|
51
|
-
sanitized_name
|
31
|
+
sanitize_branch_name(File.join(prefixes, @name))
|
52
32
|
end
|
53
33
|
|
54
34
|
private
|
@@ -189,19 +169,6 @@ module Dependabot
|
|
189
169
|
def requirements_changed?(dependency)
|
190
170
|
(dependency.requirements - dependency.previous_requirements).any?
|
191
171
|
end
|
192
|
-
|
193
|
-
def sanitize_ref(ref)
|
194
|
-
# This isn't a complete implementation of git's ref validation, but it
|
195
|
-
# covers most cases that crop up. Its list of allowed characters is a
|
196
|
-
# bit stricter than git's, but that's for cosmetic reasons.
|
197
|
-
ref.
|
198
|
-
# Remove forbidden characters (those not already replaced elsewhere)
|
199
|
-
gsub(%r{[^A-Za-z0-9/\-_.(){}]}, "").
|
200
|
-
# Slashes can't be followed by periods
|
201
|
-
gsub(%r{/\.}, "/dot-").squeeze(".").squeeze("/").
|
202
|
-
# Trailing periods are forbidden
|
203
|
-
sub(/\.$/, "")
|
204
|
-
end
|
205
172
|
end
|
206
173
|
end
|
207
174
|
end
|
@@ -315,13 +315,21 @@ module Dependabot
|
|
315
315
|
def group_intro
|
316
316
|
update_count = dependencies.map(&:name).uniq.count
|
317
317
|
|
318
|
-
msg = "Bumps the #{dependency_group.name} group#{pr_name_directory}
|
319
|
-
|
320
|
-
|
318
|
+
msg = "Bumps the #{dependency_group.name} group#{pr_name_directory} " \
|
319
|
+
"with #{update_count} update#{update_count > 1 ? 's' : ''}:"
|
320
|
+
|
321
|
+
msg += if update_count >= 5
|
322
|
+
header = %w(Package Update)
|
323
|
+
rows = dependencies.map { |dep| [dependency_link(dep), dependency_version_update(dep)] }
|
324
|
+
"\n\n#{table([header] + rows)}"
|
325
|
+
elsif update_count > 1
|
326
|
+
" #{dependency_links[0..-2].join(', ')} and #{dependency_links[-1]}."
|
321
327
|
else
|
322
|
-
"
|
328
|
+
" #{dependency_links.first}."
|
323
329
|
end
|
324
330
|
|
331
|
+
msg += "\n"
|
332
|
+
|
325
333
|
msg
|
326
334
|
end
|
327
335
|
|
@@ -389,6 +397,10 @@ module Dependabot
|
|
389
397
|
end
|
390
398
|
end
|
391
399
|
|
400
|
+
def dependency_version_update(dependency)
|
401
|
+
"#{dependency.humanized_previous_version} to #{dependency.humanized_version}"
|
402
|
+
end
|
403
|
+
|
392
404
|
def metadata_links
|
393
405
|
return metadata_links_for_dep(dependencies.first) if dependencies.count == 1
|
394
406
|
|
@@ -413,6 +425,24 @@ module Dependabot
|
|
413
425
|
msg
|
414
426
|
end
|
415
427
|
|
428
|
+
def table(rows)
|
429
|
+
[
|
430
|
+
table_header(rows[0]),
|
431
|
+
rows[1..].map { |r| table_row(r) }
|
432
|
+
].join("\n")
|
433
|
+
end
|
434
|
+
|
435
|
+
def table_header(row)
|
436
|
+
[
|
437
|
+
table_row(row),
|
438
|
+
table_row(["---"] * row.count)
|
439
|
+
].join("\n")
|
440
|
+
end
|
441
|
+
|
442
|
+
def table_row(row)
|
443
|
+
"| #{row.join(' | ')} |"
|
444
|
+
end
|
445
|
+
|
416
446
|
def metadata_cascades
|
417
447
|
return metadata_cascades_for_dep(dependencies.first) if dependencies.one?
|
418
448
|
|
@@ -12,6 +12,7 @@ require "tmpdir"
|
|
12
12
|
require "dependabot/simple_instrumentor"
|
13
13
|
require "dependabot/utils"
|
14
14
|
require "dependabot/errors"
|
15
|
+
require "dependabot/workspace"
|
15
16
|
require "dependabot"
|
16
17
|
|
17
18
|
module Dependabot
|
@@ -23,17 +24,22 @@ module Dependabot
|
|
23
24
|
"(+https://github.com/dependabot/dependabot-core)"
|
24
25
|
SIGKILL = 9
|
25
26
|
|
26
|
-
def self.in_a_temporary_repo_directory(directory = "/",
|
27
|
-
repo_contents_path = nil,
|
28
|
-
&block)
|
27
|
+
def self.in_a_temporary_repo_directory(directory = "/", repo_contents_path = nil, &block)
|
29
28
|
if repo_contents_path
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
29
|
+
# If a workspace has been defined to allow orcestration of the git repo
|
30
|
+
# by the runtime we should defer to it, otherwise we prepare the folder
|
31
|
+
# for direct use and yield.
|
32
|
+
if Dependabot::Workspace.active_workspace
|
33
|
+
Dependabot::Workspace.active_workspace.change(&block)
|
34
|
+
else
|
35
|
+
path = Pathname.new(File.join(repo_contents_path, directory)).expand_path
|
36
|
+
reset_git_repo(repo_contents_path)
|
37
|
+
# Handle missing directories by creating an empty one and relying on the
|
38
|
+
# file fetcher to raise a DependencyFileNotFound error
|
39
|
+
FileUtils.mkdir_p(path)
|
40
|
+
|
41
|
+
Dir.chdir(path) { yield(path) }
|
42
|
+
end
|
37
43
|
else
|
38
44
|
in_a_temporary_directory(directory, &block)
|
39
45
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dependabot
|
4
|
+
module Workspace
|
5
|
+
class Base
|
6
|
+
attr_reader :change_attempts, :path
|
7
|
+
|
8
|
+
def initialize(path)
|
9
|
+
@path = path
|
10
|
+
@change_attempts = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def changed?
|
14
|
+
changes.any?
|
15
|
+
end
|
16
|
+
|
17
|
+
def changes
|
18
|
+
change_attempts.select(&:success?)
|
19
|
+
end
|
20
|
+
|
21
|
+
def failed_change_attempts
|
22
|
+
change_attempts.select(&:error?)
|
23
|
+
end
|
24
|
+
|
25
|
+
def change(memo = nil)
|
26
|
+
Dir.chdir(path) { yield(path) }
|
27
|
+
rescue StandardError => e
|
28
|
+
capture_failed_change_attempt(memo, e)
|
29
|
+
clean # clean up any failed changes
|
30
|
+
raise e
|
31
|
+
end
|
32
|
+
|
33
|
+
def store_change(memo = nil); end
|
34
|
+
|
35
|
+
def to_patch
|
36
|
+
""
|
37
|
+
end
|
38
|
+
|
39
|
+
def reset!; end
|
40
|
+
|
41
|
+
protected
|
42
|
+
|
43
|
+
def capture_failed_change_attempt(memo = nil, error = nil); end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dependabot
|
4
|
+
module Workspace
|
5
|
+
class ChangeAttempt
|
6
|
+
attr_reader :diff, :error, :id, :memo, :workspace
|
7
|
+
|
8
|
+
def initialize(workspace, id:, memo:, diff: nil, error: nil)
|
9
|
+
@workspace = workspace
|
10
|
+
@id = id
|
11
|
+
@memo = memo
|
12
|
+
@diff = diff
|
13
|
+
@error = error
|
14
|
+
end
|
15
|
+
|
16
|
+
def success?
|
17
|
+
error.nil?
|
18
|
+
end
|
19
|
+
|
20
|
+
def error?
|
21
|
+
error
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/workspace/base"
|
4
|
+
require "dependabot/workspace/change_attempt"
|
5
|
+
|
6
|
+
module Dependabot
|
7
|
+
module Workspace
|
8
|
+
class Git < Base
|
9
|
+
USER = "dependabot[bot]"
|
10
|
+
EMAIL = "#{USER}@users.noreply.github.com"
|
11
|
+
|
12
|
+
attr_reader :initial_head_sha
|
13
|
+
|
14
|
+
def initialize(path)
|
15
|
+
super(path)
|
16
|
+
@initial_head_sha = head_sha
|
17
|
+
configure_git
|
18
|
+
end
|
19
|
+
|
20
|
+
def changed?
|
21
|
+
changes.any? || !changed_files.empty?
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_patch
|
25
|
+
run_shell_command("git diff --patch #{@initial_head_sha}.. .")
|
26
|
+
end
|
27
|
+
|
28
|
+
def reset!
|
29
|
+
reset(initial_head_sha)
|
30
|
+
clean
|
31
|
+
run_shell_command("git stash clear")
|
32
|
+
@change_attempts = []
|
33
|
+
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def store_change(memo = nil)
|
38
|
+
return nil if changed_files.empty?
|
39
|
+
|
40
|
+
debug("store_change - before: #{current_commit}")
|
41
|
+
sha, diff = commit(memo)
|
42
|
+
|
43
|
+
change_attempts << ChangeAttempt.new(self, id: sha, memo: memo, diff: diff)
|
44
|
+
ensure
|
45
|
+
debug("store_change - after: #{current_commit}")
|
46
|
+
end
|
47
|
+
|
48
|
+
protected
|
49
|
+
|
50
|
+
def capture_failed_change_attempt(memo = nil, error = nil)
|
51
|
+
return nil if changed_files(ignored_mode: "matching").empty? && error.nil?
|
52
|
+
|
53
|
+
sha, diff = stash(memo)
|
54
|
+
change_attempts << ChangeAttempt.new(self, id: sha, memo: memo, diff: diff, error: error)
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def configure_git
|
60
|
+
run_shell_command(%(git config user.name "#{USER}"), allow_unsafe_shell_command: true)
|
61
|
+
run_shell_command(%(git config user.email "#{EMAIL}"), allow_unsafe_shell_command: true)
|
62
|
+
end
|
63
|
+
|
64
|
+
def head_sha
|
65
|
+
run_shell_command("git rev-parse HEAD").strip
|
66
|
+
end
|
67
|
+
|
68
|
+
def last_stash_sha
|
69
|
+
run_shell_command("git rev-parse refs/stash").strip
|
70
|
+
end
|
71
|
+
|
72
|
+
def current_commit
|
73
|
+
# Avoid emiting the user's commit message to logs if Dependabot hasn't made any changes
|
74
|
+
return "Initial SHA: #{initial_head_sha}" if changes.empty?
|
75
|
+
|
76
|
+
# Prints out the last commit in the format "<short-ref> <commit-message>"
|
77
|
+
run_shell_command(%(git log -1 --pretty="%h% B"), allow_unsafe_shell_command: true).strip
|
78
|
+
end
|
79
|
+
|
80
|
+
def changed_files(ignored_mode: "traditional")
|
81
|
+
run_shell_command("git status --untracked-files=all --ignored=#{ignored_mode} --short .").strip
|
82
|
+
end
|
83
|
+
|
84
|
+
def stash(memo = nil)
|
85
|
+
msg = memo || "workspace change attempt"
|
86
|
+
run_shell_command("git add --all --force .")
|
87
|
+
run_shell_command(%(git stash push --all -m "#{msg}"), allow_unsafe_shell_command: true)
|
88
|
+
|
89
|
+
sha = last_stash_sha
|
90
|
+
diff = run_shell_command("git stash show --patch #{sha}")
|
91
|
+
|
92
|
+
[sha, diff]
|
93
|
+
end
|
94
|
+
|
95
|
+
def commit(memo = nil)
|
96
|
+
run_shell_command("git add #{path}")
|
97
|
+
diff = run_shell_command("git diff --cached .")
|
98
|
+
|
99
|
+
msg = memo || "workspace change"
|
100
|
+
run_shell_command(%(git commit -m "#{msg}"), allow_unsafe_shell_command: true)
|
101
|
+
|
102
|
+
[head_sha, diff]
|
103
|
+
end
|
104
|
+
|
105
|
+
def reset(sha)
|
106
|
+
run_shell_command("git reset --hard #{sha}")
|
107
|
+
end
|
108
|
+
|
109
|
+
def clean
|
110
|
+
run_shell_command("git clean -fx .")
|
111
|
+
end
|
112
|
+
|
113
|
+
def run_shell_command(*args, **kwargs)
|
114
|
+
Dir.chdir(path) { SharedHelpers.run_shell_command(*args, **kwargs) }
|
115
|
+
end
|
116
|
+
|
117
|
+
def debug(message)
|
118
|
+
Dependabot.logger.debug("[workspace] #{message}")
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/workspace/git"
|
4
|
+
|
5
|
+
module Dependabot
|
6
|
+
module Workspace
|
7
|
+
@active_workspace = nil
|
8
|
+
|
9
|
+
class << self
|
10
|
+
attr_accessor :active_workspace
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.setup(repo_contents_path:, directory:)
|
14
|
+
Dependabot.logger.debug("Setting up workspace in #{repo_contents_path}")
|
15
|
+
|
16
|
+
full_path = Pathname.new(File.join(repo_contents_path, directory)).expand_path
|
17
|
+
# Handle missing directories by creating an empty one and relying on the
|
18
|
+
# file fetcher to raise a DependencyFileNotFound error
|
19
|
+
FileUtils.mkdir_p(full_path)
|
20
|
+
|
21
|
+
@active_workspace = Dependabot::Workspace::Git.new(full_path)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.store_change(memo:)
|
25
|
+
return unless @active_workspace
|
26
|
+
|
27
|
+
Dependabot.logger.debug("Storing change to workspace: #{memo}")
|
28
|
+
|
29
|
+
@active_workspace.store_change(memo)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.cleanup!
|
33
|
+
return unless @active_workspace
|
34
|
+
|
35
|
+
Dependabot.logger.debug("Cleaning up current workspace")
|
36
|
+
|
37
|
+
@active_workspace.reset!
|
38
|
+
@active_workspace = nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/dependabot.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dependabot-common
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.221.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dependabot
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-07-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-codecommit
|
@@ -248,14 +248,14 @@ dependencies:
|
|
248
248
|
requirements:
|
249
249
|
- - "~>"
|
250
250
|
- !ruby/object:Gem::Version
|
251
|
-
version: 1.
|
251
|
+
version: 1.8.0
|
252
252
|
type: :development
|
253
253
|
prerelease: false
|
254
254
|
version_requirements: !ruby/object:Gem::Requirement
|
255
255
|
requirements:
|
256
256
|
- - "~>"
|
257
257
|
- !ruby/object:Gem::Version
|
258
|
-
version: 1.
|
258
|
+
version: 1.8.0
|
259
259
|
- !ruby/object:Gem::Dependency
|
260
260
|
name: gpgme
|
261
261
|
requirement: !ruby/object:Gem::Requirement
|
@@ -354,34 +354,6 @@ dependencies:
|
|
354
354
|
- - "~>"
|
355
355
|
- !ruby/object:Gem::Version
|
356
356
|
version: 1.17.1
|
357
|
-
- !ruby/object:Gem::Dependency
|
358
|
-
name: simplecov
|
359
|
-
requirement: !ruby/object:Gem::Requirement
|
360
|
-
requirements:
|
361
|
-
- - "~>"
|
362
|
-
- !ruby/object:Gem::Version
|
363
|
-
version: 0.22.0
|
364
|
-
type: :development
|
365
|
-
prerelease: false
|
366
|
-
version_requirements: !ruby/object:Gem::Requirement
|
367
|
-
requirements:
|
368
|
-
- - "~>"
|
369
|
-
- !ruby/object:Gem::Version
|
370
|
-
version: 0.22.0
|
371
|
-
- !ruby/object:Gem::Dependency
|
372
|
-
name: simplecov-console
|
373
|
-
requirement: !ruby/object:Gem::Requirement
|
374
|
-
requirements:
|
375
|
-
- - "~>"
|
376
|
-
- !ruby/object:Gem::Version
|
377
|
-
version: 0.9.1
|
378
|
-
type: :development
|
379
|
-
prerelease: false
|
380
|
-
version_requirements: !ruby/object:Gem::Requirement
|
381
|
-
requirements:
|
382
|
-
- - "~>"
|
383
|
-
- !ruby/object:Gem::Version
|
384
|
-
version: 0.9.1
|
385
357
|
- !ruby/object:Gem::Dependency
|
386
358
|
name: stackprof
|
387
359
|
requirement: !ruby/object:Gem::Requirement
|
@@ -458,6 +430,7 @@ files:
|
|
458
430
|
- lib/dependabot/file_parsers/base/dependency_set.rb
|
459
431
|
- lib/dependabot/file_updaters.rb
|
460
432
|
- lib/dependabot/file_updaters/README.md
|
433
|
+
- lib/dependabot/file_updaters/artifact_updater.rb
|
461
434
|
- lib/dependabot/file_updaters/base.rb
|
462
435
|
- lib/dependabot/file_updaters/vendor_updater.rb
|
463
436
|
- lib/dependabot/git_commit_checker.rb
|
@@ -474,6 +447,7 @@ files:
|
|
474
447
|
- lib/dependabot/pull_request_creator/azure.rb
|
475
448
|
- lib/dependabot/pull_request_creator/bitbucket.rb
|
476
449
|
- lib/dependabot/pull_request_creator/branch_namer.rb
|
450
|
+
- lib/dependabot/pull_request_creator/branch_namer/base.rb
|
477
451
|
- lib/dependabot/pull_request_creator/branch_namer/dependency_group_strategy.rb
|
478
452
|
- lib/dependabot/pull_request_creator/branch_namer/solo_strategy.rb
|
479
453
|
- lib/dependabot/pull_request_creator/codecommit.rb
|
@@ -502,13 +476,17 @@ files:
|
|
502
476
|
- lib/dependabot/update_checkers/version_filters.rb
|
503
477
|
- lib/dependabot/utils.rb
|
504
478
|
- lib/dependabot/version.rb
|
479
|
+
- lib/dependabot/workspace.rb
|
480
|
+
- lib/dependabot/workspace/base.rb
|
481
|
+
- lib/dependabot/workspace/change_attempt.rb
|
482
|
+
- lib/dependabot/workspace/git.rb
|
505
483
|
- lib/wildcard_matcher.rb
|
506
484
|
homepage: https://github.com/dependabot/dependabot-core
|
507
485
|
licenses:
|
508
486
|
- Nonstandard
|
509
487
|
metadata:
|
510
488
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
511
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
489
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.221.0
|
512
490
|
post_install_message:
|
513
491
|
rdoc_options: []
|
514
492
|
require_paths:
|