a0a987d561
deploy / deploy (push) Failing after 1m35s
Gate the deploy on tests. After pulling master and before building the image, run the full Go suite (incl. integration tests, against an ephemeral Postgres) and the frontend type-check + build. Everything runs inside throwaway toolchain containers, so the host still needs only docker and a red build never reaches production. Update DEPLOY.md to reflect the gate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
88 lines
3.7 KiB
YAML
88 lines
3.7 KiB
YAML
name: deploy
|
|
|
|
# Build the image and (re)start the compose stack on the production host
|
|
# whenever master moves. Also runnable manually from the Gitea Actions tab.
|
|
on:
|
|
push:
|
|
branches: [master]
|
|
workflow_dispatch: {}
|
|
|
|
# One deploy at a time; queue rather than cancel an in-flight run.
|
|
concurrency:
|
|
group: deploy-prod
|
|
cancel-in-progress: false
|
|
|
|
jobs:
|
|
deploy:
|
|
# Self-hosted act_runner registered on the prod host with the "host" label
|
|
# (shell executor), so the job uses the host's git + Docker daemon and the
|
|
# existing clone in /opt/tanabata. See docs/DEPLOY.md for runner setup.
|
|
#
|
|
# Only shell steps here (no `uses:` actions), so the host needs git + docker
|
|
# and nothing else — no node, no go, no rsync. The test step below runs the
|
|
# Go and Node toolchains inside throwaway containers, so nothing has to be
|
|
# installed on the host.
|
|
runs-on: host
|
|
|
|
env:
|
|
DEPLOY_DIR: /opt/tanabata
|
|
|
|
steps:
|
|
- name: Pull latest master
|
|
# DEPLOY_DIR is a git clone set up once at deploy time. reset --hard
|
|
# makes it match origin exactly; .env is untracked (.gitignore) so it
|
|
# is never touched.
|
|
run: |
|
|
cd "$DEPLOY_DIR"
|
|
git fetch --prune origin
|
|
git reset --hard origin/master
|
|
|
|
- name: Run tests
|
|
working-directory: /opt/tanabata
|
|
# Everything runs INSIDE throwaway toolchain containers — the host only
|
|
# needs docker (which it already uses for `docker compose`). Nothing (Go,
|
|
# Node, Postgres, vips/ffmpeg/exiftool) has to be installed on the host.
|
|
# The orchestration below uses only bash builtins + docker. A failure here
|
|
# fails the job, so a red build never reaches production. Module/npm caches
|
|
# persist in named volumes for speed.
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
docker rm -f tfm-ci-db >/dev/null 2>&1 || true
|
|
docker network rm tfm-ci-net >/dev/null 2>&1 || true
|
|
docker network create tfm-ci-net >/dev/null
|
|
trap 'docker rm -f tfm-ci-db >/dev/null 2>&1 || true; docker network rm tfm-ci-net >/dev/null 2>&1 || true' EXIT
|
|
|
|
docker run -d --name tfm-ci-db --network tfm-ci-net \
|
|
-e POSTGRES_PASSWORD=postgres postgres:14-alpine >/dev/null
|
|
# Wait for Postgres, using pg_isready inside the DB container (no host tools).
|
|
for ((i = 0; i < 30; i++)); do
|
|
docker exec tfm-ci-db pg_isready -U postgres >/dev/null 2>&1 && break
|
|
sleep 1
|
|
done
|
|
|
|
# Backend: full suite, including the integration tests, against the
|
|
# ephemeral Postgres. -buildvcs=false since the .git dir isn't mounted.
|
|
docker run --rm --network tfm-ci-net \
|
|
-v /opt/tanabata/backend:/src -w /src \
|
|
-v tfm-ci-gomod:/go/pkg/mod -v tfm-ci-gocache:/root/.cache/go-build \
|
|
-e CGO_ENABLED=0 \
|
|
-e TANABATA_TEST_ADMIN_DSN="postgres://postgres:postgres@tfm-ci-db:5432/postgres?sslmode=disable" \
|
|
golang:1.26-alpine go test -buildvcs=false -count=1 ./...
|
|
|
|
# Frontend: type-check + production build (also validates openapi via
|
|
# the generate:types prestep).
|
|
docker run --rm \
|
|
-v /opt/tanabata:/repo -w /repo/frontend \
|
|
-v tfm-ci-npm:/root/.npm \
|
|
node:22-alpine sh -c "npm ci && npm run check && npm run build"
|
|
|
|
- name: Build image and start the stack
|
|
working-directory: /opt/tanabata
|
|
# .env must already exist in DEPLOY_DIR on the host (secrets + DB mode).
|
|
run: docker compose up -d --build --remove-orphans
|
|
|
|
- name: Prune dangling build layers
|
|
run: docker image prune -f
|