commit a6e03d888675d379f09ad42c61cc3e340180b572 Author: enricobuehler Date: Tue May 19 19:00:55 2026 +0200 Initial: build-deploy-game.yml reusable workflow Drives the standard four-stage build-api-core → deploy-api-core → build-web → deploy-web pipeline for a played game. Game repos invoke via: jobs: deploy: uses: played/workflows/.gitea/workflows/build-deploy-game.yml@main with: game-id: secrets: inherit The caller's BUILD_ENV / NPMRC / REGISTRY_* / PLAYED_* / STEP_CA_PROVISIONER_PASSWORD are inherited; `game-id` parameterizes the VM paths (~/, ~/-secrets) and the docker tag context. Co-Authored-By: Claude Opus 4.7 (1M context) diff --git a/.gitea/workflows/build-deploy-game.yml b/.gitea/workflows/build-deploy-game.yml new file mode 100644 index 0000000..cd64c00 --- /dev/null +++ b/.gitea/workflows/build-deploy-game.yml @@ -0,0 +1,213 @@ +name: Build & Deploy played game (reusable) + +# Invoked by each game's `.gitea/workflows/deploy.yml`: +# +# jobs: +# deploy: +# uses: played/workflows/.gitea/workflows/build-deploy-game.yml@main +# with: +# game-id: relayer +# secrets: inherit +# +# The caller repo must expose these Gitea Actions secrets (via +# `secrets: inherit` or per-secret pass-through): +# - BUILD_ENV — the prod .env, written to /tmp/.env.prod for +# Docker build secret mount AND to +# ~/-secrets/.env on the deploy VM +# - NPMRC — ~/.npmrc with @played registry auth token +# - REGISTRY_USER / REGISTRY_TOKEN — Gitea container registry creds +# - PLAYED_HOST / PLAYED_USER / PLAYED_PORT / PLAYED_SSH_KEY — deploy target +# - STEP_CA_PROVISIONER_PASSWORD — for the cert-init container + +on: + workflow_call: + inputs: + game-id: + description: Game slug (must match @played/games-registry's GAMES, e.g. relayer) + type: string + required: true + +jobs: + build-api-core: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + config-inline: | + [registry."docker.io"] + mirrors = ["192.168.1.52:5000"] + [registry."192.168.1.52:5000"] + http = true + insecure = true + + - name: Log in to Gitea registry + uses: docker/login-action@v3 + with: + registry: git.unom.io + username: ${{ secrets.REGISTRY_USER }} + password: ${{ secrets.REGISTRY_TOKEN }} + + - name: Write secrets to files + env: + BUILD_ENV: ${{ secrets.BUILD_ENV }} + NPMRC: ${{ secrets.NPMRC }} + run: | + printenv BUILD_ENV > /tmp/.env.prod + printenv NPMRC > /tmp/.npmrc + + - name: Build & push api-core + uses: docker/build-push-action@v6 + with: + context: . + file: ./api/core/Dockerfile + push: true + tags: | + git.unom.io/${{ gitea.repository }}/api-core:latest + git.unom.io/${{ gitea.repository }}/api-core:${{ gitea.sha }} + secret-files: | + env=/tmp/.env.prod + npmrc=/tmp/.npmrc + cache-from: | + type=registry,ref=git.unom.io/${{ gitea.repository }}/api-core:cache + type=registry,ref=git.unom.io/played/bun-cache:latest + cache-to: | + type=registry,ref=git.unom.io/${{ gitea.repository }}/api-core:cache,mode=min + type=registry,ref=git.unom.io/played/bun-cache:latest,mode=max + + deploy-api-core: + runs-on: ubuntu-24.04 + needs: build-api-core + steps: + - name: Write secrets to server + uses: appleboy/ssh-action@v1.2.5 + with: + host: ${{ secrets.PLAYED_HOST }} + username: ${{ secrets.PLAYED_USER }} + port: ${{ secrets.PLAYED_PORT }} + key: ${{ secrets.PLAYED_SSH_KEY }} + envs: BUILD_ENV,STEP_CA_PROVISIONER_PASSWORD,GAME_ID + script: | + mkdir -p ~/${GAME_ID}-secrets + printf '%s' "$BUILD_ENV" > ~/${GAME_ID}-secrets/.env + printf '%s' "$STEP_CA_PROVISIONER_PASSWORD" > ~/${GAME_ID}-secrets/step-provisioner-password.txt + chmod 644 ~/${GAME_ID}-secrets/.env + chmod 600 ~/${GAME_ID}-secrets/step-provisioner-password.txt + env: + BUILD_ENV: ${{ secrets.BUILD_ENV }} + STEP_CA_PROVISIONER_PASSWORD: ${{ secrets.STEP_CA_PROVISIONER_PASSWORD }} + GAME_ID: ${{ inputs.game-id }} + + - name: Pull and start api-core + uses: appleboy/ssh-action@v1.2.5 + with: + host: ${{ secrets.PLAYED_HOST }} + username: ${{ secrets.PLAYED_USER }} + port: ${{ secrets.PLAYED_PORT }} + key: ${{ secrets.PLAYED_SSH_KEY }} + envs: GAME_ID + script: | + docker login git.unom.io -u ${{ secrets.REGISTRY_USER }} -p ${{ secrets.REGISTRY_TOKEN }} + cd ~/${GAME_ID} + git fetch origin main + git reset --hard origin/main + docker compose -f compose.production.yml --env-file ~/${GAME_ID}-secrets/.env pull api-core + docker compose -f compose.production.yml --env-file ~/${GAME_ID}-secrets/.env up -d --no-build api-core + env: + GAME_ID: ${{ inputs.game-id }} + + - name: Wait for api-core to be healthy + uses: appleboy/ssh-action@v1.2.5 + with: + host: ${{ secrets.PLAYED_HOST }} + username: ${{ secrets.PLAYED_USER }} + port: ${{ secrets.PLAYED_PORT }} + key: ${{ secrets.PLAYED_SSH_KEY }} + envs: GAME_ID + script: | + cd ~/${GAME_ID} + echo "Waiting for api-core to be ready..." + for i in $(seq 1 30); do + if docker compose -f compose.production.yml --env-file ~/${GAME_ID}-secrets/.env ps api-core | grep -q "(healthy)"; then + echo "api-core is healthy" + exit 0 + fi + echo "Attempt $i/30..." + sleep 5 + done + echo "api-core did not become healthy in time" + exit 1 + env: + GAME_ID: ${{ inputs.game-id }} + + build-web: + runs-on: ubuntu-24.04 + needs: deploy-api-core + steps: + - uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + config-inline: | + [registry."docker.io"] + mirrors = ["192.168.1.52:5000"] + [registry."192.168.1.52:5000"] + http = true + insecure = true + + - name: Log in to Gitea registry + uses: docker/login-action@v3 + with: + registry: git.unom.io + username: ${{ secrets.REGISTRY_USER }} + password: ${{ secrets.REGISTRY_TOKEN }} + + - name: Write secrets to files + env: + BUILD_ENV: ${{ secrets.BUILD_ENV }} + NPMRC: ${{ secrets.NPMRC }} + run: | + printenv BUILD_ENV > /tmp/.env.prod + printenv NPMRC > /tmp/.npmrc + + - name: Build & push web + uses: docker/build-push-action@v6 + with: + context: . + file: ./apps/web/Dockerfile + push: true + tags: | + git.unom.io/${{ gitea.repository }}/web:latest + git.unom.io/${{ gitea.repository }}/web:${{ gitea.sha }} + secret-files: | + env=/tmp/.env.prod + npmrc=/tmp/.npmrc + cache-from: | + type=registry,ref=git.unom.io/${{ gitea.repository }}/web:cache + type=registry,ref=git.unom.io/played/bun-cache:latest + cache-to: | + type=registry,ref=git.unom.io/${{ gitea.repository }}/web:cache,mode=min + type=registry,ref=git.unom.io/played/bun-cache:latest,mode=max + + deploy-web: + runs-on: ubuntu-24.04 + needs: build-web + steps: + - name: Pull and start web + uses: appleboy/ssh-action@v1.2.5 + with: + host: ${{ secrets.PLAYED_HOST }} + username: ${{ secrets.PLAYED_USER }} + port: ${{ secrets.PLAYED_PORT }} + key: ${{ secrets.PLAYED_SSH_KEY }} + envs: GAME_ID + script: | + docker login git.unom.io -u ${{ secrets.REGISTRY_USER }} -p ${{ secrets.REGISTRY_TOKEN }} + cd ~/${GAME_ID} + docker compose -f compose.production.yml --env-file ~/${GAME_ID}-secrets/.env pull web + docker compose -f compose.production.yml --env-file ~/${GAME_ID}-secrets/.env up -d --no-build web + env: + GAME_ID: ${{ inputs.game-id }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/README.md b/README.md new file mode 100644 index 0000000..b4774e1 --- /dev/null +++ b/README.md @@ -0,0 +1,47 @@ +# played/workflows + +Reusable Gitea Actions workflows for the played ecosystem. + +## `build-deploy-game.yml` + +Drives the standard four-stage `build-api-core → deploy-api-core → build-web → deploy-web` pipeline for a played game. + +### Usage + +Each game's `.gitea/workflows/deploy.yml`: + +```yaml +name: Build & Deploy +run-name: ${{ gitea.actor }} is deploying + +on: + push: + branches: [main] + workflow_dispatch: + +jobs: + build-deploy: + uses: played/workflows/.gitea/workflows/build-deploy-game.yml@main + with: + game-id: + secrets: inherit +``` + +### Required caller secrets + +`secrets: inherit` makes all the calling repo's secrets available. The workflow reads: + +| Secret | Purpose | +| ------ | ------- | +| `BUILD_ENV` | Full prod `.env` contents. Used as a Docker build secret (`secret-files: env=...`) AND written to `~/-secrets/.env` on the deploy VM. | +| `NPMRC` | `~/.npmrc` content with `@played:registry=...` + auth tokens. | +| `REGISTRY_USER` / `REGISTRY_TOKEN` | Gitea container registry creds. | +| `PLAYED_HOST` / `PLAYED_USER` / `PLAYED_PORT` / `PLAYED_SSH_KEY` | Deploy target SSH. | +| `STEP_CA_PROVISIONER_PASSWORD` | For the `cert-init` container in `compose.production.yml`. | + +### Assumptions + +- The repo lives at `git.unom.io/played/` (matches `${{ gitea.repository }}`). +- The VM working dir is `~/` (the deploy step `cd`s there). +- Secrets dir is `~/-secrets/`. +- `compose.production.yml` defines `api-core` and `web` services, both with `--env-file ~/-secrets/.env`.