Skip to content

Move helm_oci_manifest into a separate rules_helm_img module - #2

Draft
rdark wants to merge 1 commit into
richard/pla-2603-helm-deploy-multi-deployfrom
richard/pla-2603-helm-img-separate-module
Draft

rdark wants to merge 1 commit into
richard/pla-2603-helm-deploy-multi-deployfrom
richard/pla-2603-helm-img-separate-module

Conversation

@rdark

@rdark rdark commented Nov 10, 2026

Copy link
Copy Markdown
Owner

Stacked on periareon#305, so the diff is one commit. It shows the first of the three options in my reply to the review question on periareon#305 ("Is there a way to avoid this being a mandatory dependency?", comment). It is opened on the fork because the base branch is there.

Problem

Bazel has no optional bazel_dep, and a dev dependency is invisible to dependents. While helm/rules_img.bzl is in rules_helm, a consumer that never uses helm_oci_manifest still fetches rules_img (about 1.3 MB of source), hermetic_launcher (164 KB) and the img_toolchain hub repo (20 KB), and gets its module versions raised.

Change

helm_oci_manifest moves to modules/rules_helm_img, a second module in this repository. rules_helm keeps rules_img as a dev dependency only.

bazel_dep(name = "rules_helm", version = "...")
bazel_dep(name = "rules_helm_img", version = "...")  # only if you use helm_oci_manifest
load("@rules_helm_img//:defs.bzl", "helm_oci_manifest")
  • The new module reuses the rules_helm release archive with strip_prefix = "modules/rules_helm_img" and is listed in .bcr/config.yml as a second module root. Both modules have one version and are released from one tag.
  • It loads the private helm_oci_parts rule. HELM_OCI_PARTS_API in helm/private/oci_parts.bzl makes a rules_helm_img that runs against a rules_helm with a different interface fail with a clear message. bazel_dep versions are minimums, so nothing else detects that pairing.
  • Bazel does not skip a directory that has its own MODULE.bazel, so .bazelignore keeps the module out of //.... The root uses it through a dev dependency and local_path_override.
  • tests/bzl_version compares the module's version and its rules_helm dependency with version.bzl. A release that misses a bump now fails on the pull request. release_prep.sh checks the same values after the tag is pushed, as a backstop.
  • rules_helm_img_smoke_build_test builds the module's smoke target from the root. //... does not reach the module, and a missing bazel_dep(platforms) in it passed the root tests and failed a standalone build on Bazel 9.

Costs

  • A consumer who uses helm_oci_manifest adds a second bazel_dep, and the two versions have to match.
  • A release changes three files instead of two (version.bzl, MODULE.bazel, modules/rules_helm_img/MODULE.bazel). The test above checks them.
  • The module supports Bzlmod only, and there is a second module in the Bazel Central Registry to review.
  • The module depends on a private rules_helm rule. HELM_OCI_PARTS_API is the only guard, and whoever changes that rule's attributes or outputs has to raise it.
  • If this direction is chosen, the description of Add helm_oci_manifest so rules_img's multi_deploy can push a chart periareon/rules_helm#305 changes: rules_img is no longer a non-dev dependency there, and the "Dependency change" section goes.

Verification

On macOS, Bazel 9.x and 7.x:

  • bazel test //...: 69 pass, 3 skipped (the Linux-only with_image_deps_img tests), plain on 9.x, and with --config=strict on 9.x and 7.x. Buildifier and gofmt pass, and //docs:book builds.
  • A throwaway consumer that depends only on rules_helm fetches no rules_img, hermetic_launcher or img_toolchain, and bazel mod graph has no rules_img.
  • A consumer that depends on both modules builds a multi_deploy of a chart. Its --sink output has the manifest digest that helm_oci_digest gives.
  • The module builds as its own root with --override_module=rules_helm=<checkout>.
  • release_prep.sh builds the archive, and both modules resolve from it with archive_override and the strip_prefix above. The version check exits 1 for a wrong module version, a wrong rules_helm dependency and a missing line, and passes with CRLF line endings, an extra argument on the dependency and a trailing comment.
  • The new checks fail when they should: tests/bzl_version on a mismatched version or dependency, the smoke test without bazel_dep(platforms) on Bazel 9, and helm_oci_manifest when HELM_OCI_PARTS_API differs.

Not verified

  • Linux, Windows and Bazel 8.x. CI covers the first two for the root tests.
  • The real publish to the Bazel Central Registry, which needs a tag and the publish token. Two things are open: that publish-to-bcr with attest: true attaches the shared archive's attestation to both modules, and that the registry validator accepts a MODULE.bazel with a dev dependency and local_path_override for a module that is published in the same pull request. Check the registry pull request for both modules after the first tag.

Bazel has no optional `bazel_dep`, and a dev dependency is invisible to
dependents. While `helm/rules_img.bzl` was in `rules_helm`, every
consumer resolved `rules_img`, `hermetic_launcher` and the `img_toolchain`
hub repo, including those that never use `helm_oci_manifest`.

`helm_oci_manifest` now lives in `modules/rules_helm_img`, a second module
that is released from the same tag and has the same version. `rules_helm`
has `rules_img` as a dev dependency only. A consumer adds
`bazel_dep(name = "rules_helm_img")` and loads from
`@rules_helm_img//:defs.bzl`.

- The new module loads the private `helm_oci_parts` rule.
  `HELM_OCI_PARTS_API` in `oci_parts.bzl` makes a `rules_helm_img` that is
  paired with a different `rules_helm` fail with a clear message.
- `.bazelignore` keeps the module out of `//...`, because Bazel does not
  skip a directory that has its own `MODULE.bazel`. The root uses the
  module through a dev dependency and `local_path_override`.
- `.bcr/config.yml` lists both module roots. The new module reuses the
  `rules_helm` release archive with `strip_prefix = "modules/rules_helm_img"`.
- `tests/bzl_version` also compares the new module's version and its
  `rules_helm` dependency with `version.bzl`, so a release that misses a bump
  fails on the pull request. `release_prep.sh` checks the same values as a
  backstop.
- `rules_helm_img_smoke_build_test` builds the module's smoke target from
  the root. `//...` does not reach it, and a missing `bazel_dep(platforms)`
  in the module passed the root tests and failed a standalone build on
  Bazel 9.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant