| # Copyright 2025 The Pigweed Authors |
| # |
| # 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 |
| # |
| # https://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. |
| """Recipe module for updating MODULE.bazel.lock files.""" |
| |
| from __future__ import annotations |
| |
| from collections.abc import Sequence |
| from typing import TYPE_CHECKING |
| |
| from recipe_engine import recipe_api |
| |
| from RECIPE_MODULES.fuchsia.git_roll_util import api as git_roll_util_api |
| |
| if TYPE_CHECKING: # pragma: no cover |
| from RECIPE_MODULES.pigweed.checkout import api as checkout_api |
| |
| from PB.recipe_modules.pigweed.bazel.options import Options as BazelOptions |
| from PB.recipe_modules.pigweed.module_bazel_lock_roll.module_bazel_lock import ( |
| ModuleBazelLock, |
| ) |
| |
| from RECIPE_MODULES.fuchsia.roll_commit_message import api as rcm_api |
| |
| |
| class Roll(rcm_api.BaseRoll): |
| def __init__(self, name: str, *args, **kwargs): |
| super().__init__(*args, **kwargs) |
| self._name = name |
| |
| def short_name(self) -> str: |
| return self._name |
| |
| def message_header(self, force_summary_version: bool = False) -> str: |
| del force_summary_version # Unused. |
| return self.short_name() |
| |
| def message_body( |
| self, |
| *, |
| force_summary_version: bool = False, |
| escape_tags: Sequence[str] | None = None, |
| filter_tags: Sequence[str] | None = None, |
| ) -> str: |
| del force_summary_version # Unused. |
| del escape_tags # Unused. |
| del filter_tags # Unused. |
| return f'Regenerated {self.short_name()}' |
| |
| def message_footer(self, *, send_comment: bool) -> str: # pragma: no cover |
| del send_comment # Unused. |
| return '' |
| |
| def output_property(self) -> dict[str, str]: |
| return {'name': self._name} |
| |
| |
| class ModuleBazelLockRollApi(recipe_api.RecipeApi): |
| """Recipe module for updating MODULE.bazel.lock files.""" |
| |
| def update( |
| self, |
| checkout: checkout_api.CheckoutContext, |
| module_bazel_lock: ModuleBazelLock, |
| ) -> list[git_roll_util_api.Roll]: |
| """Updates the MODULE.bazel.lock file if it exists. |
| |
| If a `MODULE.bazel.lock` file is present at the root of the checkout, |
| this method runs `bazelisk mod deps --lockfile_mode=update` to |
| regenerate it based on the current `MODULE.bazel` file. |
| |
| Args: |
| checkout: The checkout context. |
| module_bazel_lock: Lockfile update options. |
| """ |
| directory = checkout.root |
| if module_bazel_lock.subdirectory: |
| directory /= module_bazel_lock.subdirectory |
| |
| name = 'MODULE.bazel.lock' |
| lock = directory / name |
| self.m.path.mock_add_file(lock) |
| if not self.m.path.isfile(lock): |
| return [] # pragma: no cover |
| |
| with self.m.step.nest(name): |
| runner = self.m.bazel.new_runner( |
| checkout=checkout, |
| options=BazelOptions(), |
| ) |
| |
| with self.m.context(cwd=directory): |
| bazel = module_bazel_lock.bazel_executable |
| if not bazel: |
| bazel = runner.ensure_bazelisk() |
| bazel_name = self.m.path.basename(bazel) |
| |
| self.m.step( |
| f'{bazel_name} mod deps --lockfile_mode=update', |
| [ |
| bazel, |
| 'mod', |
| 'deps', |
| '--lockfile_mode=update', |
| ], |
| ) |
| |
| diff = self.m.git.diff(lock, exit_code=True, ok_ret=(0, 1)) |
| if diff.exc_result.retcode: |
| return [Roll(name)] |
| return [] |