Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 30 additions & 6 deletions .github/workflows/release-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,19 @@ on:
type: boolean
default: true
required: false
require-same-commit:
description: >-
Require every image to resolve to ONE build commit. Correct when a
single workflow builds them together (an app and its sidecar), where a
mismatch means a half-updated pair shipping under one version. WRONG
for a repo whose images are built by separate, path-filtered workflows:
those components change independently and almost never share a commit,
so the release is legitimately "SPA built at X plus config built at Y".
Set false there — each image is still verified against this branch's
history, and the tag lands on the newest resolved commit.
type: boolean
default: true
required: false
verify-depth:
description: >-
How many commits back to search for the build. Needs to cover the gap
Expand Down Expand Up @@ -220,6 +233,7 @@ jobs:
SOURCE_TAG: ${{ inputs.source-tag }}
IMAGE_TAG: ${{ steps.plan.outputs.image_tag }}
VERIFY: ${{ inputs.verify-source-commit }}
SAME_COMMIT: ${{ inputs.require-same-commit }}
DEPTH: ${{ inputs.verify-depth }}
SHA: ${{ github.sha }}
run: |
Expand Down Expand Up @@ -289,13 +303,23 @@ jobs:
behind="$(git rev-list --count "$release_commit..$SHA")"
echo " verified: built from $release_commit (tag $matched), $behind commit(s) behind the ref"
if [ -n "$RELEASE_COMMIT" ] && [ "$RELEASE_COMMIT" != "$release_commit" ]; then
echo "::error::images disagree about which commit they were built from:"
echo "::error:: $RELEASE_COMMIT vs $release_commit ($img)."
echo "::error::Images released together must come from one build."
exit 1
if [ "$SAME_COMMIT" = "true" ]; then
echo "::error::images disagree about which commit they were built from:"
echo "::error:: $RELEASE_COMMIT vs $release_commit ($img)."
echo "::error::Images released together must come from one build."
echo "::error::If these components are built by separate path-filtered"
echo "::error::workflows, they change independently — set require-same-commit: false."
exit 1
fi
echo " note: differs from $RELEASE_COMMIT — independent components, allowed"
fi
# Keep the NEWEST resolved commit: with independent components the
# release is "everything up to here", and the oldest would name a
# commit that predates code being shipped.
if [ -z "$RELEASE_COMMIT" ] || [ "$behind" -lt "$BEHIND" ]; then
RELEASE_COMMIT="$release_commit"
BEHIND="$behind"
fi
RELEASE_COMMIT="$release_commit"
BEHIND="$behind"
fi

# Tag BY DIGEST, not by re-resolving :latest. Between the check above
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,13 @@ jobs:
the image tag: `/` is not legal in a docker tag.
- Notes are always GitHub-generated; `summary` is pre-pended when supplied, and
the promoted digests are listed under it.
- **`require-same-commit: false` for independently-built components.** By default
every image must resolve to one build commit, which catches a half-updated
pair shipping under one version. That is wrong for a repo whose images come
from separate path-filtered workflows — those change independently and almost
never share a commit, so the release legitimately means "SPA built at X plus
config built at Y". Each image is still verified against the branch's history;
the tag lands on the newest resolved commit.
- **`ghcr-token` when the package is user-owned.** On a personal account a
package bootstrapped by a manual push is owned by the user, not the repo, and
`GITHUB_TOKEN` gets 403 on it — including on reads, which the registry reports
Expand Down