Skip to content

Commit 64a0d89

Browse files
coopernetesclaude
andcommitted
chore: bump to 1.0.0-rc.1; pin release to commit SHA image; add weekly interim image cleanup
- Gradle version bumped to 1.0.0-rc.1 - docker-publish: main push now tags build-{sha7} alongside :edge; release promotion resolves build-{sha7} (commit-pinned) instead of :edge, eliminating the race condition where edge moves forward between tag cut and workflow run - cleanup-interim-images: weekly workflow (Mon 08:00 UTC) deletes all GHCR package versions exclusively tagged build-*; protected tags (v*, edge, latest, untagged) are never touched; serialised with main push via concurrency group closes #193 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent b4f4db4 commit 64a0d89

3 files changed

Lines changed: 100 additions & 13 deletions

File tree

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
name: Cleanup Interim Images
2+
3+
# Deletes GHCR package versions whose tags are exclusively build-* (ephemeral
4+
# per-commit images). Versions carrying any other tag (v*, edge, latest, etc.)
5+
# are never touched. Runs weekly and can be triggered manually.
6+
7+
on:
8+
schedule:
9+
- cron: '0 8 * * 1' # Monday 08:00 UTC
10+
workflow_dispatch:
11+
12+
# Serialise with docker-publish to avoid deleting a build-* image that a
13+
# concurrent release promotion is about to resolve. cancel-in-progress: false
14+
# makes cleanup wait rather than be killed.
15+
concurrency:
16+
group: docker-refs/heads/main
17+
cancel-in-progress: false
18+
19+
permissions:
20+
contents: read
21+
packages: write
22+
23+
jobs:
24+
cleanup:
25+
runs-on: ubuntu-latest
26+
steps:
27+
- name: Delete stale build-* package versions
28+
env:
29+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
30+
run: |
31+
OWNER="${{ github.repository_owner }}"
32+
PACKAGE="${{ github.event.repository.name }}"
33+
DELETED=0
34+
KEPT=0
35+
36+
echo "Fetching package versions for ${OWNER}/${PACKAGE}..."
37+
38+
# Collect all versions into a temp file (handles pagination via --paginate)
39+
gh api \
40+
-H "Accept: application/vnd.github+json" \
41+
"/users/${OWNER}/packages/container/${PACKAGE}/versions" \
42+
--paginate > /tmp/versions.json
43+
44+
TOTAL=$(jq 'length' /tmp/versions.json)
45+
echo "Found ${TOTAL} total package versions."
46+
echo ""
47+
48+
jq -c '.[]' /tmp/versions.json | while read -r version; do
49+
VERSION_ID=$(echo "$version" | jq -r '.id')
50+
TAGS=$(echo "$version" | jq -r '.metadata.container.tags // [] | .[]')
51+
52+
# Skip untagged versions — never delete them (likely referenced by a manifest list)
53+
if [ -z "$TAGS" ]; then
54+
echo "KEEP [${VERSION_ID}] (untagged)"
55+
continue
56+
fi
57+
58+
TAG_LIST=$(echo "$TAGS" | tr '\n' ' ' | sed 's/ $//')
59+
60+
# Guard: keep if ANY tag does not match build-[0-9a-f]+
61+
PROTECTED=false
62+
while IFS= read -r tag; do
63+
if [[ ! "$tag" =~ ^build-[0-9a-f]+$ ]]; then
64+
PROTECTED=true
65+
break
66+
fi
67+
done <<< "$TAGS"
68+
69+
if [ "$PROTECTED" = true ]; then
70+
echo "KEEP [${VERSION_ID}] tags: ${TAG_LIST}"
71+
else
72+
echo "DELETE [${VERSION_ID}] tags: ${TAG_LIST}"
73+
gh api \
74+
--method DELETE \
75+
-H "Accept: application/vnd.github+json" \
76+
"/users/${OWNER}/packages/container/${PACKAGE}/versions/${VERSION_ID}"
77+
fi
78+
done
79+
80+
echo ""
81+
echo "Cleanup complete."

.github/workflows/docker-publish.yml

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ concurrency:
2222

2323
jobs:
2424
build-and-push:
25-
# Tags are released by promoting the already-built edge image — no rebuild needed.
25+
name: Docker / Build & Push
26+
# Tags are released by promoting the already-built build image — no rebuild needed.
2627
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
2728
runs-on: ubuntu-latest
2829
outputs:
@@ -55,6 +56,7 @@ jobs:
5556
tags: |
5657
type=ref,event=pr
5758
type=raw,value=edge,enable={{is_default_branch}}
59+
type=sha,prefix=build-,format=short,enable={{is_default_branch}}
5860
type=raw,value=${{ inputs.version }},enable=${{ github.event_name == 'workflow_dispatch' }}
5961
6062
- name: Build and push
@@ -153,21 +155,25 @@ jobs:
153155
grep "grype_${GRYPE_VERSION}_linux_amd64.tar.gz" "grype_${GRYPE_VERSION}_checksums.txt" | sha256sum --check
154156
tar -xzf "grype_${GRYPE_VERSION}_linux_amd64.tar.gz" -C /usr/local/bin grype
155157
156-
# Resolve the digest of the already-built, already-scanned edge image.
157-
# The tag ruleset enforces Container Scan passed on this commit before the tag
158-
# could be pushed, so edge is guaranteed clean at this point.
159-
- name: Resolve edge digest
160-
id: edge
158+
# Resolve the digest of the build-{sha} image produced when this commit landed on main.
159+
# The tag ruleset enforces Container Scan passed on this commit before the tag could be
160+
# pushed, so the build image is guaranteed scanned. Using the commit-pinned build tag
161+
# (not :edge) ensures we promote the exact image for this release regardless of how
162+
# many commits have landed on main since.
163+
- name: Resolve build image digest
164+
id: build
161165
run: |
166+
TAG="build-${GITHUB_SHA::7}"
162167
DIGEST=$(docker buildx imagetools inspect \
163-
ghcr.io/${{ github.repository }}:edge \
168+
"ghcr.io/${{ github.repository }}:${TAG}" \
164169
--format '{{.Manifest.Digest}}')
165170
echo "digest=${DIGEST}" >> "$GITHUB_OUTPUT"
166-
echo "Promoting edge digest: ${DIGEST}"
171+
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
172+
echo "Promoting ${TAG} @ ${DIGEST}"
167173
168-
- name: Scan edge image
174+
- name: Scan build image
169175
run: |
170-
grype ghcr.io/${{ github.repository }}@${{ steps.edge.outputs.digest }} \
176+
grype "ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }}" \
171177
--config .grype.yaml \
172178
-o "template=grype-report.txt" \
173179
-o "json=grype-report.json"
@@ -182,12 +188,12 @@ jobs:
182188
grype-report.json
183189
retention-days: 90
184190

185-
- name: Promote edge to release tags
191+
- name: Promote build image to release tags
186192
run: |
187193
VERSION=${GITHUB_REF_NAME}
188194
MAJOR=$(echo ${VERSION} | cut -d. -f1)
189195
MINOR=$(echo ${VERSION} | cut -d. -f1-2)
190-
SOURCE="ghcr.io/${{ github.repository }}@${{ steps.edge.outputs.digest }}"
196+
SOURCE="ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }}"
191197
docker buildx imagetools create \
192198
--tag "ghcr.io/${{ github.repository }}:${VERSION}" \
193199
--tag "ghcr.io/${{ github.repository }}:${MINOR}" \

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ ext {
7979

8080
allprojects {
8181
group = 'org.finos.gitproxy'
82-
version = '1.0.0-beta.7'
82+
version = '1.0.0-rc.1'
8383

8484
repositories {
8585
mavenCentral()

0 commit comments

Comments
 (0)