Files
antisocial/.gitea/workflows/publish.yml
T
thatguygriffandClaude Opus 5 deeedbcc85
CI / Typecheck, test, build (push) Successful in 48s
Publish / Build and push (push) Successful in 2m41s
Match version tags with globs, not regex
Workflow tag filters are glob patterns, so the `[0-9]+` in the previous
version had `+` read as a literal plus and would never have matched 1.0.0 —
the release would have pushed a tag and quietly built nothing.

`[0-9]*.[0-9]*.[0-9]*` uses only basic glob, matches 1.2.3 and 1.2.3-rc1
alike, and still ignores tags that are not versions. The prerelease patterns
collapse into it, since the trailing wildcard already absorbs a suffix.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01BGkRmLfiWuJHx6tQ12EELY
2026-08-26 12:10:53 -03:00

144 lines
5.2 KiB
YAML

name: Publish
# Builds the application image and pushes it to a container registry.
#
# push to main -> :main and :sha-<short>
# tag 1.2.3 -> :1.2.3, :1.2, :1 and :latest
# pull request -> builds without pushing, so a broken Dockerfile is
# caught before it can move a published tag
#
# Configure with repository variables and secrets:
#
# vars.REGISTRY required, e.g. registry.example.com
# vars.IMAGE_NAME optional, defaults to this repository's owner/name
# vars.REGISTRY_USER optional, defaults to the actor running the workflow
# secrets.REGISTRY_TOKEN required to push
#
# Point REGISTRY at a host the runner reaches directly, without an intermediate
# proxy that caps request bodies: a browser image has layers well over 100MB,
# and such a proxy rejects them mid-push with `413 Payload Too Large`.
#
# If that host serves plain HTTP, the builder's Docker daemon also needs it in
# `insecure-registries` — that is daemon configuration, not something a
# workflow can set.
on:
push:
branches:
- main
tags:
# Glob, not regex: `[0-9]` is one digit and `*` is the rest, so these
# match 1.2.3 and 1.2.3-rc1 while ignoring tags that are not versions.
# A `+` here would be read as a literal plus.
- '[0-9]*.[0-9]*.[0-9]*'
- 'v[0-9]*.[0-9]*.[0-9]*'
pull_request:
paths:
- 'Dockerfile'
- 'package.json'
- 'package-lock.json'
- '.gitea/workflows/publish.yml'
workflow_dispatch:
jobs:
build:
name: Build and push
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check the runner can build images
run: |
if ! docker info >/dev/null 2>&1; then
echo "No usable Docker daemon in the job container." >&2
exit 1
fi
docker version --format 'client {{.Client.Version}} / server {{.Server.Version}} / arch {{.Server.Arch}}'
# Images are built natively, so each carries the architecture of the
# runner that built it. A runner of a different architecture joining the
# pool would overwrite these tags with its own arch, at which point this
# needs buildx and a manifest list.
- name: Work out the tags
id: meta
env:
REGISTRY: ${{ vars.REGISTRY }}
IMAGE_NAME: ${{ vars.IMAGE_NAME }}
run: |
set -euo pipefail
if [ -z "${REGISTRY}" ]; then
echo "The REGISTRY repository variable is not set." >&2
echo "Set it to the registry host to publish to, e.g. registry.example.com" >&2
exit 1
fi
image="${REGISTRY}/$(echo "${IMAGE_NAME:-${{ github.repository }}}" | tr '[:upper:]' '[:lower:]')"
tags=""
if [ "${{ github.ref_type }}" = "tag" ]; then
version="${{ github.ref_name }}"
version="${version#v}"
tags="${version}"
# Only a final release moves the rolling aliases; a prerelease is
# published under its own exact version and nothing else.
case "${version}" in
*-*) ;;
*)
major="${version%%.*}"
minor="${version%.*}"
tags="${tags} ${minor} ${major} latest"
;;
esac
else
tags="main sha-$(git rev-parse --short HEAD)"
fi
args=""
for tag in ${tags}; do args="${args} --tag ${image}:${tag}"; done
{
echo "image=${image}"
echo "tags=${tags}"
echo "args=${args}"
} >> "$GITHUB_OUTPUT"
echo "Publishing ${image} as:${tags// /, :}"
# The Actions task token is rejected by some registries, so pushing uses
# a token that belongs to a real user.
- name: Log in to the container registry
if: github.event_name != 'pull_request'
run: |
if [ -z "${{ secrets.REGISTRY_TOKEN }}" ]; then
echo "REGISTRY_TOKEN is not set." >&2
exit 1
fi
if ! echo "${{ secrets.REGISTRY_TOKEN }}" \
| docker login "${{ vars.REGISTRY }}" -u "${{ vars.REGISTRY_USER || github.actor }}" --password-stdin
then
echo >&2
echo "If that failed with 'server gave HTTP response to HTTPS client', the" >&2
echo "registry is plain HTTP and the builder's Docker daemon has to be told" >&2
echo "to allow it: add ${{ vars.REGISTRY }} to insecure-registries in the" >&2
echo "daemon config on the runner. The workflow cannot configure that." >&2
exit 1
fi
- name: Build
run: docker build --pull ${{ steps.meta.outputs.args }} --file Dockerfile .
- name: Push
if: github.event_name != 'pull_request'
run: |
set -euo pipefail
for tag in ${{ steps.meta.outputs.tags }}; do
docker push "${{ steps.meta.outputs.image }}:${tag}"
done
echo "Published ${{ steps.meta.outputs.image }} as: ${{ steps.meta.outputs.tags }}"
- name: Log out
if: always() && github.event_name != 'pull_request'
run: docker logout "${{ vars.REGISTRY }}" || true