From 95946943e31b7b3d293e9650f27de32eab4b0e9b Mon Sep 17 00:00:00 2001 From: SandObserver <260779319+SandObserver@users.noreply.github.com> Date: Sat, 17 Oct 2026 13:20:02 -0400 Subject: [PATCH] Copy the release image to Docker Hub by digest in its own job --- .github/workflows/release.yml | 52 +++++++++++++++++++++++++++++++---- CONTRIBUTING.md | 2 +- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ad57edc..c27c986 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,6 +39,8 @@ jobs: permissions: contents: read packages: write + outputs: + digest: ${{ steps.build.outputs.digest }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: @@ -58,13 +60,12 @@ jobs: - id: meta uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 with: - images: | - ghcr.io/sandobserver/posteryard - docker.io/sandobserver/posteryard + images: ghcr.io/sandobserver/posteryard tags: | type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} - - uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0 + - id: build + uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0 with: context: . platforms: linux/amd64,linux/arm64 @@ -74,9 +75,50 @@ jobs: provenance: mode=max sbom: true - release: + # Docker Hub refuses to move an X.Y.Z tag. Copy the pushed digest. Never build here. + dockerhub-image: needs: image runs-on: ubuntu-24.04 + permissions: + contents: read + packages: read + steps: + - uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1 + - uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 + with: + registry: docker.io + username: sandobserver + password: ${{ secrets.DOCKERHUB_TOKEN }} + - id: meta + uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 + with: + images: docker.io/sandobserver/posteryard + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + - name: Copy the image to Docker Hub + env: + DIGEST: ${{ needs.image.outputs.digest }} + TAGS: ${{ steps.meta.outputs.tags }} + run: | + while read -r tag; do + [ -n "$tag" ] || continue + current=$(docker buildx imagetools inspect --raw "$tag" 2>/dev/null | sha256sum | cut -d' ' -f1) || true + if [ "sha256:$current" = "$DIGEST" ]; then + echo "$tag already points at $DIGEST" + continue + fi + docker buildx imagetools create --tag "$tag" "ghcr.io/sandobserver/posteryard@$DIGEST" + done <<< "$TAGS" + + release: + needs: [image, dockerhub-image] + runs-on: ubuntu-24.04 permissions: contents: write steps: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f0ba140..9e688bb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -118,4 +118,4 @@ The Plex preview shows either 12 random movies or 12 random shows from `site/pos ## Releases -Semantic versioning. Move the `Unreleased` entries in [CHANGELOG.md](CHANGELOG.md) under the new version with its date, set `version` in `pyproject.toml`, merge, and push a `vX.Y.Z` tag. The tag runs the CI checks, then pushes `X.Y.Z`, `X.Y` and `latest` to `ghcr.io/sandobserver/posteryard` and `docker.io/sandobserver/posteryard`, publishes a GitHub release with the version's CHANGELOG section, and rewrites the Docker Hub page from `README.md` with `tools/dockerhub_description.py`, and opens a pull request that copies the release notes into the Unraid template and merges when its checks pass. That pull request needs the release GitHub App, through the secrets `RELEASE_APP_CLIENT_ID` and `RELEASE_APP_PRIVATE_KEY`. Docker Hub needs the repository secret `DOCKERHUB_TOKEN`, an access token with Read, Write and Delete. Docker Hub refuses to move an `X.Y.Z` tag, so a version cannot be published twice. The `Docker Hub page` workflow updates the page by hand. The release stops if the tag, `pyproject.toml` and a dated CHANGELOG section do not agree. The image carries an SBOM and build provenance. A tag with a suffix, such as `v1.0.0-rc.1`, publishes a prerelease: only the `1.0.0-rc.1` image tag, and a GitHub release marked as prerelease. +Semantic versioning. Move the `Unreleased` entries in [CHANGELOG.md](CHANGELOG.md) under the new version with its date, set `version` in `pyproject.toml`, merge, and push a `vX.Y.Z` tag. The tag runs the CI checks, then pushes `X.Y.Z`, `X.Y` and `latest` to `ghcr.io/sandobserver/posteryard`, copies the same image to `docker.io/sandobserver/posteryard`, publishes a GitHub release with the version's CHANGELOG section, and rewrites the Docker Hub page from `README.md` with `tools/dockerhub_description.py`, and opens a pull request that copies the release notes into the Unraid template and merges when its checks pass. That pull request needs the release GitHub App, through the secrets `RELEASE_APP_CLIENT_ID` and `RELEASE_APP_PRIVATE_KEY`. Docker Hub needs the repository secret `DOCKERHUB_TOKEN`, an access token with Read, Write and Delete. Docker Hub refuses to move an `X.Y.Z` tag, so a version cannot be published twice. If the Docker Hub copy fails, use Re-run failed jobs. The copy skips tags that already point at the image. The `Docker Hub page` workflow updates the page by hand. The release stops if the tag, `pyproject.toml` and a dated CHANGELOG section do not agree. The image carries an SBOM and build provenance. A tag with a suffix, such as `v1.0.0-rc.1`, publishes a prerelease: only the `1.0.0-rc.1` image tag, and a GitHub release marked as prerelease.