ci(docker): mirror the all-in-one image to Docker Hub
The aio image (#1042) shipped GHCR-only with a TODO to wire the Docker Hub mirror once the Hub repo existed. backend, frontend and the ml sidecar all publish to docker.io/picpeak/*; aio was the only image a Docker Hub user could not pull. merge-aio now follows merge-backend/merge-ml verbatim: DOCKERHUB_ENABLED computed from the repository slug (so forks stay GHCR-only), a gated Docker Hub login, docker.io/picpeak/aio added to the metadata images list, and a Docker Hub manifest inspect. Tag scheme is untouched — the same beta/main/stable/latest/semver tags land in both registries. The build summary drops the "Docker Hub mirror pending" note and lists the aio (and ml) Hub images when the mirror is active.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
This GitHub Actions workflow automatically builds and pushes Docker images for the backend, the frontend, and the all-in-one image to GitHub Container Registry (ghcr.io).
|
||||
|
||||
The **all-in-one image** (`<repo>/aio`, built from `Dockerfile.aio` at the repo root, #1042) bundles the backend and the built frontend into a single container with SQLite as the default engine — one `docker run`, no compose. It follows the same per-arch build → digest-merge → per-version tag scheme as the other two images, is currently GHCR-only (the Docker Hub mirror gets wired later), and every PR additionally runs a `smoke-aio` job that boots the image and asserts the SPA shell, brand-title rendering, immutable asset caching, and the SQLite engine resolution.
|
||||
The **all-in-one image** (`<repo>/aio`, built from `Dockerfile.aio` at the repo root, #1042) bundles the backend and the built frontend into a single container with SQLite as the default engine — one `docker run`, no compose. It follows the same per-arch build → digest-merge → per-version tag scheme as the other two images, is mirrored to Docker Hub (`docker.io/picpeak/aio`) alongside GHCR on the canonical org repo, and every PR additionally runs a `smoke-aio` job that boots the image and asserts the SPA shell, brand-title rendering, immutable asset caching, and the SQLite engine resolution.
|
||||
|
||||
## Features
|
||||
|
||||
|
||||
@@ -780,6 +780,15 @@ jobs:
|
||||
run: |
|
||||
repo_lc="${GITHUB_REPOSITORY,,}"
|
||||
echo "AIO_IMAGE_NAME=${repo_lc}/aio" >> "$GITHUB_ENV"
|
||||
# Mirror manifests to Docker Hub (picpeak/aio) only on the canonical org
|
||||
# repo, where the DOCKERHUB_* secrets live. Forks (and any other owner)
|
||||
# fall back to GHCR-only — the Docker Hub image line and login are gated
|
||||
# on this flag so their builds keep working unchanged.
|
||||
if [[ "$GITHUB_REPOSITORY" == "PicPeak/picpeak" ]]; then
|
||||
echo "DOCKERHUB_ENABLED=true" >> "$GITHUB_ENV"
|
||||
else
|
||||
echo "DOCKERHUB_ENABLED=false" >> "$GITHUB_ENV"
|
||||
fi
|
||||
|
||||
- name: Download digest artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -811,16 +820,24 @@ jobs:
|
||||
echo "is_prerelease=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
# Same per-version tag scheme as backend/frontend: every Release Please
|
||||
# version publishes a matching aio image. GHCR-only for now — the Docker
|
||||
# Hub mirror (docker.io/picpeak/aio) is wired later once the Hub repo
|
||||
# exists: add the images line + Docker Hub login exactly like
|
||||
# merge-backend (#1042).
|
||||
- name: Log in to Docker Hub
|
||||
if: env.DOCKERHUB_ENABLED == 'true'
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: docker.io
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
# Same per-version tag scheme as backend/frontend/ml: every Release Please
|
||||
# version publishes a matching aio image, mirrored to Docker Hub
|
||||
# (docker.io/picpeak/aio) on the canonical org repo (#1042).
|
||||
- name: Extract metadata for AIO
|
||||
id: meta-aio
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.AIO_IMAGE_NAME }}
|
||||
images: |
|
||||
${{ env.REGISTRY }}/${{ env.AIO_IMAGE_NAME }}
|
||||
${{ env.DOCKERHUB_ENABLED == 'true' && 'docker.io/picpeak/aio' || '' }}
|
||||
labels: |
|
||||
org.opencontainers.image.title=PicPeak All-in-one
|
||||
org.opencontainers.image.description=PicPeak backend + frontend in a single container (SQLite default)
|
||||
@@ -857,6 +874,11 @@ jobs:
|
||||
run: |
|
||||
docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.AIO_IMAGE_NAME }}:${{ steps.meta-aio.outputs.version }}
|
||||
|
||||
- name: Inspect manifest (Docker Hub)
|
||||
if: env.DOCKERHUB_ENABLED == 'true'
|
||||
run: |
|
||||
docker buildx imagetools inspect docker.io/picpeak/aio:${{ steps.meta-aio.outputs.version }}
|
||||
|
||||
# Boot-level verification of the AIO image on every PR: build for the
|
||||
# runner's arch, run it with no DB env (SQLite default), and assert the
|
||||
# things nginx used to guarantee — SPA shell with the brand title rendered,
|
||||
@@ -1388,10 +1410,14 @@ jobs:
|
||||
if [[ "${{ needs.merge-ml.result }}" == "success" ]]; then
|
||||
echo "- ML sidecar (optional): \`${{ env.REGISTRY }}/${{ env.ML_IMAGE_NAME }}\`" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
echo "- All-in-one: \`${{ env.REGISTRY }}/${{ env.AIO_IMAGE_NAME }}\` (GHCR only — Docker Hub mirror pending)" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- All-in-one: \`${{ env.REGISTRY }}/${{ env.AIO_IMAGE_NAME }}\`" >> $GITHUB_STEP_SUMMARY
|
||||
if [[ "$DOCKERHUB_ENABLED" == "true" ]]; then
|
||||
echo "- Backend (Docker Hub): \`docker.io/picpeak/backend\`" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- Frontend (Docker Hub): \`docker.io/picpeak/frontend\`" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- All-in-one (Docker Hub): \`docker.io/picpeak/aio\`" >> $GITHUB_STEP_SUMMARY
|
||||
if [[ "${{ needs.merge-ml.result }}" == "success" ]]; then
|
||||
echo "- ML sidecar (Docker Hub): \`docker.io/picpeak/ml\`" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
Reference in New Issue
Block a user