nxtgauge-admin-solid/.forgejo/workflows/build.yaml
Ashwin Kumar Sivakumar ed4b65cba8
All checks were successful
build-and-release / build (push) Successful in 1m6s
fix(ci): sort registry prune by real image build time, protect current SHA
Same fix as nxtgauge-frontend-solid: registry_prune.py sorted candidate
tags by the manifest GET response's Date header (the moment of the
request, not the image's actual build time), making the "keep newest N"
sort effectively random whenever multiple tags are touched in the same
prune run - which happens on every single run, since the tag just
pushed by this same build is always one of the candidates. That let the
prune step delete the image a run had just built, before gitops even
got a chance to reference it.

Now reads the real "created" timestamp from the image's config blob and
always protects the current run's own SHA from deletion regardless of
sort order.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-17 05:37:45 +05:30

134 lines
5.2 KiB
YAML

name: build-and-release
on:
push:
branches:
- main
- high-performance
concurrency:
group: admin-solid-build-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: docker-ready
env:
DOCKER_BUILDKIT: "1"
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Point DOCKER_HOST at this container's own gateway
run: |
set -euo pipefail
# 127.0.0.1 doesn't work: the job container is nested one level
# inside the runner pod's dind sidecar, so its own loopback isn't
# the sidecar's. Read the container's actual default-route gateway
# directly from /proc/net/route instead of relying on `ip`/`route`
# CLI tools being installed in the job image.
GATEWAY="$(awk '$2 == "00000000" {print $3}' /proc/net/route | head -1 | \
sed -E 's/(..)(..)(..)(..)/0x\4 0x\3 0x\2 0x\1/' | \
{ read -r a b c d; printf '%d.%d.%d.%d' "$a" "$b" "$c" "$d"; })"
echo "Detected docker host gateway: $GATEWAY"
echo "DOCKER_HOST=tcp://$GATEWAY:2375" >> "$GITHUB_ENV"
- name: Set up Docker Buildx
run: |
set -euo pipefail
for attempt in $(seq 1 30); do
if docker version >/dev/null 2>&1; then
break
fi
sleep 2
done
docker version
docker buildx create --use --name nxtgauge-builder || docker buildx use nxtgauge-builder
docker buildx inspect --bootstrap
- name: Login to registry
env:
REGISTRY_HOST: ${{ secrets.REGISTRY_HOST || 'ci.nxtgauge.com' }}
REGISTRY_NAMESPACE: ${{ secrets.REGISTRY_NAMESPACE || 'ashwin' }}
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
run: |
set -euo pipefail
test -n "$REGISTRY_HOST"
printf '%s' "$REGISTRY_PASSWORD" | docker login "$REGISTRY_HOST" -u "$REGISTRY_USERNAME" --password-stdin
- name: Build and push image
env:
REGISTRY_HOST: ${{ secrets.REGISTRY_HOST || 'ci.nxtgauge.com' }}
REGISTRY_NAMESPACE: ${{ secrets.REGISTRY_NAMESPACE || 'ashwin' }}
SHA: ${{ github.sha }}
run: |
set -euo pipefail
metadata_file="/tmp/admin-solid-metadata.json"
image_ref="$REGISTRY_HOST/$REGISTRY_NAMESPACE/nxtgauge-admin-solid:$SHA"
docker buildx build --push \
--metadata-file "$metadata_file" \
-f Dockerfile \
-t "$image_ref" \
.
digest="$(grep -o '"containerimage\.digest"[[:space:]]*:[[:space:]]*"sha256:[^"]*"' "$metadata_file" | grep -o 'sha256:[^"]*')"
test -n "$digest"
printf '%s@%s\n' "$REGISTRY_HOST/$REGISTRY_NAMESPACE/nxtgauge-admin-solid" "$digest" > /tmp/admin-solid-image-ref.txt
- name: Prune old SHA tags
if: success()
continue-on-error: true
env:
REGISTRY_HOST: ${{ secrets.REGISTRY_HOST || 'ci.nxtgauge.com' }}
REGISTRY_NAMESPACE: ${{ secrets.REGISTRY_NAMESPACE || 'ashwin' }}
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
SHA: ${{ github.sha }}
run: |
set -euo pipefail
python3 .forgejo/scripts/registry_prune.py \
--registry "$REGISTRY_HOST" \
--repo "$REGISTRY_NAMESPACE/nxtgauge-admin-solid" \
--username "$REGISTRY_USERNAME" \
--password "$REGISTRY_PASSWORD" \
--protect "$SHA" \
--keep 2
- name: Update GitOps release
env:
GITOPS_GITHUB_OWNER: ${{ secrets.GITOPS_GITHUB_OWNER || 'Traceworks2023' }}
GITOPS_REPO: ${{ secrets.GITOPS_REPO || 'nxtgauge-gitops' }}
GITOPS_BRANCH: ${{ secrets.GITOPS_BRANCH || 'main' }}
# GitHub is the source of truth for nxtgauge-gitops. Push there;
# the repo's own sync-to-forgejo.yml GitHub Action relays the
# commit to Forgejo, which is what Flux (flux-system GitRepository)
# actually watches. Do not push straight to Forgejo here - that
# bypasses GitHub as source of truth.
GITOPS_GITHUB_TOKEN: ${{ secrets.GITOPS_GITHUB_TOKEN }}
SHA: ${{ github.sha }}
run: |
set -euo pipefail
test -n "${GITOPS_GITHUB_TOKEN:-}" || { echo "GITOPS_GITHUB_TOKEN is empty"; exit 1; }
GITOPS_DIR=$(mktemp -d)
git clone "https://${GITOPS_GITHUB_OWNER}:${GITOPS_GITHUB_TOKEN}@github.com/${GITOPS_GITHUB_OWNER}/${GITOPS_REPO}.git" "$GITOPS_DIR"
cd "$GITOPS_DIR"
git checkout "$GITOPS_BRANCH"
image_ref="$(cat /tmp/admin-solid-image-ref.txt)"
./scripts/set-app-release.sh admin-solid "$image_ref"
if git diff --quiet; then
echo "GitOps repo already up to date."
exit 0
fi
git config user.name "forgejo-actions[bot]"
git config user.email "forgejo-actions@ci.nxtgauge.com"
git add apps scripts/set-app-release.sh
git commit -m "chore(gitops): deploy admin-solid@${SHA}"
git push origin "HEAD:${GITOPS_BRANCH}"