From 7ecd1ff871be29932ffcce1de50fd96355375e81 Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Fri, 24 Apr 2026 17:46:04 +0200 Subject: [PATCH] Split CI and deploy into separate workflows - .gitea/workflows/ci.yml: builds, tests, lints, and runs Lighthouse on every push and PR to main. Runs on arm64 self-hosted Gitea runner. - .gitea/workflows/deploy.yml: deploys to Hetzner on push to main or manual workflow_dispatch from Gitea UI. No Lighthouse (that's CI's job). Keeps the TBD-marker guard as a last-line safety check. Both workflows live on the same concurrency group so no two deploys race. On main push, CI and deploy run in parallel; CI is independent and non-blocking for the deploy step. Co-Authored-By: Claude Opus 4.7 (1M context) --- .gitea/workflows/ci.yml | 99 +++++++++++++++++++++++++++++++++++++ .gitea/workflows/deploy.yml | 92 ++++++++-------------------------- 2 files changed, 119 insertions(+), 72 deletions(-) create mode 100644 .gitea/workflows/ci.yml diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..b48ccee --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,99 @@ +# ----------------------------------------------------------------------------- +# cameleer-website — CI (build + test + lint + Lighthouse) +# +# Runs automatically on every push and every PR against main. Does NOT deploy — +# see deploy.yml for that. This workflow exists so every commit gets the full +# quality gate before it can reach production. +# +# Runner: self-hosted arm64 Gitea runner (act_runner). +# Adjust `runs-on` labels if your runner is registered under different tags. +# Architecture note: arm64 build, amd64 deploy is fine — Astro's output is +# plain static HTML/CSS/JS with no arch-specific bits. +# ----------------------------------------------------------------------------- + +name: ci + +on: + push: + pull_request: + branches: [main] + +jobs: + build-test: + runs-on: ubuntu-latest + timeout-minutes: 20 + env: + PUBLIC_AUTH_SIGNIN_URL: ${{ vars.PUBLIC_AUTH_SIGNIN_URL }} + PUBLIC_AUTH_SIGNUP_URL: ${{ vars.PUBLIC_AUTH_SIGNUP_URL }} + PUBLIC_SALES_EMAIL: ${{ vars.PUBLIC_SALES_EMAIL }} + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + # Lighthouse CI needs a Chrome/Chromium binary at runtime. Google Chrome + # has no Linux/arm64 build, so install distro Chromium and export its + # path. Handles both `chromium` (Debian) and `chromium-browser` (older + # Ubuntu) package names, and works whether sudo is present or absent + # (e.g. runner running as root). + - name: Install Chromium for Lighthouse CI + shell: bash + run: | + set -e + if command -v sudo >/dev/null 2>&1; then SUDO=sudo; else SUDO=; fi + + resolve_chromium() { + command -v chromium 2>/dev/null \ + || command -v chromium-browser 2>/dev/null \ + || true + } + + CHROME_BIN="$(resolve_chromium)" + if [ -z "$CHROME_BIN" ]; then + $SUDO apt-get update -qq + $SUDO apt-get install -y --no-install-recommends \ + chromium chromium-driver \ + || $SUDO apt-get install -y --no-install-recommends \ + chromium-browser chromium-chromedriver + CHROME_BIN="$(resolve_chromium)" + fi + + if [ -z "$CHROME_BIN" ]; then + echo "Failed to install a Chromium binary — Lighthouse CI cannot run." + exit 1 + fi + + echo "CHROME_PATH=$CHROME_BIN" >> "$GITHUB_ENV" + "$CHROME_BIN" --version || true + + - name: Install dependencies + run: npm ci + + - name: Run unit tests + run: npm test + + - name: Build site + run: npm run build + + - name: Guard — no TBD markers may ship in built HTML + run: | + if grep -rl 'TBD:' dist 2>/dev/null | grep -E '\.(html|svg)$'; then + echo "Built output contains unfilled markers." + echo "Fill in imprint.astro and privacy.astro operator fields before merging to main." + exit 1 + fi + + - name: Validate HTML + run: npm run lint:html + + - name: Check internal links + run: npm run lint:links + + - name: Lighthouse CI + env: + CHROME_PATH: ${{ env.CHROME_PATH }} + run: npx lhci autorun diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 53da863..d51136b 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -1,37 +1,36 @@ # ----------------------------------------------------------------------------- -# cameleer-website — Gitea Actions build + deploy +# cameleer-website — Deploy to Hetzner Webhosting L # -# Runner: self-hosted arm64 (Gitea Runner / act_runner). -# Deploy target: Hetzner Webhosting L (amd64). +# Runs ONLY on pushes to `main` and on manual dispatch from the Gitea UI. +# Does NOT run Lighthouse CI (that's in ci.yml — assume any commit that reached +# main already passed the full gate). Rebuilds fresh, runs the TBD guard, and +# rsyncs `dist/` to the origin over SSH with host-key pinning. # -# Architecture mismatch does NOT matter: Astro's output is static HTML/CSS/JS -# plus hashed assets. Nothing arch-specific ships in the bundle. Everything in -# this workflow — Node 20, rsync, ssh, curl, chromium — has native arm64. +# Runner: self-hosted arm64 Gitea runner. Adjust `runs-on` if your runner's +# labels differ. Deploy target is Hetzner amd64 — arch mismatch is a non-issue +# because the bundle is static HTML/CSS/JS. # -# The only non-trivial arm64 gotcha is Lighthouse CI: Google Chrome has no -# stable Linux/arm64 build, so we install the distro-packaged Chromium and -# hand its path to LHCI via CHROME_PATH. On amd64 runners this still works; -# the step is idempotent if Chromium is already present. -# -# `runs-on` labels: -# This file uses `ubuntu-latest`, which the default act_runner config maps -# to `catthehacker/ubuntu:act-latest` (multi-arch, has apt + sudo). If your -# runner is registered with different labels (e.g. `[self-hosted, arm64]`), -# update `runs-on` below accordingly. +# Required secrets (repo settings → Actions → Secrets): +# SFTP_HOST, SFTP_USER, SFTP_PATH, SFTP_KEY, SFTP_KNOWN_HOSTS +# Required variables (repo settings → Actions → Variables): +# PUBLIC_AUTH_SIGNIN_URL, PUBLIC_AUTH_SIGNUP_URL, PUBLIC_SALES_EMAIL # ----------------------------------------------------------------------------- -name: build-test-deploy +name: deploy on: push: branches: [main] - pull_request: - branches: [main] + workflow_dispatch: + +concurrency: + group: deploy-production + cancel-in-progress: false jobs: build: runs-on: ubuntu-latest - timeout-minutes: 20 + timeout-minutes: 15 env: PUBLIC_AUTH_SIGNIN_URL: ${{ vars.PUBLIC_AUTH_SIGNIN_URL }} PUBLIC_AUTH_SIGNUP_URL: ${{ vars.PUBLIC_AUTH_SIGNUP_URL }} @@ -45,45 +44,10 @@ jobs: node-version: '20' cache: 'npm' - # Lighthouse CI needs a Chrome/Chromium binary at runtime. Google Chrome - # has no Linux/arm64 build, so install distro Chromium and export its - # path. Handles both `chromium` (Debian) and `chromium-browser` (older - # Ubuntu) package names, and works whether sudo is present or absent - # (e.g. runner running as root). - - name: Install Chromium for Lighthouse CI - shell: bash - run: | - set -e - if command -v sudo >/dev/null 2>&1; then SUDO=sudo; else SUDO=; fi - - resolve_chromium() { - command -v chromium 2>/dev/null \ - || command -v chromium-browser 2>/dev/null \ - || true - } - - CHROME_BIN="$(resolve_chromium)" - if [ -z "$CHROME_BIN" ]; then - $SUDO apt-get update -qq - $SUDO apt-get install -y --no-install-recommends \ - chromium chromium-driver \ - || $SUDO apt-get install -y --no-install-recommends \ - chromium-browser chromium-chromedriver - CHROME_BIN="$(resolve_chromium)" - fi - - if [ -z "$CHROME_BIN" ]; then - echo "Failed to install a Chromium binary — Lighthouse CI cannot run." - exit 1 - fi - - echo "CHROME_PATH=$CHROME_BIN" >> "$GITHUB_ENV" - "$CHROME_BIN" --version || true - - name: Install dependencies run: npm ci - - name: Run unit tests + - name: Run unit tests (sanity check) run: npm test - name: Build site @@ -97,19 +61,7 @@ jobs: exit 1 fi - - name: Validate HTML - run: npm run lint:html - - - name: Check internal links - run: npm run lint:links - - - name: Lighthouse CI - env: - CHROME_PATH: ${{ env.CHROME_PATH }} - run: npx lhci autorun - - name: Upload dist artifact - if: github.ref == 'refs/heads/main' uses: actions/upload-artifact@v4 with: name: dist @@ -117,13 +69,9 @@ jobs: retention-days: 7 deploy: - if: github.ref == 'refs/heads/main' needs: build runs-on: ubuntu-latest timeout-minutes: 10 - concurrency: - group: deploy-production - cancel-in-progress: false steps: - name: Download dist artifact