dependabot-bazel 0.346.0 → 0.347.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e57f47a06cc01ad92b9511e1e880ae7e4f2478976029ccf1047e718611f2a5e1
4
- data.tar.gz: 4ae6c02d405ed3fcc3fbb22f0778d129520aadc60dffb56966fa79d682d47154
3
+ metadata.gz: 9852686dc5127e74b39132b06f0f0842c87072db3c49cdf6967c497f18188c0c
4
+ data.tar.gz: fb12ceb562835906b5b0c49240fc9f8e2e89c58b66b600795cfc25f4546cb12a
5
5
  SHA512:
6
- metadata.gz: 2acd0ca2a0ace5fd91eef6edb4bfee26e6aca2e08f9fa1930102ba2d6a1a05b8ca91fe2fc367404d1c31a1d1cfc9600b19b59a78a3230fda02ee52577d064fc1
7
- data.tar.gz: e9dad0b0b6985566c9c140dcbcc0f2ac338cebc2800821a0110502b660c27d7c82dd7a1b5269385300bf82dfe8bad12703c28eee3178536d6c8ce944ff897e9d
6
+ metadata.gz: 8a38a1c7af4b2d3f2e9eb85dd108cb7a516c2d623d7e3c4ee28908149a99d18c8f7cf0f814ddd9fdfe897469aa453b12a2e33c53633d4af74db23d2c7799ea05
7
+ data.tar.gz: 9d5dbe0e680f1be8ce7c3debdc133c95c30ea0ba9899f4b2fffe65cdf7da3100489ebe39138823f482e77a3b7e0730c666b95092f93fa108314c6ef60616232b
@@ -1,4 +1,4 @@
1
- # typed: strong
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "dependabot/file_fetchers"
@@ -10,8 +10,10 @@ module Dependabot
10
10
  extend T::Sig
11
11
 
12
12
  WORKSPACE_FILES = T.let(%w(WORKSPACE WORKSPACE.bazel).freeze, T::Array[String])
13
- MODULE_FILES = T.let(%w(MODULE.bazel).freeze, T::Array[String])
14
- CONFIG_FILES = T.let(%w(.bazelrc MODULE.bazel.lock .bazelversion maven_install.json).freeze, T::Array[String])
13
+ MODULE_FILE = T.let("MODULE.bazel", String)
14
+ CONFIG_FILES = T.let(
15
+ %w(.bazelrc MODULE.bazel.lock .bazelversion maven_install.json BUILD BUILD.bazel).freeze, T::Array[String]
16
+ )
15
17
  SKIP_DIRECTORIES = T.let(%w(.git .bazel-* bazel-* node_modules .github).freeze, T::Array[String])
16
18
 
17
19
  sig { override.returns(String) }
@@ -21,7 +23,7 @@ module Dependabot
21
23
 
22
24
  sig { override.params(filenames: T::Array[String]).returns(T::Boolean) }
23
25
  def self.required_files_in?(filenames)
24
- filenames.any? { |name| WORKSPACE_FILES.include?(name) || MODULE_FILES.include?(name) }
26
+ filenames.any? { |name| WORKSPACE_FILES.include?(name) || name.end_with?(MODULE_FILE) }
25
27
  end
26
28
 
27
29
  sig { override.returns(T::Array[DependencyFile]) }
@@ -40,6 +42,7 @@ module Dependabot
40
42
  fetched_files += workspace_files
41
43
  fetched_files += module_files
42
44
  fetched_files += config_files
45
+ fetched_files += referenced_files_from_modules
43
46
 
44
47
  return fetched_files if fetched_files.any?
45
48
 
@@ -74,30 +77,138 @@ module Dependabot
74
77
  def module_files
75
78
  files = T.let([], T::Array[DependencyFile])
76
79
 
77
- MODULE_FILES.each do |filename|
78
- file = fetch_file_if_present(filename)
80
+ module_file_items.each do |item|
81
+ file = fetch_file_if_present(item.name)
79
82
  files << file if file
80
83
  end
81
84
 
82
85
  files
83
86
  end
84
87
 
88
+ sig { returns(T::Array[T.untyped]) }
89
+ def module_file_items
90
+ repo_contents(raise_errors: false).select { |f| f.type == "file" && f.name.end_with?(MODULE_FILE) }
91
+ end
92
+
85
93
  sig { returns(T::Array[DependencyFile]) }
86
94
  def config_files
87
95
  files = T.let([], T::Array[DependencyFile])
88
96
 
89
97
  CONFIG_FILES.map do |filename|
90
- file = fetch_file_if_present(filename)
98
+ file = if filename == ".bazelversion"
99
+ fetch_bazelversion_file
100
+ else
101
+ fetch_file_if_present(filename)
102
+ end
91
103
  files << file if file
92
104
  end
93
105
 
94
106
  files
95
107
  end
96
108
 
109
+ sig { returns(T.nilable(DependencyFile)) }
110
+ def fetch_bazelversion_file
111
+ file = fetch_file_if_present(".bazelversion")
112
+ return file if file
113
+ return if [".", "/"].include?(directory)
114
+
115
+ fetch_file_from_parent_directories(".bazelversion")
116
+ end
117
+
118
+ sig { params(filename: String).returns(T.nilable(DependencyFile)) }
119
+ def fetch_file_from_parent_directories(filename)
120
+ (1..directory.split("/").count).each do |i|
121
+ candidate_path = ("../" * i) + filename
122
+ file = fetch_file_if_present(candidate_path)
123
+ if file
124
+ file.name = filename
125
+ return file
126
+ end
127
+ end
128
+ nil
129
+ end
130
+
97
131
  sig { params(dirname: String).returns(T::Boolean) }
98
132
  def should_skip_directory?(dirname)
99
133
  SKIP_DIRECTORIES.any? { |skip_dir| dirname.start_with?(skip_dir) }
100
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
146
+ sig { returns(T::Array[DependencyFile]) }
147
+ def referenced_files_from_modules
148
+ files = T.let([], T::Array[DependencyFile])
149
+ directories_with_files = T.let(Set.new, T::Set[String])
150
+
151
+ module_files.each do |module_file|
152
+ referenced_paths = extract_referenced_paths(module_file)
153
+
154
+ referenced_paths.each do |path|
155
+ fetched_file = fetch_file_if_present(path)
156
+ next unless fetched_file
157
+
158
+ files << fetched_file
159
+ # Track directories that contain referenced files so we can fetch their BUILD files.
160
+ # Exclude root directory (.) as BUILD files there are already handled by config_files.
161
+ dir = File.dirname(path)
162
+ directories_with_files.add(dir) unless dir == "."
163
+ end
164
+ end
165
+
166
+ # Fetch BUILD or BUILD.bazel files for directories that contain referenced files.
167
+ # These BUILD files are required for Bazel to recognize directories as valid packages.
168
+ directories_with_files.each do |dir|
169
+ build_file = fetch_file_if_present("#{dir}/BUILD") || fetch_file_if_present("#{dir}/BUILD.bazel")
170
+ files << build_file if build_file
171
+ end
172
+
173
+ files
174
+ end
175
+
176
+ # Extracts file paths from lock_file and requirements_lock attributes in MODULE.bazel content.
177
+ # Converts Bazel label syntax to filesystem paths.
178
+ #
179
+ # Bazel labels can have several formats:
180
+ # - "@repo//path:file" - external or self-referential repository with path
181
+ # - "//path:file" - main repository reference with path
182
+ # - "@repo//:file" - external or self-referential repository root file
183
+ # - "//:file" - main repository root file
184
+ #
185
+ # The method:
186
+ # 1. Strips optional @repo prefix
187
+ # 2. Converts colon separators to forward slashes (path:file -> path/file)
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
203
+
204
+ # Match requirements_lock attributes with optional @repo prefix
205
+ content.scan(%r{requirements_lock\s*=\s*"(?:@[^"/]+)?//([^"]+)"}) do |match|
206
+ path = match[0].tr(":", "/").sub(%r{^/}, "")
207
+ paths << path
208
+ end
209
+
210
+ paths.uniq
211
+ end
101
212
  end
102
213
  end
103
214
  end
@@ -222,6 +222,7 @@ module Dependabot
222
222
  name = func_call.arguments["name"]
223
223
  tag = func_call.arguments["tag"]
224
224
  commit = func_call.arguments["commit"]
225
+ remote = func_call.arguments["remote"]
225
226
 
226
227
  return nil unless name.is_a?(String)
227
228
 
@@ -236,7 +237,7 @@ module Dependabot
236
237
  file: file.name,
237
238
  requirement: version,
238
239
  groups: [],
239
- source: { type: "git_repository", tag: tag, commit: commit }
240
+ source: { type: "git_repository", tag: tag, commit: commit, remote: remote }
240
241
  }
241
242
  ],
242
243
  package_manager: "bazel"
@@ -10,6 +10,8 @@ module Dependabot
10
10
  class BzlmodFileUpdater
11
11
  extend T::Sig
12
12
 
13
+ require_relative "lockfile_updater"
14
+
13
15
  sig do
14
16
  params(
15
17
  dependency_files: T::Array[Dependabot::DependencyFile],
@@ -25,12 +27,27 @@ module Dependabot
25
27
 
26
28
  sig { returns(T::Array[Dependabot::DependencyFile]) }
27
29
  def updated_module_files
28
- module_files.filter_map do |file|
30
+ updated_files = T.let([], T::Array[Dependabot::DependencyFile])
31
+
32
+ module_files.each do |file|
29
33
  updated_content = update_file_content(file)
30
34
  next if updated_content == T.must(file.content)
31
35
 
32
- file.dup.tap { |f| f.content = updated_content }
36
+ updated_files << file.dup.tap { |f| f.content = updated_content }
37
+ end
38
+
39
+ if generate_lockfile?
40
+ lockfile_updater = LockfileUpdater.new(
41
+ dependency_files: dependency_files,
42
+ dependencies: dependencies,
43
+ credentials: credentials
44
+ )
45
+
46
+ updated_lockfile = lockfile_updater.updated_lockfile
47
+ updated_files << updated_lockfile if updated_lockfile
33
48
  end
49
+
50
+ updated_files
34
51
  end
35
52
 
36
53
  private
@@ -52,6 +69,11 @@ module Dependabot
52
69
  )
53
70
  end
54
71
 
72
+ sig { returns(T::Boolean) }
73
+ def generate_lockfile?
74
+ dependency_files.any? { |f| f.name.end_with?("MODULE.bazel.lock") }
75
+ end
76
+
55
77
  sig { params(file: Dependabot::DependencyFile).returns(String) }
56
78
  def update_file_content(file)
57
79
  content = T.must(file.content).dup
@@ -0,0 +1,239 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+ require "dependabot/bazel/file_updater"
6
+ require "dependabot/shared_helpers"
7
+ require "pathname"
8
+ require "fileutils"
9
+
10
+ module Dependabot
11
+ module Bazel
12
+ class FileUpdater < Dependabot::FileUpdaters::Base
13
+ class LockfileUpdater
14
+ extend T::Sig
15
+
16
+ DEFAULT_BAZEL_VERSION = "8.4.2"
17
+
18
+ sig do
19
+ params(
20
+ dependency_files: T::Array[Dependabot::DependencyFile],
21
+ dependencies: T::Array[Dependabot::Dependency],
22
+ credentials: T::Array[Dependabot::Credential]
23
+ ).void
24
+ end
25
+ def initialize(dependency_files:, dependencies:, credentials:)
26
+ @dependency_files = dependency_files
27
+ @dependencies = dependencies
28
+ @credentials = credentials
29
+ end
30
+
31
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
32
+ def updated_lockfile
33
+ return nil unless needs_lockfile_update?
34
+
35
+ existing_lockfile = lockfile
36
+ updated_content = generate_lockfile_content
37
+
38
+ if existing_lockfile
39
+ return nil if existing_lockfile.content == updated_content
40
+
41
+ existing_lockfile.dup.tap { |f| f.content = updated_content }
42
+ else
43
+ Dependabot::DependencyFile.new(
44
+ name: "MODULE.bazel.lock",
45
+ content: updated_content,
46
+ directory: module_file.directory
47
+ )
48
+ end
49
+ rescue SharedHelpers::HelperSubprocessFailed => e
50
+ handle_bazel_error_for_lockfile(e)
51
+ end
52
+
53
+ sig { returns(String) }
54
+ def determine_bazel_version
55
+ bazelversion_file = dependency_files.find { |f| f.name == ".bazelversion" }
56
+ return DEFAULT_BAZEL_VERSION unless bazelversion_file
57
+
58
+ version = T.must(bazelversion_file.content).strip
59
+ version.empty? ? DEFAULT_BAZEL_VERSION : version
60
+ end
61
+
62
+ private
63
+
64
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
65
+ attr_reader :dependency_files
66
+
67
+ sig { returns(T::Array[Dependabot::Dependency]) }
68
+ attr_reader :dependencies
69
+
70
+ sig { returns(T::Array[Dependabot::Credential]) }
71
+ attr_reader :credentials
72
+
73
+ sig { returns(T::Boolean) }
74
+ def needs_lockfile_update?
75
+ return false unless module_file?
76
+
77
+ dependencies.any? { |dep| bzlmod_dependency?(dep) }
78
+ end
79
+
80
+ sig { returns(T::Boolean) }
81
+ def module_file?
82
+ module_files.any?
83
+ end
84
+
85
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
86
+ def module_files
87
+ @module_files ||= T.let(
88
+ dependency_files.select { |f| f.name.end_with?("MODULE.bazel") },
89
+ T.nilable(T::Array[Dependabot::DependencyFile])
90
+ )
91
+ end
92
+
93
+ sig { returns(Dependabot::DependencyFile) }
94
+ def module_file
95
+ T.must(module_files.first)
96
+ end
97
+
98
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
99
+ def lockfile
100
+ @lockfile ||= T.let(
101
+ dependency_files.find { |f| f.name == "MODULE.bazel.lock" },
102
+ T.nilable(Dependabot::DependencyFile)
103
+ )
104
+ end
105
+
106
+ sig { params(dependency: Dependabot::Dependency).returns(T::Boolean) }
107
+ def bzlmod_dependency?(dependency)
108
+ dependency.requirements.any? { |req| req[:file]&.end_with?("MODULE.bazel") }
109
+ end
110
+
111
+ sig { returns(String) }
112
+ def generate_lockfile_content
113
+ base_directory = module_file.directory
114
+
115
+ SharedHelpers.in_a_temporary_repo_directory(base_directory, repo_contents_path) do
116
+ write_temporary_dependency_files
117
+
118
+ File.write(module_file.name, updated_module_content)
119
+
120
+ run_bazel_mod_tidy_command
121
+
122
+ File.read("MODULE.bazel.lock")
123
+ end
124
+ end
125
+
126
+ sig { returns(String) }
127
+ def updated_module_content
128
+ bzlmod_updater = BzlmodFileUpdater.new(
129
+ dependency_files: dependency_files,
130
+ dependencies: dependencies,
131
+ credentials: credentials
132
+ )
133
+
134
+ bzlmod_updater.send(:update_file_content, module_file)
135
+ end
136
+
137
+ sig { returns(T.nilable(String)) }
138
+ def repo_contents_path
139
+ # For now, return nil. This can be enhanced later if needed.
140
+ nil
141
+ end
142
+
143
+ sig { void }
144
+ def write_temporary_dependency_files
145
+ dependency_files.each do |file|
146
+ path = file.name
147
+ FileUtils.mkdir_p(Pathname.new(path).dirname) if path.include?("/")
148
+ File.write(path, T.must(file.content))
149
+ end
150
+
151
+ write_bazelversion_if_missing
152
+ end
153
+
154
+ sig { void }
155
+ def write_bazelversion_if_missing
156
+ return if dependency_files.any? { |f| f.name == ".bazelversion" }
157
+
158
+ bazel_version = determine_bazel_version
159
+ File.write(".bazelversion", bazel_version)
160
+ Dependabot.logger.info("Using Bazel version: #{bazel_version}")
161
+ end
162
+
163
+ sig { void }
164
+ def run_bazel_mod_tidy_command
165
+ bazel_command = bazelisk_available? ? "bazelisk" : "bazel"
166
+
167
+ SharedHelpers.run_shell_command(
168
+ "#{bazel_command} mod tidy --lockfile_mode=update",
169
+ fingerprint: "#{bazel_command} mod tidy --lockfile_mode=update"
170
+ )
171
+
172
+ return if File.exist?("MODULE.bazel.lock")
173
+
174
+ raise SharedHelpers::HelperSubprocessFailed.new(
175
+ message: "MODULE.bazel.lock file was not generated",
176
+ error_context: {}
177
+ )
178
+ end
179
+
180
+ sig { returns(T::Boolean) }
181
+ def bazelisk_available?
182
+ !!system("which bazelisk > /dev/null 2>&1")
183
+ end
184
+
185
+ sig { params(error: SharedHelpers::HelperSubprocessFailed).returns(T.nilable(Dependabot::DependencyFile)) }
186
+ def handle_bazel_error_for_lockfile(error)
187
+ Dependabot.logger.warn("Bazel lockfile generation failed: #{error.message}")
188
+
189
+ case error.message
190
+ when /command not found/i, /bazel(isk)?\s*:\s*(command\s+)?not found/i
191
+ raise Dependabot::DependencyFileNotResolvable,
192
+ "Bazel binary not available. Cannot generate MODULE.bazel.lock file."
193
+ when /module.*not.*found/i, /registry.*not.*found/i
194
+ raise Dependabot::DependencyFileNotResolvable,
195
+ "Dependency not found in Bazel Central Registry."
196
+ when /network.*error/i, /timeout/i, /connection.*refused/i
197
+ raise Dependabot::DependencyFileNotResolvable,
198
+ "Network error during lockfile generation. Please try again later."
199
+ when /invalid.*syntax/i, /parse.*error/i
200
+ raise Dependabot::DependencyFileNotParseable,
201
+ "Invalid MODULE.bazel syntax prevents lockfile generation."
202
+ when /permission.*denied/i
203
+ raise Dependabot::DependencyFileNotResolvable,
204
+ "Permission error during lockfile generation."
205
+ else
206
+ raise Dependabot::DependencyFileNotResolvable,
207
+ "Error generating lockfile: #{error.message}"
208
+ end
209
+ end
210
+
211
+ sig { params(error: SharedHelpers::HelperSubprocessFailed).returns(String) }
212
+ def handle_bazel_error(error)
213
+ Dependabot.logger.warn("Bazel lockfile generation failed: #{error.message}")
214
+
215
+ case error.message
216
+ when /command not found/i, /bazel(isk)?\s*:\s*(command\s+)?not found/i
217
+ raise Dependabot::DependencyFileNotResolvable,
218
+ "Bazel binary not available. Cannot generate MODULE.bazel.lock file."
219
+ when /module.*not.*found/i, /registry.*not.*found/i
220
+ raise Dependabot::DependencyFileNotResolvable,
221
+ "Dependency not found in Bazel Central Registry."
222
+ when /network.*error/i, /timeout/i, /connection.*refused/i
223
+ raise Dependabot::DependencyFileNotResolvable,
224
+ "Network error during lockfile generation. Please try again later."
225
+ when /invalid.*syntax/i, /parse.*error/i
226
+ raise Dependabot::DependencyFileNotParseable,
227
+ "Invalid MODULE.bazel syntax prevents lockfile generation."
228
+ when /permission.*denied/i
229
+ raise Dependabot::DependencyFileNotResolvable,
230
+ "Permission error during lockfile generation."
231
+ else
232
+ raise Dependabot::DependencyFileNotResolvable,
233
+ "Error generating lockfile: #{error.message}"
234
+ end
235
+ end
236
+ end
237
+ end
238
+ end
239
+ end
@@ -17,7 +17,9 @@ module Dependabot
17
17
  def self.updated_files_regex
18
18
  [
19
19
  /^MODULE\.bazel$/,
20
- %r{^(?:.*/)?MODULE\.bazel$},
20
+ %r{^(?:.*/)?[^/]+\.MODULE\.bazel$},
21
+ /^MODULE\.bazel\.lock$/,
22
+ %r{^(?:.*/)?MODULE\.bazel\.lock$},
21
23
  /^WORKSPACE$/,
22
24
  %r{^(?:.*/)?WORKSPACE\.bazel$},
23
25
  %r{^(?:.*/)?BUILD$},
@@ -70,6 +72,19 @@ module Dependabot
70
72
  )
71
73
  end
72
74
 
75
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
76
+ def lockfile_files
77
+ @lockfile_files ||= T.let(
78
+ dependency_files.select { |f| f.name.end_with?("MODULE.bazel.lock") },
79
+ T.nilable(T::Array[Dependabot::DependencyFile])
80
+ )
81
+ end
82
+
83
+ sig { returns(T::Boolean) }
84
+ def requires_lockfile_update?
85
+ dependencies.any? { |dep| bzlmod_dependency?(dep) }
86
+ end
87
+
73
88
  sig { params(dependency: Dependabot::Dependency).returns(T::Boolean) }
74
89
  def bzlmod_dependency?(dependency)
75
90
  dependency.requirements.any? { |req| req[:file]&.end_with?("MODULE.bazel") }
@@ -1,10 +1,6 @@
1
- # typed: strong
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- # NOTE: This file was scaffolded automatically but is OPTIONAL.
5
- # If you don't need custom metadata finding logic (changelogs, release notes, etc.),
6
- # you can safely delete this file and remove the require from lib/dependabot/bazel.rb
7
-
8
4
  require "dependabot/metadata_finders"
9
5
  require "dependabot/metadata_finders/base"
10
6
 
@@ -13,14 +9,102 @@ module Dependabot
13
9
  class MetadataFinder < Dependabot::MetadataFinders::Base
14
10
  extend T::Sig
15
11
 
12
+ require_relative "update_checker/registry_client"
13
+
14
+ GITHUB_URL_PATTERNS = T.let(
15
+ [
16
+ %r{github\.com/([^/]+)/([^/]+)/archive},
17
+ %r{github\.com/([^/]+)/([^/]+)/releases},
18
+ %r{github\.com/([^/]+)/([^/]+)}
19
+ ].freeze,
20
+ T::Array[Regexp]
21
+ )
22
+
16
23
  private
17
24
 
18
25
  sig { override.returns(T.nilable(Dependabot::Source)) }
19
26
  def look_up_source
20
- # TODO: Implement custom source lookup logic if needed
21
- # Otherwise, delete this file and the require in the main registration file
27
+ case source_type
28
+ when :bazel_dep
29
+ find_source_from_bcr
30
+ when :http_archive
31
+ find_source_from_http_archive
32
+ when :git_repository
33
+ find_source_from_git_repository
34
+ when :unknown
35
+ nil
36
+ end
37
+ end
38
+
39
+ sig { returns(Symbol) }
40
+ def source_type
41
+ return :bazel_dep if dependency.requirements.empty?
42
+ return :bazel_dep if dependency.requirements.any? { |r| r[:source].nil? }
43
+
44
+ source_details = dependency.requirements.first&.dig(:source)
45
+ return :bazel_dep unless source_details
46
+
47
+ case source_details[:type]
48
+ when "http_archive" then :http_archive
49
+ when "git_repository" then :git_repository
50
+ else :unknown
51
+ end
52
+ end
53
+
54
+ sig { returns(T.nilable(Dependabot::Source)) }
55
+ def find_source_from_bcr
56
+ version = dependency.version
57
+ return nil unless version
58
+
59
+ source_info = registry_client.get_source(dependency.name, version)
60
+ url = source_info&.dig("url")
61
+ return nil unless url
62
+
63
+ source_from_url(url)
64
+ end
65
+
66
+ sig { returns(T.nilable(Dependabot::Source)) }
67
+ def find_source_from_http_archive
68
+ url = dependency.requirements.first&.dig(:source, :url)
69
+ return nil unless url
70
+
71
+ source_from_url(url)
72
+ end
73
+
74
+ sig { returns(T.nilable(Dependabot::Source)) }
75
+ def find_source_from_git_repository
76
+ remote_url = dependency.requirements.first&.dig(:source, :remote)
77
+ return nil unless remote_url
78
+
79
+ Dependabot::Source.from_url(remote_url)
80
+ end
81
+
82
+ sig { params(url: String).returns(T.nilable(Dependabot::Source)) }
83
+ def source_from_url(url)
84
+ extract_github_source_from_url(url) || Dependabot::Source.from_url(url)
85
+ end
86
+
87
+ sig { params(url: String).returns(T.nilable(Dependabot::Source)) }
88
+ def extract_github_source_from_url(url)
89
+ GITHUB_URL_PATTERNS.each do |pattern|
90
+ match = url.match(pattern)
91
+ next unless match
92
+
93
+ repo_url = "https://github.com/#{match[1]}/#{match[2]}"
94
+ source = Dependabot::Source.from_url(repo_url)
95
+ return source if source
96
+ end
97
+
22
98
  nil
23
99
  end
100
+
101
+ sig { returns(Dependabot::Bazel::UpdateChecker::RegistryClient) }
102
+ def registry_client
103
+ @registry_client ||= T.let(
104
+ Dependabot::Bazel::UpdateChecker::RegistryClient.new(credentials: credentials),
105
+ T.nilable(Dependabot::Bazel::UpdateChecker::RegistryClient)
106
+ )
107
+ end
24
108
  end
25
109
  end
26
110
  end
@@ -8,10 +8,11 @@ require "dependabot/shared_helpers"
8
8
  require "dependabot/clients/github_with_retries"
9
9
  require "dependabot/dependency"
10
10
  require "dependabot/errors"
11
+ require "dependabot/bazel/update_checker"
11
12
 
12
13
  module Dependabot
13
14
  module Bazel
14
- class UpdateChecker
15
+ class UpdateChecker < Dependabot::UpdateCheckers::Base
15
16
  class RegistryClient
16
17
  extend T::Sig
17
18
 
@@ -1,9 +1,11 @@
1
1
  # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "dependabot/bazel/update_checker"
5
+
4
6
  module Dependabot
5
7
  module Bazel
6
- class UpdateChecker
8
+ class UpdateChecker < Dependabot::UpdateCheckers::Base
7
9
  class RequirementsUpdater
8
10
  extend T::Sig
9
11
 
@@ -1,10 +1,6 @@
1
1
  # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
- # NOTE: This file was scaffolded automatically but is OPTIONAL.
5
- # If your ecosystem uses standard semantic versioning without special logic,
6
- # you can safely delete this file and remove the require from lib/dependabot/bazel.rb
7
-
8
4
  require "dependabot/version"
9
5
  require "dependabot/utils"
10
6
 
@@ -13,9 +9,13 @@ module Dependabot
13
9
  class Version < Dependabot::Version
14
10
  extend T::Sig
15
11
 
16
- # TODO: Implement custom version comparison logic if needed
17
- # Example: Handle pre-release versions, build metadata, etc.
18
- # If standard semantic versioning is sufficient, delete this file
12
+ # Bazel uses semantic versioning with hyphens for pre-release versions (e.g., "1.7.0-rc4")
13
+ # Dependabot::Version normalizes these to dot notation with "pre" prefix (e.g., "1.7.0.pre.rc4")
14
+ # We need to preserve the original format for Bazel Central Registry compatibility
15
+ sig { override.returns(String) }
16
+ def to_s
17
+ @original_version
18
+ end
19
19
  end
20
20
  end
21
21
  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.346.0
4
+ version: 0.347.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.346.0
18
+ version: 0.347.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.346.0
25
+ version: 0.347.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: debug
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -248,6 +248,7 @@ files:
248
248
  - lib/dependabot/bazel/file_updater.rb
249
249
  - lib/dependabot/bazel/file_updater/bzlmod_file_updater.rb
250
250
  - lib/dependabot/bazel/file_updater/declaration_parser.rb
251
+ - lib/dependabot/bazel/file_updater/lockfile_updater.rb
251
252
  - lib/dependabot/bazel/file_updater/workspace_file_updater.rb
252
253
  - lib/dependabot/bazel/language.rb
253
254
  - lib/dependabot/bazel/metadata_finder.rb
@@ -262,7 +263,7 @@ licenses:
262
263
  - MIT
263
264
  metadata:
264
265
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
265
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.346.0
266
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.347.0
266
267
  rdoc_options: []
267
268
  require_paths:
268
269
  - lib