| #!/usr/bin/env bash | |
| # Copyright 2026 The Bazel Authors. All rights reserved. | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| set -euo pipefail | |
| # --- begin runfiles.bash initialization v3 --- | |
| # Copy-pasted from the Bazel Bash runfiles library v3. | |
| set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash | |
| source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ | |
| source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ | |
| source "$0.runfiles/$f" 2>/dev/null || \ | |
| source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ | |
| source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ | |
| { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e | |
| # --- end runfiles.bash initialization v3 --- | |
| function die() { | |
| echo "$@" >&2 | |
| exit 1 | |
| } | |
| # In downstream pipelines, Bazel is built at HEAD and MODULE.bazel.lock is updated | |
| # for Bazel@HEAD, which will not match the Bazel version in .bazelversion. | |
| if [[ -n "${UPDATE_BAZEL_LOCK_FILE:-}" || "${BUILDKITE_PIPELINE_SLUG:-}" == "bazel-at-head-plus-downstream" ]]; then | |
| echo "Skipping MODULE.bazel.lock verification in downstream pipeline." | |
| exit 0 | |
| fi | |
| # Verifies that Bazel's own MODULE.bazel.lock is up-to-date, i.e., that running | |
| # `bazel mod deps --lockfile_mode=update` in the workspace would not modify it. | |
| # | |
| # `--lockfile_mode=error` on CI only reports lockfile information that is | |
| # missing or outdated, but tolerates extra information such as entries for | |
| # registry files, yanked versions or module extensions that are no longer | |
| # referenced after a change to MODULE.bazel (this tolerance is intentional, | |
| # e.g. to keep automated git merges of lockfiles working). Such leftovers are | |
| # only cleaned up by an update, which makes local builds dirty the tree. This | |
| # test replays module resolution against the checked-in lockfile and fails if | |
| # an update would modify the file. | |
| # The lockfile is maintained by the Bazel version in .bazelversion, which | |
| # developers and CI use via bazelisk and which resolves modules slightly | |
| # differently than a Bazel built at HEAD, e.g. due to the bazel_dep versions in | |
| # its embedded MODULE.tools. Download and run exactly that version. | |
| bazel_version="$(tr -d '[:space:]' < "$(rlocation io_bazel/.bazelversion)")" | |
| case "$(uname -s)" in | |
| Linux) os=linux ;; | |
| Darwin) os=darwin ;; | |
| MSYS*|MINGW*|CYGWIN*) os=windows ;; | |
| *) die "Unsupported operating system: $(uname -s)" ;; | |
| esac | |
| case "$(uname -m)" in | |
| x86_64|amd64) arch=x86_64 ;; | |
| arm64|aarch64) arch=arm64 ;; | |
| *) die "Unsupported architecture: $(uname -m)" ;; | |
| esac | |
| suffix="" | |
| if [[ "$os" == "windows" ]]; then | |
| suffix=".exe" | |
| fi | |
| url="https://releases.bazel.build/${bazel_version}/release/bazel-${bazel_version}-${os}-${arch}${suffix}" | |
| bazel="$TEST_TMPDIR/bazel${suffix}" | |
| echo "Downloading $url" | |
| curl -fsSL -o "$bazel" "$url" || die "Failed to download Bazel $bazel_version from $url." | |
| chmod +x "$bazel" | |
| # Set up a workspace that contains everything that module resolution (but not | |
| # module extension evaluation, which requires fetching repos) needs: the root | |
| # module file, the current lockfile, and the files referenced by the overrides | |
| # in MODULE.bazel. This mirrors the workspace set up by the | |
| # //:generate_dist_lockfile genrule. | |
| checked_in_lockfile="$(rlocation io_bazel/MODULE.bazel.lock)" | |
| mkdir -p "$TEST_TMPDIR/workspace" | |
| cd "$TEST_TMPDIR/workspace" | |
| touch BUILD.bazel | |
| cp "$(rlocation io_bazel/MODULE.bazel)" MODULE.bazel | |
| cp "$checked_in_lockfile" MODULE.bazel.lock | |
| chmod u+w MODULE.bazel MODULE.bazel.lock | |
| # Patches referenced by overrides in MODULE.bazel are read during module | |
| # resolution and thus have to exist in the workspace. | |
| for label in $(grep -o '"//[^"]*\.patch"' MODULE.bazel | tr -d '"' | sort -u); do | |
| patch_path="${label#//}" | |
| patch_path="${patch_path/://}" | |
| mkdir -p "$(dirname "$patch_path")" | |
| cp "$(rlocation "io_bazel/$patch_path")" "$patch_path" \ | |
| || die "Patch file $label referenced by an override in MODULE.bazel is not available to this test. Please add it to the data of //:verify_module_bazel_lock in BUILD." | |
| # The package containing a patch has to exist for its label to resolve, but | |
| # its BUILD file is never loaded. | |
| touch "$(dirname "$patch_path")/BUILD" | |
| done | |
| # MODULE.bazel files of modules with a local_path_override are read during | |
| # module resolution. If this list is incomplete, the bazel invocation below | |
| # fails with a clear error message. | |
| mkdir -p third_party/remoteapis | |
| cp "$(rlocation io_bazel/third_party/remoteapis/MODULE.bazel)" \ | |
| third_party/remoteapis/MODULE.bazel | |
| # `bazel query :all` triggers module resolution, but no extension evaluation, | |
| # and in update mode rewrites MODULE.bazel.lock if and only if its contents | |
| # are no longer up-to-date. | |
| echo "Running: bazel query --lockfile_mode=update to verify the lockfile." | |
| "$bazel" --batch --ignore_all_rc_files \ | |
| --host_jvm_args=-Djava.net.preferIPv6Addresses=system \ | |
| --output_user_root="$TEST_TMPDIR/output_user_root" \ | |
| query --check_direct_dependencies=error --lockfile_mode=update :all \ | |
| || die "Module resolution failed. If the error above mentions a file that does not exist in this test's workspace, please add it to the data of //:verify_module_bazel_lock in BUILD and copy it into place above." | |
| diff -u "$checked_in_lockfile" MODULE.bazel.lock \ | |
| || die "MODULE.bazel.lock is not up-to-date (see the diff above; '-' lines are checked in, '+' lines are what Bazel would generate). Please run \"bazel mod deps --lockfile_mode=update\" in your workspace and commit the resulting changes. This typically happens when MODULE.bazel is changed without updating the lockfile." | |
| echo "PASS" |