dependabot-common 0.220.0 → 0.221.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|