Skip to content

Bazel: bazel_dep versions held in a constant are neither parsed nor updated #16802

Open

Description

@CHervaudBetclic

Is there an existing issue for this?

  • I have searched the existing issues

Package ecosystem

bazel

Package manager version

Bazel 9.2.0

Language version

No response

Manifest location and content before the Dependabot update

/MODULE.bazel
module(name = "example")

RULES_KOTLIN_VERSION = "2.4.20"

bazel_dep(name = "rules_kotlin", version = RULES_KOTLIN_VERSION)

dependabot.yml content

version: 2
updates:
  - package-ecosystem: "bazel"
    directory: "/"
    schedule:
      interval: "weekly"

Updated dependency

rules_kotlin, from 2.4.20 to the latest release

What you expected to see, versus what you actually saw

Expected

Dependabot resolves RULES_KOTLIN_VERSION to "2.4.20" and opens a PR that bumps the constant's value. Holding versions in top-level constants is common in MODULE.bazel: the file can't load() a .bzl file, so a version shared by several bazel_deps or by a maven.install artifact has to live in a constant.

Actual

  1. parse_value returns a bare identifier's name, so the version is read as the string "RULES_KOTLIN_VERSION":
    def parse_value
    skip_whitespace_and_comments
    case current_char
    when '"', "'"
    parse_string
    when /[0-9]/
    parse_number
    when "["
    parse_array
    when /[a-zA-Z_]/
    identifier = parse_identifier
    case identifier
    when "True"
    true
    when "False"
    false
    when "None"
    nil
    else
    identifier
  2. That string passes the is_a?(String) check, so the dependency is recorded with a version that isn't a version:
    next unless name.is_a?(String) && version.is_a?(String) && !name.empty? && !version.empty?
  3. update_bazel_dep_version only rewrites a quoted literal (version\s*=\s*["'][^"']*["']), so version = RULES_KOTLIN_VERSION can never be updated:
    def update_bazel_dep_version(content, dependency)
    new_version = dependency.version
    return content unless new_version
    escaped_name = Regexp.escape(dependency.name)
    bazel_dep_pattern = /bazel_dep\s*\(([^)]+?)\)/mx
    content.gsub(bazel_dep_pattern) do |match|
    function_content = T.must(Regexp.last_match(1))
    if /name\s*=\s*["']#{escaped_name}["']/.match?(function_content)
    updated_function_content = function_content.gsub(
    /version\s*=\s*["'][^"']*["']/,
    "version = \"#{new_version}\""
    )
    "bazel_dep(#{updated_function_content})"
    else
    match
    end

Possible fix

When version is an identifier, resolve it from a top-level IDENT = "x.y.z" assignment in the same file, and rewrite that assignment instead of the bazel_dep.

Native package manager behavior

Bazel evaluates the constant: bazel mod graph resolves rules_kotlin@2.4.20.

Images of the diff or a link to the PR, issue, or logs

No response

Smallest manifest that reproduces the issue

/MODULE.bazel
module(name = "example")

RULES_KOTLIN_VERSION = "2.4.20"

bazel_dep(name = "rules_kotlin", version = RULES_KOTLIN_VERSION)

Metadata

Metadata

Labels

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions