Files
jorgecuadros-platform/.gitea/workflows/build.yml
T
rmancinasandClaude Opus 5 b12382b436
Build and Push Images / Build jorgecuadros-web (push) Successful in 1m39s
Build and Push Images / Build jorgecuadros-api (push) Successful in 2m17s
ci: move the galactus deploy chain to a tag-only workflow
The deploy was a job inside build.yml gated by
`if: startsWith(github.ref, 'refs/tags/v')`. Gitea draws every job into the
run graph before it evaluates that `if`, so an ordinary push to master showed
a pending "Deploy to galactus" — indistinguishable from prod being about to be
redeployed off an unreleased commit, and the only safe reaction is to cancel
the run, which takes the images down with it.

The gate itself was never wrong (no deploy-galactus run has ever been created
from a branch ref), but a guarantee you cannot see is not much of a guarantee.
`on: push: tags: ["v*"]` in a workflow of its own makes it structural: the
deploy cannot appear on a master build because the workflow does not exist
there.

It replaces `needs: build` by polling the Actions API for the build.yml run at
this tag and requiring it green, so both images are still known to be in the
registry before anything is pulled. AUTO_DEPLOY_GALACTUS still cuts the chain.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 22:28:02 -07:00

111 lines
4.1 KiB
YAML

# Build + push the API and web container images to the git.mancinas.io registry.
#
# Two images from this one repo:
# git.mancinas.io/rmancinas/jorgecuadros-api
# git.mancinas.io/rmancinas/jorgecuadros-web
#
# Comprehensive versioning (docker/metadata-action). Every build pushes a set
# of tags so an image is addressable at several granularities:
# - vX.Y.Z / vX.Y when the trigger is a git tag vX.Y.Z (releases)
# - <branch> the branch that was pushed (e.g. master, feat-foo)
# - sha-<short> immutable per-commit id, always present
# - latest only on the default branch (master)
# The same version string + commit + build date are baked into the image as
# ARG/ENV (APP_VERSION / GIT_SHA / BUILD_DATE) and as OCI labels, so a running
# container can report exactly what is deployed.
#
# Release flow: git tag v1.2.0 && git push origin v1.2.0 -> versioned images
# -> deploy-on-tag.yml waits for this run to go green and then
# dispatches deploy-galactus.yml.
#
# This workflow BUILDS ONLY — it never deploys. The deploy chain used to be a
# job here, gated to tag refs, but Gitea draws every job of a workflow into the
# run graph before it evaluates the job's `if`: a routine master build showed a
# pending "Deploy to galactus" and looked like prod was about to be redeployed
# off an unreleased commit. Keeping the deploy in a `on: push: tags` workflow of
# its own makes that structurally impossible.
name: Build and Push Images
on:
push:
branches: [master]
tags: ["v*"]
paths:
- "apps/**"
- "packages/**"
- "docker/**"
- "package.json"
- "pnpm-lock.yaml"
- ".gitea/workflows/build.yml"
workflow_dispatch:
env:
REGISTRY: git.mancinas.io
jobs:
build:
name: Build ${{ matrix.image }}
# release.yml pushes the release commit and its tag in a single `git push`,
# so Gitea creates two runs for the same commit: one for master, one for the
# tag. Only the tag run matters — it is the one that emits the X.Y.Z / X.Y
# image tags, and it publishes `latest` and `sha-<short>` too, since it is
# the same commit. Skip the branch run rather than racing or cancelling it.
# Ordinary pushes to master (any message but `chore(release):`) still build.
if: >-
github.event_name != 'push' ||
startsWith(github.ref, 'refs/tags/') ||
!startsWith(github.event.head_commit.message, 'chore(release):')
runs-on: docker
container:
image: docker:27-dind
options: --privileged
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- image: jorgecuadros-api
dockerfile: docker/api.Dockerfile
- image: jorgecuadros-web
dockerfile: docker/web.Dockerfile
steps:
- name: Install Node.js for actions
run: apk add --no-cache nodejs npm
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ matrix.image }}
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=ref,event=branch
type=sha,format=short,prefix=sha-
type=raw,value=latest,enable={{is_default_branch}}
- uses: docker/build-push-action@v5
with:
context: .
file: ${{ matrix.dockerfile }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64
build-args: |
APP_VERSION=${{ steps.meta.outputs.version }}
GIT_SHA=${{ github.sha }}
BUILD_DATE=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }}