Skip to content

ci: pin first-party hyperi-ci caller via moving major tag (@vMAJOR) to cut cross-project update churn #32

@catinspace-au

Description

@catinspace-au

Problem

Consumers SHA-pin the hyperi-ci reusable-workflow caller (Renovate
helpers:pinGitHubActionDigests), e.g.
uses: hyperi-io/hyperi-ci/.github/workflows/python-ci.yml@<sha> # v2.6.1.
That is correct supply-chain hygiene, but it means every hyperi-ci release
needs a bump PR in every consumer repo
to be picked up — N repos × 1 PR per
release. During active hyperi-ci development that is real churn.

Decision

Adopt a moving major tag @vMAJOR for the first-party hyperi-ci caller
(mirrors actions/checkout@v4). Consumers reference @v2; the release flow
advances v2 to each new release commit; one tag-move rolls every consumer
forward. Minor/patch flow automatically; only a major bump is a deliberate
per-consumer edit.

Chosen over: a per-repo hyperi-ci pin-ci CLI (per-repo fan-out = mini-Renovate,
the bespoke machinery #31 warned against), bare @main (no version gate at all),
and status-quo Renovate SHA-pinning (most PR churn).

Keep Renovate SHA-pinning for third-party actions — that is where pinning
earns its keep. Only the first-party hyperi-ci caller moves to @vMAJOR.

Why it is safe (and what it does not change)

Implementation checklist

  • scripts/advance-major-tag.py — derive vN from the release version
    (VERSION file / arg / latest tag), move vN to the release commit, push
    (force). Pure logic (major extraction + tag name) unit-tested; git ops covered
    with a tmp repo. No bash — Python, like scripts/update-versions.py.
  • Wire it into hyperi-ci's own .github/workflows/ci.yml Release job
    (after npx semantic-release). Not in the shared _release-tail.yml
    only hyperi-ci is consumed as a reusable workflow. Needs contents: write
    (already present) + a token allowed to move tags.
  • init: scaffold @vN instead of @main. Derive N from __version__
    major (_WORKFLOW_REF = f"v{__version__.split('.')[0]}") so it auto-tracks.
    Update _render_workflow test.
  • Renovate org preset (hyperi-io/renovate-config, governed from hyperi-ci):
    add a packageRule that excludes hyperi-io/hyperi-ci reusable-workflow
    refs from digest-pinning (keep them on the moving tag, allow major-tag bumps).
    Third-party digest-pinning unchanged.
  • Bootstrap: create the v2 tag at the current release (no bare-major tag
    exists yet) so consumers can switch immediately.
  • Roll existing consumers @<sha>/@main -> @v2 (pylib, rustlib, dfe-*).
  • Docs: docs/dependencies/WORKFLOW-PINNING.md (add the @vMAJOR first-party
    caller policy), docs/dependencies/DEPS-PINNING.md (first-party caller is the
    one exception to SHA-pinning), and the init notes in README/ARCHITECTURE.

Current state (for whoever picks this up)

  • Stable release: v2.6.1 (on PyPI). No bare-major tag (v2) exists yet.
  • init scaffolds @main (src/hyperi_ci/init.py _WORKFLOW_REF = "main").
  • Renovate currently SHA-pins the caller in consumers (see pylib history:
    chore(deps): Pin hyperi-io/hyperi-ci action to ...).
  • Reusable resolver already exists: scripts/update-versions.py
    (_select_pinned_release, _pinned_spec_for) — version->SHA with cooldown,
    if a SHA is ever needed.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions