blob: f8a60b3bbfcc728bf0df616192a51921018cbe2f [file]
#!/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
}
# 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 \
--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"