dependabot-bazel 0.349.0 → 0.350.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/bazel/file_fetcher/bzl_file_fetcher.rb +116 -0
- data/lib/dependabot/bazel/file_fetcher/directory_tree_fetcher.rb +79 -0
- data/lib/dependabot/bazel/file_fetcher/downloader_config_fetcher.rb +58 -0
- data/lib/dependabot/bazel/file_fetcher/module_path_extractor.rb +83 -0
- data/lib/dependabot/bazel/file_fetcher/path_converter.rb +78 -0
- data/lib/dependabot/bazel/file_fetcher.rb +54 -72
- data/lib/dependabot/bazel/file_parser.rb +1 -2
- data/lib/dependabot/bazel/version.rb +62 -3
- metadata +9 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 89e2aed09f75955bca16702b04e8fdda1daa176158f51b14b83d1d7134071b32
|
|
4
|
+
data.tar.gz: d4e6d299e8d7f66a35ef8dd53dc90b6d072cd7c4b7f26b3d1c5154ecb9434722
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 33a3bae8546312ada4aa162f6b4c8b31141f6d87b5d859bb0b87f7e3357297c9fe4eb2fd52714657aa5f951911fbcf19ebada4fd92a58dcfc5549dff5c6a0120
|
|
7
|
+
data.tar.gz: 90609272d6e1707e079c13d3a2648c9dd85892207193dbb926fa8644fbfcd511deacc60b4c16b57dfd022b7b9445fe09fb5057d9e264d0f0695d686cabc5048d
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "dependabot/bazel/file_fetcher"
|
|
5
|
+
require "sorbet-runtime"
|
|
6
|
+
|
|
7
|
+
module Dependabot
|
|
8
|
+
module Bazel
|
|
9
|
+
class FileFetcher < Dependabot::FileFetchers::Base
|
|
10
|
+
# Fetches .bzl files and their dependencies recursively.
|
|
11
|
+
# Handles load() and Label() statements to build a complete dependency graph.
|
|
12
|
+
class BzlFileFetcher
|
|
13
|
+
extend T::Sig
|
|
14
|
+
|
|
15
|
+
sig do
|
|
16
|
+
params(
|
|
17
|
+
module_file: DependencyFile,
|
|
18
|
+
fetcher: FileFetcher
|
|
19
|
+
).void
|
|
20
|
+
end
|
|
21
|
+
def initialize(module_file:, fetcher:)
|
|
22
|
+
@module_file = module_file
|
|
23
|
+
@fetcher = fetcher
|
|
24
|
+
@visited_bzl_files = T.let(Set.new, T::Set[String])
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
sig { returns(T::Array[DependencyFile]) }
|
|
28
|
+
def fetch_bzl_files
|
|
29
|
+
content = T.must(@module_file.content)
|
|
30
|
+
bzl_file_paths = extract_bzl_file_paths(content)
|
|
31
|
+
fetch_bzl_files_recursively(bzl_file_paths)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
sig { returns(DependencyFile) }
|
|
37
|
+
attr_reader :module_file
|
|
38
|
+
|
|
39
|
+
sig { returns(FileFetcher) }
|
|
40
|
+
attr_reader :fetcher
|
|
41
|
+
|
|
42
|
+
sig { returns(T::Set[String]) }
|
|
43
|
+
attr_reader :visited_bzl_files
|
|
44
|
+
|
|
45
|
+
# Fetches .bzl files recursively, following their load() and Label() dependencies.
|
|
46
|
+
sig { params(paths: T::Array[String]).returns(T::Array[DependencyFile]) }
|
|
47
|
+
def fetch_bzl_files_recursively(paths)
|
|
48
|
+
files = T.let([], T::Array[DependencyFile])
|
|
49
|
+
|
|
50
|
+
paths.each do |path|
|
|
51
|
+
next if visited_bzl_files.include?(path)
|
|
52
|
+
|
|
53
|
+
fetched_file = fetcher.send(:fetch_file_if_present, path)
|
|
54
|
+
next unless fetched_file
|
|
55
|
+
|
|
56
|
+
files << fetched_file
|
|
57
|
+
visited_bzl_files.add(path)
|
|
58
|
+
|
|
59
|
+
if path.end_with?(".bzl")
|
|
60
|
+
bzl_deps = extract_bzl_load_dependencies(fetched_file.content, path)
|
|
61
|
+
files += fetch_bzl_files_recursively(bzl_deps)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
files
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Extracts .bzl file paths from use_extension() and use_repo_rule() calls.
|
|
69
|
+
# Only extracts workspace-relative paths (//...) and filters out external Bazel
|
|
70
|
+
# repositories (@repo//...) since those files don't exist in the current repository.
|
|
71
|
+
sig { params(content: String).returns(T::Array[String]) }
|
|
72
|
+
def extract_bzl_file_paths(content)
|
|
73
|
+
extract_use_extension_paths(content) + extract_use_repo_rule_paths(content)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
sig { params(content: String).returns(T::Array[String]) }
|
|
77
|
+
def extract_use_extension_paths(content)
|
|
78
|
+
content.scan(%r{use_extension\s*\(\s*"//([^"]+)"}).filter_map do |match|
|
|
79
|
+
path = T.must(match[0]).tr(":", "/").sub(%r{^/}, "")
|
|
80
|
+
path if path.end_with?(".bzl")
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
sig { params(content: String).returns(T::Array[String]) }
|
|
85
|
+
def extract_use_repo_rule_paths(content)
|
|
86
|
+
content.scan(%r{use_repo_rule\s*\(\s*"//([^"]+)"}).filter_map do |match|
|
|
87
|
+
path = T.must(match[0]).tr(":", "/").sub(%r{^/}, "")
|
|
88
|
+
path if path.end_with?(".bzl")
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Extracts file dependencies from load() and Label() statements.
|
|
93
|
+
# Only extracts workspace-relative (//...) and file-relative (:...) paths.
|
|
94
|
+
# External Bazel repositories (@repo//...) are excluded since those files
|
|
95
|
+
# exist in different repositories, not the current one being analyzed.
|
|
96
|
+
sig { params(content: String, file_path: String).returns(T::Array[String]) }
|
|
97
|
+
def extract_bzl_load_dependencies(content, file_path)
|
|
98
|
+
paths = []
|
|
99
|
+
file_dir = File.dirname(file_path)
|
|
100
|
+
|
|
101
|
+
content.scan(%r{load\s*\(\s*"(//[^"]+|:[^"]+)"}) do |match|
|
|
102
|
+
path = PathConverter.label_to_path(match[0], context_dir: file_dir)
|
|
103
|
+
paths << path unless path.empty?
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
content.scan(%r{Label\s*\(\s*"(//[^"]+|:[^"]+)"\)}) do |match|
|
|
107
|
+
path = PathConverter.label_to_path(match[0], context_dir: file_dir)
|
|
108
|
+
paths << path unless path.empty?
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
paths
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "dependabot/bazel/file_fetcher"
|
|
5
|
+
require "sorbet-runtime"
|
|
6
|
+
|
|
7
|
+
module Dependabot
|
|
8
|
+
module Bazel
|
|
9
|
+
class FileFetcher < Dependabot::FileFetchers::Base
|
|
10
|
+
# Fetches entire directory trees, typically for local_path_override directories.
|
|
11
|
+
# Includes BUILD files to make directories valid Bazel packages.
|
|
12
|
+
class DirectoryTreeFetcher
|
|
13
|
+
extend T::Sig
|
|
14
|
+
|
|
15
|
+
SKIP_DIRECTORIES = T.let(%w(.git .bazel-* bazel-* node_modules .github).freeze, T::Array[String])
|
|
16
|
+
|
|
17
|
+
sig { params(fetcher: FileFetcher).void }
|
|
18
|
+
def initialize(fetcher:)
|
|
19
|
+
@fetcher = fetcher
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
sig { params(directory: String).returns(T::Array[DependencyFile]) }
|
|
23
|
+
def fetch_directory_tree(directory)
|
|
24
|
+
return [] if should_skip_directory?(directory)
|
|
25
|
+
|
|
26
|
+
files = T.let([], T::Array[DependencyFile])
|
|
27
|
+
|
|
28
|
+
begin
|
|
29
|
+
repo_contents = @fetcher.send(:repo_contents, dir: directory)
|
|
30
|
+
|
|
31
|
+
repo_contents.each do |item|
|
|
32
|
+
path = item.path
|
|
33
|
+
next if path.nil? || should_skip_directory?(path)
|
|
34
|
+
|
|
35
|
+
case item.type
|
|
36
|
+
when "file"
|
|
37
|
+
fetched_file = @fetcher.send(:fetch_file_if_present, path)
|
|
38
|
+
files << fetched_file if fetched_file
|
|
39
|
+
when "dir"
|
|
40
|
+
files += fetch_directory_tree(path)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
rescue Octokit::NotFound, Dependabot::RepoNotFound, Dependabot::DependencyFileNotFound => e
|
|
44
|
+
Dependabot.logger.warn("Skipping inaccessible directory '#{directory}': #{e.message}")
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
files
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
sig { params(directories: T::Set[String]).returns(T::Array[DependencyFile]) }
|
|
51
|
+
def fetch_build_files_for_directories(directories)
|
|
52
|
+
files = T.let([], T::Array[DependencyFile])
|
|
53
|
+
directories.each do |dir|
|
|
54
|
+
build_file = @fetcher.send(:fetch_file_if_present, "#{dir}/BUILD") ||
|
|
55
|
+
@fetcher.send(:fetch_file_if_present, "#{dir}/BUILD.bazel")
|
|
56
|
+
files << build_file if build_file
|
|
57
|
+
end
|
|
58
|
+
files
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
sig { returns(FileFetcher) }
|
|
64
|
+
attr_reader :fetcher
|
|
65
|
+
|
|
66
|
+
sig { params(dirname: String).returns(T::Boolean) }
|
|
67
|
+
def should_skip_directory?(dirname)
|
|
68
|
+
SKIP_DIRECTORIES.any? do |skip_pattern|
|
|
69
|
+
if skip_pattern.end_with?("*")
|
|
70
|
+
dirname.start_with?(skip_pattern.chomp("*"))
|
|
71
|
+
else
|
|
72
|
+
dirname == skip_pattern || dirname.end_with?("/#{skip_pattern}")
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "dependabot/bazel/file_fetcher"
|
|
5
|
+
require "sorbet-runtime"
|
|
6
|
+
|
|
7
|
+
module Dependabot
|
|
8
|
+
module Bazel
|
|
9
|
+
class FileFetcher < Dependabot::FileFetchers::Base
|
|
10
|
+
# Fetches downloader configuration files referenced in .bazelrc.
|
|
11
|
+
# Parses .bazelrc for --downloader_config flags and fetches those files.
|
|
12
|
+
class DownloaderConfigFetcher
|
|
13
|
+
extend T::Sig
|
|
14
|
+
|
|
15
|
+
sig { params(fetcher: FileFetcher).void }
|
|
16
|
+
def initialize(fetcher:)
|
|
17
|
+
@fetcher = fetcher
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
sig { returns(T::Array[DependencyFile]) }
|
|
21
|
+
def fetch_downloader_config_files
|
|
22
|
+
bazelrc_file = @fetcher.send(:fetch_file_if_present, ".bazelrc")
|
|
23
|
+
return [] unless bazelrc_file
|
|
24
|
+
|
|
25
|
+
config_paths = extract_downloader_config_paths(bazelrc_file)
|
|
26
|
+
files = T.let([], T::Array[DependencyFile])
|
|
27
|
+
|
|
28
|
+
config_paths.each do |path|
|
|
29
|
+
fetched_file = @fetcher.send(:fetch_file_if_present, path)
|
|
30
|
+
files << fetched_file if fetched_file
|
|
31
|
+
rescue Dependabot::DependencyFileNotFound
|
|
32
|
+
Dependabot.logger.warn(
|
|
33
|
+
"Downloader config file '#{path}' referenced in .bazelrc but not found in repository"
|
|
34
|
+
)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
files
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
sig { returns(FileFetcher) }
|
|
43
|
+
attr_reader :fetcher
|
|
44
|
+
|
|
45
|
+
sig { params(bazelrc_file: DependencyFile).returns(T::Array[String]) }
|
|
46
|
+
def extract_downloader_config_paths(bazelrc_file)
|
|
47
|
+
content = T.must(bazelrc_file.content)
|
|
48
|
+
extract_downloader_config_flags(content).reject(&:empty?).uniq
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
sig { params(content: String).returns(T::Array[String]) }
|
|
52
|
+
def extract_downloader_config_flags(content)
|
|
53
|
+
content.scan(/--downloader_config[=\s]+(\S+)/).flatten
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "dependabot/bazel/file_fetcher"
|
|
5
|
+
require "dependabot/bazel/file_fetcher/path_converter"
|
|
6
|
+
require "sorbet-runtime"
|
|
7
|
+
|
|
8
|
+
module Dependabot
|
|
9
|
+
module Bazel
|
|
10
|
+
class FileFetcher < Dependabot::FileFetchers::Base
|
|
11
|
+
# Extracts file and directory paths referenced in MODULE.bazel files.
|
|
12
|
+
# Handles attributes like lock_file, requirements_lock, patches, and local_path_override.
|
|
13
|
+
class ModulePathExtractor
|
|
14
|
+
extend T::Sig
|
|
15
|
+
|
|
16
|
+
sig { params(module_file: DependencyFile).void }
|
|
17
|
+
def initialize(module_file:)
|
|
18
|
+
@module_file = module_file
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
sig { returns([T::Array[String], T::Array[String]]) }
|
|
22
|
+
def extract_paths
|
|
23
|
+
content = T.must(@module_file.content)
|
|
24
|
+
file_paths = extract_file_attribute_paths(content)
|
|
25
|
+
directory_paths = extract_directory_paths(content)
|
|
26
|
+
[file_paths.uniq, directory_paths.uniq]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
sig { returns(DependencyFile) }
|
|
32
|
+
attr_reader :module_file
|
|
33
|
+
|
|
34
|
+
# Extracts file paths from lock_file, requirements_lock, and patches attributes.
|
|
35
|
+
sig { params(content: String).returns(T::Array[String]) }
|
|
36
|
+
def extract_file_attribute_paths(content)
|
|
37
|
+
(
|
|
38
|
+
extract_lock_file_paths(content) +
|
|
39
|
+
extract_requirements_lock_paths(content) +
|
|
40
|
+
extract_patches_paths(content)
|
|
41
|
+
).compact
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
sig { params(content: String).returns(T::Array[String]) }
|
|
45
|
+
def extract_lock_file_paths(content)
|
|
46
|
+
content.scan(/lock_file\s*=\s*"([^"]+)"/).map { |match| PathConverter.label_to_path(T.must(match[0])) }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
sig { params(content: String).returns(T::Array[String]) }
|
|
50
|
+
def extract_requirements_lock_paths(content)
|
|
51
|
+
content.scan(/requirements_lock\s*=\s*"([^"]+)"/).map do |match|
|
|
52
|
+
PathConverter.label_to_path(T.must(match[0]))
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
sig { params(content: String).returns(T::Array[String]) }
|
|
57
|
+
def extract_patches_paths(content)
|
|
58
|
+
patches = []
|
|
59
|
+
content.scan(/patches\s*=\s*\[([^\]]+)\]/) do |match|
|
|
60
|
+
match[0].scan(/"([^"]+)"/) { |file| patches << PathConverter.label_to_path(file[0]) }
|
|
61
|
+
end
|
|
62
|
+
content.scan(/patches\s*=\s*"([^"]+)"/) do |match|
|
|
63
|
+
patches << PathConverter.label_to_path(match[0])
|
|
64
|
+
end
|
|
65
|
+
patches
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Extracts directory paths from local_path_override attributes.
|
|
69
|
+
sig { params(content: String).returns(T::Array[String]) }
|
|
70
|
+
def extract_directory_paths(content)
|
|
71
|
+
extract_local_path_override_paths(content)
|
|
72
|
+
.reject { |path| PathConverter.should_filter_path?(path) }
|
|
73
|
+
.map { |path| PathConverter.normalize_path(path) }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
sig { params(content: String).returns(T::Array[String]) }
|
|
77
|
+
def extract_local_path_override_paths(content)
|
|
78
|
+
content.scan(/local_path_override\s*\([^)]*path\s*=\s*"([^"]+)"[^)]*\)/m).flatten
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "dependabot/bazel/file_fetcher"
|
|
5
|
+
require "sorbet-runtime"
|
|
6
|
+
|
|
7
|
+
module Dependabot
|
|
8
|
+
module Bazel
|
|
9
|
+
class FileFetcher < Dependabot::FileFetchers::Base
|
|
10
|
+
# Converts Bazel label syntax to filesystem paths
|
|
11
|
+
class PathConverter
|
|
12
|
+
extend T::Sig
|
|
13
|
+
|
|
14
|
+
sig { params(label: String, context_dir: T.nilable(String)).returns(String) }
|
|
15
|
+
def self.label_to_path(label, context_dir: nil)
|
|
16
|
+
path = strip_external_repo_prefix(label)
|
|
17
|
+
return resolve_relative_path(path, context_dir) if relative_path?(path)
|
|
18
|
+
|
|
19
|
+
convert_absolute_label_to_path(path)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
sig { params(path: String).returns(T::Boolean) }
|
|
23
|
+
def self.should_filter_path?(path)
|
|
24
|
+
absolute_path_or_url?(path)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
sig { params(path: String).returns(String) }
|
|
28
|
+
def self.normalize_path(path)
|
|
29
|
+
remove_leading_dot_slash(path)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
sig { params(label: String).returns(String) }
|
|
33
|
+
private_class_method def self.strip_external_repo_prefix(label)
|
|
34
|
+
label.sub(%r{^@[^/]+//}, "")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
sig { params(path: String).returns(T::Boolean) }
|
|
38
|
+
private_class_method def self.relative_path?(path)
|
|
39
|
+
path.start_with?(":")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
sig { params(path: String, context_dir: T.nilable(String)).returns(String) }
|
|
43
|
+
private_class_method def self.resolve_relative_path(path, context_dir)
|
|
44
|
+
relative_file = path.sub(/^:/, "")
|
|
45
|
+
return relative_file if context_dir.nil? || context_dir == "."
|
|
46
|
+
|
|
47
|
+
"#{context_dir}/#{relative_file}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
sig { params(path: String).returns(String) }
|
|
51
|
+
private_class_method def self.convert_absolute_label_to_path(path)
|
|
52
|
+
path_with_slashes = replace_colon_separator_with_slash(path)
|
|
53
|
+
remove_leading_slashes(path_with_slashes)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
sig { params(path: String).returns(String) }
|
|
57
|
+
private_class_method def self.replace_colon_separator_with_slash(path)
|
|
58
|
+
path.tr(":", "/")
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
sig { params(path: String).returns(String) }
|
|
62
|
+
private_class_method def self.remove_leading_slashes(path)
|
|
63
|
+
path.sub(%r{^/+}, "")
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
sig { params(path: String).returns(T::Boolean) }
|
|
67
|
+
private_class_method def self.absolute_path_or_url?(path)
|
|
68
|
+
path.start_with?("http://", "https://", "/", "@")
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
sig { params(path: String).returns(String) }
|
|
72
|
+
private_class_method def self.remove_leading_dot_slash(path)
|
|
73
|
+
path.sub(%r{^\./}, "")
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -9,12 +9,17 @@ module Dependabot
|
|
|
9
9
|
class FileFetcher < Dependabot::FileFetchers::Base
|
|
10
10
|
extend T::Sig
|
|
11
11
|
|
|
12
|
+
require_relative "file_fetcher/path_converter"
|
|
13
|
+
require_relative "file_fetcher/bzl_file_fetcher"
|
|
14
|
+
require_relative "file_fetcher/module_path_extractor"
|
|
15
|
+
require_relative "file_fetcher/directory_tree_fetcher"
|
|
16
|
+
require_relative "file_fetcher/downloader_config_fetcher"
|
|
17
|
+
|
|
12
18
|
WORKSPACE_FILES = T.let(%w(WORKSPACE WORKSPACE.bazel).freeze, T::Array[String])
|
|
13
19
|
MODULE_FILE = T.let("MODULE.bazel", String)
|
|
14
20
|
CONFIG_FILES = T.let(
|
|
15
21
|
%w(.bazelrc MODULE.bazel.lock .bazelversion maven_install.json BUILD BUILD.bazel).freeze, T::Array[String]
|
|
16
22
|
)
|
|
17
|
-
SKIP_DIRECTORIES = T.let(%w(.git .bazel-* bazel-* node_modules .github).freeze, T::Array[String])
|
|
18
23
|
|
|
19
24
|
sig { override.returns(String) }
|
|
20
25
|
def self.required_files_message
|
|
@@ -28,21 +33,12 @@ module Dependabot
|
|
|
28
33
|
|
|
29
34
|
sig { override.returns(T::Array[DependencyFile]) }
|
|
30
35
|
def fetch_files
|
|
31
|
-
unless allow_beta_ecosystems?
|
|
32
|
-
raise Dependabot::DependencyFileNotFound.new(
|
|
33
|
-
nil,
|
|
34
|
-
"Bazel support is currently in beta. To enable it, add `enable_beta_ecosystems: true` to the" \
|
|
35
|
-
" top-level of your `dependabot.yml`. See " \
|
|
36
|
-
"https://docs.github.com/en/code-security/dependabot/working-with-dependabot" \
|
|
37
|
-
"/dependabot-options-reference#enable-beta-ecosystems for details."
|
|
38
|
-
)
|
|
39
|
-
end
|
|
40
|
-
|
|
41
36
|
fetched_files = T.let([], T::Array[DependencyFile])
|
|
42
37
|
fetched_files += workspace_files
|
|
43
38
|
fetched_files += module_files
|
|
44
39
|
fetched_files += config_files
|
|
45
40
|
fetched_files += referenced_files_from_modules
|
|
41
|
+
fetched_files += downloader_config_files
|
|
46
42
|
|
|
47
43
|
return fetched_files if fetched_files.any?
|
|
48
44
|
|
|
@@ -128,86 +124,72 @@ module Dependabot
|
|
|
128
124
|
nil
|
|
129
125
|
end
|
|
130
126
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
SKIP_DIRECTORIES.any? { |skip_dir| dirname.start_with?(skip_dir) }
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
# Fetches files referenced in MODULE.bazel files via lock_file and requirements_lock attributes.
|
|
137
|
-
# Also fetches BUILD/BUILD.bazel files from directories containing referenced files, as these
|
|
138
|
-
# are required by Bazel to recognize the directories as valid packages.
|
|
139
|
-
#
|
|
140
|
-
# This method handles Bazel label syntax and converts it to filesystem paths:
|
|
141
|
-
# - "@repo//path:file.json" -> "path/file.json"
|
|
142
|
-
# - "//path:file.json" -> "path/file.json"
|
|
143
|
-
# - "@repo//:file.json" -> "file.json"
|
|
144
|
-
#
|
|
145
|
-
# @return [Array<DependencyFile>] referenced files and their associated BUILD files
|
|
127
|
+
# Fetches files referenced in MODULE.bazel and their associated BUILD files.
|
|
128
|
+
# Bazel requires BUILD files to recognize directories as valid packages.
|
|
146
129
|
sig { returns(T::Array[DependencyFile]) }
|
|
147
130
|
def referenced_files_from_modules
|
|
148
131
|
files = T.let([], T::Array[DependencyFile])
|
|
149
132
|
directories_with_files = T.let(Set.new, T::Set[String])
|
|
133
|
+
local_override_directories = T.let(Set.new, T::Set[String])
|
|
134
|
+
tree_fetcher = DirectoryTreeFetcher.new(fetcher: self)
|
|
150
135
|
|
|
151
136
|
module_files.each do |module_file|
|
|
152
|
-
|
|
137
|
+
extractor = ModulePathExtractor.new(module_file: module_file)
|
|
138
|
+
file_paths, directory_paths = extractor.extract_paths
|
|
153
139
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
next unless fetched_file
|
|
140
|
+
bzl_fetcher = BzlFileFetcher.new(module_file: module_file, fetcher: self)
|
|
141
|
+
bzl_files = bzl_fetcher.fetch_bzl_files
|
|
157
142
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
# Exclude root directory (.) as BUILD files there are already handled by config_files.
|
|
161
|
-
dir = File.dirname(path)
|
|
143
|
+
bzl_files.each do |file|
|
|
144
|
+
dir = File.dirname(file.name)
|
|
162
145
|
directories_with_files.add(dir) unless dir == "."
|
|
163
146
|
end
|
|
164
|
-
end
|
|
165
147
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
files << build_file if build_file
|
|
148
|
+
files += bzl_files
|
|
149
|
+
files += fetch_paths_and_track_directories(file_paths, directories_with_files)
|
|
150
|
+
|
|
151
|
+
directory_paths.each { |dir| local_override_directories.add(dir) unless dir == "." }
|
|
171
152
|
end
|
|
172
153
|
|
|
154
|
+
files += tree_fetcher.fetch_build_files_for_directories(directories_with_files)
|
|
155
|
+
files += fetch_local_override_directory_trees(local_override_directories)
|
|
156
|
+
|
|
173
157
|
files
|
|
174
158
|
end
|
|
175
159
|
|
|
176
|
-
#
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
# 3. Removes leading slashes to create relative paths
|
|
189
|
-
#
|
|
190
|
-
# @param module_file [DependencyFile] the MODULE.bazel file to parse
|
|
191
|
-
# @return [Array<String>] unique relative file paths referenced in the module
|
|
192
|
-
sig { params(module_file: DependencyFile).returns(T::Array[String]) }
|
|
193
|
-
def extract_referenced_paths(module_file)
|
|
194
|
-
content = T.must(module_file.content)
|
|
195
|
-
paths = []
|
|
196
|
-
|
|
197
|
-
# Match lock_file attributes with optional @repo prefix: "(?:@[^"\/]+)?\/\/([^"]+)"
|
|
198
|
-
# Capture group 1: everything after // (e.g., "tools/jol:file.json" or ":file.json")
|
|
199
|
-
content.scan(%r{lock_file\s*=\s*"(?:@[^"/]+)?//([^"]+)"}) do |match|
|
|
200
|
-
path = match[0].tr(":", "/").sub(%r{^/}, "")
|
|
201
|
-
paths << path
|
|
202
|
-
end
|
|
160
|
+
# Fetches files and tracks their directories for BUILD file resolution.
|
|
161
|
+
sig do
|
|
162
|
+
params(
|
|
163
|
+
paths: T::Array[String],
|
|
164
|
+
directories: T::Set[String]
|
|
165
|
+
).returns(T::Array[DependencyFile])
|
|
166
|
+
end
|
|
167
|
+
def fetch_paths_and_track_directories(paths, directories)
|
|
168
|
+
files = T.let([], T::Array[DependencyFile])
|
|
169
|
+
paths.each do |path|
|
|
170
|
+
fetched_file = fetch_file_if_present(path)
|
|
171
|
+
next unless fetched_file
|
|
203
172
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
paths << path
|
|
173
|
+
files << fetched_file
|
|
174
|
+
dir = File.dirname(path)
|
|
175
|
+
directories.add(dir) unless dir == "."
|
|
208
176
|
end
|
|
177
|
+
files
|
|
178
|
+
end
|
|
209
179
|
|
|
210
|
-
|
|
180
|
+
# Fetches complete directory trees for local module overrides.
|
|
181
|
+
sig { params(directories: T::Set[String]).returns(T::Array[DependencyFile]) }
|
|
182
|
+
def fetch_local_override_directory_trees(directories)
|
|
183
|
+
tree_fetcher = DirectoryTreeFetcher.new(fetcher: self)
|
|
184
|
+
files = T.let([], T::Array[DependencyFile])
|
|
185
|
+
directories.each { |dir| files += tree_fetcher.fetch_directory_tree(dir) }
|
|
186
|
+
files
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
sig { returns(T::Array[DependencyFile]) }
|
|
190
|
+
def downloader_config_files
|
|
191
|
+
config_fetcher = DownloaderConfigFetcher.new(fetcher: self)
|
|
192
|
+
config_fetcher.fetch_downloader_config_files
|
|
211
193
|
end
|
|
212
194
|
end
|
|
213
195
|
end
|
|
@@ -169,8 +169,7 @@ module Dependabot
|
|
|
169
169
|
name = func_call.arguments["name"]
|
|
170
170
|
version = func_call.arguments["version"]
|
|
171
171
|
|
|
172
|
-
|
|
173
|
-
next unless name.is_a?(String) && version.is_a?(String)
|
|
172
|
+
next unless name.is_a?(String) && version.is_a?(String) && !name.empty? && !version.empty?
|
|
174
173
|
|
|
175
174
|
dependency_set << Dependabot::Dependency.new(
|
|
176
175
|
name: name,
|
|
@@ -9,13 +9,72 @@ module Dependabot
|
|
|
9
9
|
class Version < Dependabot::Version
|
|
10
10
|
extend T::Sig
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
sig { override.params(version: VersionParameter).void }
|
|
13
|
+
def initialize(version)
|
|
14
|
+
@original_version = T.let(version.to_s, String)
|
|
15
|
+
@bcr_suffix = T.let(parse_bcr_suffix(@original_version), T.nilable(Integer))
|
|
16
|
+
|
|
17
|
+
base_version = remove_bcr_suffix(@original_version)
|
|
18
|
+
super(base_version)
|
|
19
|
+
|
|
20
|
+
@original_version = version.to_s
|
|
21
|
+
end
|
|
22
|
+
|
|
15
23
|
sig { override.returns(String) }
|
|
16
24
|
def to_s
|
|
17
25
|
@original_version
|
|
18
26
|
end
|
|
27
|
+
|
|
28
|
+
sig { returns(T.nilable(Integer)) }
|
|
29
|
+
attr_reader :bcr_suffix
|
|
30
|
+
|
|
31
|
+
sig { override.params(other: T.untyped).returns(T.nilable(Integer)) }
|
|
32
|
+
def <=>(other)
|
|
33
|
+
other_bazel = convert_to_bazel_version(other)
|
|
34
|
+
return nil unless other_bazel
|
|
35
|
+
|
|
36
|
+
base_comparison = super(other_bazel)
|
|
37
|
+
return base_comparison unless base_comparison&.zero?
|
|
38
|
+
|
|
39
|
+
compare_bcr_suffixes(@bcr_suffix, other_bazel.bcr_suffix)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
sig { params(version_string: String).returns(T.nilable(Integer)) }
|
|
45
|
+
def parse_bcr_suffix(version_string)
|
|
46
|
+
match = version_string.match(/\.bcr\.(\d+)$/)
|
|
47
|
+
match ? T.must(match[1]).to_i : nil
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
sig { params(version_string: String).returns(String) }
|
|
51
|
+
def remove_bcr_suffix(version_string)
|
|
52
|
+
version_string.sub(/\.bcr\.\d+$/, "")
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
sig { params(other: T.untyped).returns(T.nilable(Dependabot::Bazel::Version)) }
|
|
56
|
+
def convert_to_bazel_version(other)
|
|
57
|
+
case other
|
|
58
|
+
when Dependabot::Bazel::Version
|
|
59
|
+
other
|
|
60
|
+
when Gem::Version
|
|
61
|
+
T.cast(Dependabot::Bazel::Version.new(other.to_s), Dependabot::Bazel::Version)
|
|
62
|
+
when String
|
|
63
|
+
T.cast(Dependabot::Bazel::Version.new(other), Dependabot::Bazel::Version)
|
|
64
|
+
when Dependabot::Version
|
|
65
|
+
T.cast(Dependabot::Bazel::Version.new(other.to_s), Dependabot::Bazel::Version)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
sig { params(ours: T.nilable(Integer), theirs: T.nilable(Integer)).returns(Integer) }
|
|
70
|
+
def compare_bcr_suffixes(ours, theirs)
|
|
71
|
+
return ours <=> theirs if ours && theirs
|
|
72
|
+
|
|
73
|
+
return 1 if ours
|
|
74
|
+
return -1 if theirs
|
|
75
|
+
|
|
76
|
+
0
|
|
77
|
+
end
|
|
19
78
|
end
|
|
20
79
|
end
|
|
21
80
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dependabot-bazel
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.350.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dependabot
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - '='
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.350.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - '='
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.
|
|
25
|
+
version: 0.350.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: debug
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -243,6 +243,11 @@ extra_rdoc_files: []
|
|
|
243
243
|
files:
|
|
244
244
|
- lib/dependabot/bazel.rb
|
|
245
245
|
- lib/dependabot/bazel/file_fetcher.rb
|
|
246
|
+
- lib/dependabot/bazel/file_fetcher/bzl_file_fetcher.rb
|
|
247
|
+
- lib/dependabot/bazel/file_fetcher/directory_tree_fetcher.rb
|
|
248
|
+
- lib/dependabot/bazel/file_fetcher/downloader_config_fetcher.rb
|
|
249
|
+
- lib/dependabot/bazel/file_fetcher/module_path_extractor.rb
|
|
250
|
+
- lib/dependabot/bazel/file_fetcher/path_converter.rb
|
|
246
251
|
- lib/dependabot/bazel/file_parser.rb
|
|
247
252
|
- lib/dependabot/bazel/file_parser/starlark_parser.rb
|
|
248
253
|
- lib/dependabot/bazel/file_updater.rb
|
|
@@ -263,7 +268,7 @@ licenses:
|
|
|
263
268
|
- MIT
|
|
264
269
|
metadata:
|
|
265
270
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
|
266
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
|
271
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.350.0
|
|
267
272
|
rdoc_options: []
|
|
268
273
|
require_paths:
|
|
269
274
|
- lib
|