ci: let the image workflows be run by hand

None of the three image workflows could be started manually, so when 0.20.0
tagged before the release chain knew about the frontend and sandbox images,
there was no way to build those images for the tag short of recreating the
release. Add a workflow_dispatch trigger taking the version to build.

A manual run also gets a `move_latest` switch, so rebuilding an older tag does
not drag `latest` backwards. The rule for the moving tag now lives in the
manifest step's shell rather than in a nested expression: `latest` follows the
build unless the release is a prerelease, the run asked it not to, or it is the
rolling `develop` build.
This commit is contained in:
Alex committed 2026-09-12 23:29:33 +01:00
1 parent 15c4d82bcf
commit 55e619b812
3 files changed
+85 -22

No files matched your search

+29 -6
View File
@@ -14,11 +14,25 @@ on:
description: Release tag to build and push (the images are tagged with it)
type: string
required: true
move_latest:
description: Also move the `latest` tag onto this build
type: boolean
default: true
secrets:
DOCKER_USERNAME:
required: true
DOCKER_PASSWORD:
required: true
workflow_dispatch:
inputs:
version:
description: Release tag to build and push (the images are tagged with it)
type: string
required: true
move_latest:
description: Also move the `latest` tag onto this build
type: boolean
default: true
permissions:
contents: read
@@ -142,15 +156,24 @@ jobs:
- name: Create and push multi-arch manifests
env:
TAG: ${{ env.RELEASE_TAG }}${{ matrix.variant }}
# A stable release moves `latest`; a prerelease published by hand
# moves only its own tag (the release trigger fires for those too).
LATEST: ${{ (inputs.version || !github.event.release.prerelease) && format('latest{0}', matrix.variant) || '' }}
VARIANT: ${{ matrix.variant }}
# Raw facts; the shell below decides from them what `latest` does.
IS_PRERELEASE: ${{ github.event.release.prerelease || false }}
MOVE_LATEST: ${{ inputs.move_latest }}
run: |
set -e
# $LATEST is deliberately unquoted: it is empty for a prerelease, and
# an empty word would create a manifest named "$repo:".
# `latest` follows this build, except for a release marked prerelease
# (the release trigger fires for those too) or a manual run that asked
# it not to. MOVE_LATEST is empty for a release event, where only the
# prerelease flag decides.
moving="latest${VARIANT}"
if [ "$IS_PRERELEASE" = true ] || [ "$MOVE_LATEST" = false ]; then
moving=""
fi
# $moving is deliberately unquoted: an empty word would create a
# manifest named "$repo:".
for repo in "$DOCKERHUB_NAMESPACE/docsgpt" "ghcr.io/${{ github.repository_owner }}/docsgpt"; do
for name in "$TAG" $LATEST; do
for name in "$TAG" $moving; do
docker manifest create "$repo:$name" \
--amend "$repo:$TAG-amd64" \
--amend "$repo:$TAG-arm64"
+28 -8
View File
@@ -14,11 +14,25 @@ on:
description: Release tag to build and push (the images are tagged with it)
type: string
required: true
move_latest:
description: Also move the `latest` tag onto this build
type: boolean
default: true
secrets:
DOCKER_USERNAME:
required: true
DOCKER_PASSWORD:
required: true
workflow_dispatch:
inputs:
version:
description: Release tag to build and push (the images are tagged with it)
type: string
required: true
move_latest:
description: Also move the `latest` tag onto this build
type: boolean
default: true
permissions:
contents: read
@@ -26,10 +40,6 @@ permissions:
env:
# The tag being published: passed in by the caller, or the release's own.
RELEASE_TAG: ${{ inputs.version || github.event.release.tag_name }}
# A stable release also moves `latest`. A prerelease published by hand moves
# only its own tag: the release trigger fires for those too, and they must not
# become `latest`.
MOVING_TAG: ${{ (inputs.version || !github.event.release.prerelease) && 'latest' || '' }}
jobs:
build:
@@ -143,13 +153,23 @@ jobs:
- name: Create and push multi-arch manifests
env:
TAG: ${{ env.RELEASE_TAG }}
MOVING: ${{ env.MOVING_TAG }}
# Raw facts; the shell below decides from them what `latest` does.
IS_PRERELEASE: ${{ github.event.release.prerelease || false }}
MOVE_LATEST: ${{ inputs.move_latest }}
run: |
set -e
# $MOVING is deliberately unquoted: it is empty for a prerelease, and
# an empty word would create a manifest named "$repo:".
# `latest` follows this build, except for a release marked prerelease
# (the release trigger fires for those too) or a manual run that asked
# it not to. MOVE_LATEST is empty for a release event, where only the
# prerelease flag decides.
moving=latest
if [ "$IS_PRERELEASE" = true ] || [ "$MOVE_LATEST" = false ]; then
moving=""
fi
# $moving is deliberately unquoted: an empty word would create a
# manifest named "$repo:".
for repo in "$DOCKERHUB_NAMESPACE/docsgpt-fe" "ghcr.io/${{ github.repository_owner }}/docsgpt-fe"; do
for name in "$TAG" $MOVING; do
for name in "$TAG" $moving; do
docker manifest create "$repo:$name" \
--amend "$repo:$TAG-amd64" \
--amend "$repo:$TAG-arm64"
+28 -8
View File
@@ -21,11 +21,25 @@ on:
description: Release tag to build and push (the images are tagged with it)
type: string
required: true
move_latest:
description: Also move the `latest` tag onto this build
type: boolean
default: true
secrets:
DOCKER_USERNAME:
required: true
DOCKER_PASSWORD:
required: true
workflow_dispatch:
inputs:
version:
description: Release tag to build and push (the images are tagged with it)
type: string
required: true
move_latest:
description: Also move the `latest` tag onto this build
type: boolean
default: true
push:
branches: [main]
paths:
@@ -38,10 +52,6 @@ permissions:
env:
# The version being published, or `develop` for a push to main.
RELEASE_TAG: ${{ inputs.version || github.event.release.tag_name || 'develop' }}
# A stable release also moves `latest`. A push to main moves nothing but
# `develop`, and a prerelease published by hand moves only its own tag: the
# release trigger fires for those too, and they must not become `latest`.
MOVING_TAG: ${{ (inputs.version || (github.event.release.tag_name && !github.event.release.prerelease)) && 'latest' || '' }}
jobs:
build:
@@ -155,13 +165,23 @@ jobs:
- name: Create and push multi-arch manifests
env:
TAG: ${{ env.RELEASE_TAG }}
MOVING: ${{ env.MOVING_TAG }}
# Raw facts; the shell below decides from them what `latest` does.
IS_PRERELEASE: ${{ github.event.release.prerelease || false }}
MOVE_LATEST: ${{ inputs.move_latest }}
run: |
set -e
# $MOVING is deliberately unquoted: it is empty for a push to main,
# and an empty word would create a manifest named "$repo:".
# `latest` follows this build, except for the rolling `develop` build,
# a release marked prerelease (the release trigger fires for those
# too), or a manual run that asked it not to. MOVE_LATEST is empty for
# a release event and for a push, where the other two rules decide.
moving=latest
if [ "$TAG" = develop ] || [ "$IS_PRERELEASE" = true ] || [ "$MOVE_LATEST" = false ]; then
moving=""
fi
# $moving is deliberately unquoted: an empty word would create a
# manifest named "$repo:".
for repo in "$DOCKERHUB_NAMESPACE/docsgpt-sandbox" "ghcr.io/${{ github.repository_owner }}/docsgpt-sandbox"; do
for name in "$TAG" $MOVING; do
for name in "$TAG" $moving; do
docker manifest create "$repo:$name" \
--amend "$repo:$TAG-amd64" \
--amend "$repo:$TAG-arm64"