diff --git a/.github/workflows/handbook-build-check.yaml b/.github/workflows/handbook-build-check.yaml index 093997db..45e89853 100644 --- a/.github/workflows/handbook-build-check.yaml +++ b/.github/workflows/handbook-build-check.yaml @@ -2,7 +2,7 @@ name: Handbook Build Check # PR-only build verification for Dockerfile.handbook + the Goldens-assembled # screenshots. Does NOT push to Docker Hub and does NOT deploy — that -# remains the job of handbook-deploy.yaml (develop push → DEV → PRD). +# remains the job of handbook-deploy.yaml (staging push → DEV, develop push → PRD). # # Path filter covers everything that goes into the handbook image: # - docs/handbook/** handbook HTML, README, en/de subtrees diff --git a/.github/workflows/handbook-deploy.yaml b/.github/workflows/handbook-deploy.yaml index c1a26d83..f114ec5c 100644 --- a/.github/workflows/handbook-deploy.yaml +++ b/.github/workflows/handbook-deploy.yaml @@ -1,9 +1,15 @@ name: Handbook CI/CD -# Single deploy pipeline for the handbook image: every push to `develop` -# (with handbook-relevant paths) builds the image once and rolls it out -# to BOTH the DEV and PRD endpoints sequentially. PRD only runs when DEV -# finishes green, so a broken handbook can't reach production. +# Per-branch handbook deploy pipeline, one environment per branch: +# push to `staging` → build from staging → deploy DEV (dev-handbook.realunit.app) +# push to `develop` → build from develop → deploy PRD (handbook.realunit.app) +# +# DEV and PRD are independent runs keyed by the pushed branch; they no +# longer share a single run that fans out to both. The "DEV is green before +# PRD ships" guarantee is now provided by the branch-promotion flow itself: +# handbook content reaches `develop` only after it has been on `staging` +# (auto-staging-pr.yaml opens the staging → develop PR), i.e. after it was +# built and smoke-tested on DEV. Promoting to develop is what triggers PRD. # # This is a deliberate dev/prd-coupling exception scoped to the handbook # alone — the wallet app itself still follows the strict develop→main @@ -11,11 +17,12 @@ name: Handbook CI/CD # # All build/deploy/smoke logic lives in the reusable workflow # .github/workflows/handbook.yaml. This file only wires the per-env -# parameters and the DEV-must-pass ordering. +# parameters (source ref, image tag, smoke URL, deploy secrets) and routes +# the pushed branch to its environment via the per-job `if:` guards below. on: push: - branches: [develop] + branches: [staging, develop] paths: - "docs/handbook/**" - "test/goldens/screens/**" @@ -37,21 +44,28 @@ on: permissions: contents: read -# Serialize handbook deploys so a manual workflow_dispatch can't race a -# concurrent develop push: both would build :beta in parallel, the later -# build would win on Docker Hub, and dfxdev / dfxprd could end up pulling -# different images depending on timing. cancel-in-progress is false so a -# mid-rollout deploy is never killed (we'd otherwise risk leaving DEV -# halfway through and PRD never started). +# One concurrency lane PER BRANCH so a staging (DEV) deploy and a develop +# (PRD) deploy never serialize against — or cancel — each other. Within a +# single lane a manual workflow_dispatch still can't race a push: both would +# build the same env's tag in parallel, the later build would win on Docker +# Hub, and the target server could pull either depending on timing. +# cancel-in-progress is false so a mid-rollout deploy is never killed (we'd +# otherwise risk recreating the container halfway through). concurrency: - group: handbook-deploy + group: handbook-deploy-${{ github.ref_name }} cancel-in-progress: false jobs: + # Push to staging → DEV. Distinct image tag (:beta) from PRD (:latest) so a + # staging build can never clobber the develop build on Docker Hub (both + # used to push :beta, which raced whenever the two branches were pushed + # close together). deploy-dev: + if: github.ref_name == 'staging' uses: ./.github/workflows/handbook.yaml with: environment: DEV + ref: staging docker_tag: dfxswiss/realunit-app-handbook:beta smoke_url: https://dev-handbook.realunit.app/healthz secrets: @@ -62,12 +76,14 @@ jobs: DEPLOY_USER: ${{ secrets.DEPLOY_DEV_USER }} DEPLOY_HOST: ${{ secrets.DEPLOY_DEV_HOST }} + # Push to develop → PRD. deploy-prd: - needs: deploy-dev + if: github.ref_name == 'develop' uses: ./.github/workflows/handbook.yaml with: environment: PRD - docker_tag: dfxswiss/realunit-app-handbook:beta + ref: develop + docker_tag: dfxswiss/realunit-app-handbook:latest smoke_url: https://handbook.realunit.app/healthz secrets: DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} diff --git a/.github/workflows/handbook.yaml b/.github/workflows/handbook.yaml index d7b9d579..9c11603d 100644 --- a/.github/workflows/handbook.yaml +++ b/.github/workflows/handbook.yaml @@ -4,9 +4,11 @@ name: Handbook reusable CI/CD # Docker Hub, and tells the target server to pull + recreate the container. # # Caller (handbook-deploy.yaml) provides the per-environment parameters -# (tag, smoke URL, deploy secrets) so the deploy logic itself lives in -# exactly one place. The caller fans this workflow out to DEV first and -# then PRD with `needs:` ordering. +# (source ref, tag, smoke URL, deploy secrets) so the deploy logic itself +# lives in exactly one place. Each pushed branch is an independent caller +# run — staging → DEV, develop → PRD — so there is no DEV→PRD `needs:` +# ordering here; "DEV green before PRD" comes from the staging→develop +# promotion flow (see handbook-deploy.yaml header). # # Mirrors infrastructure/templates/ssh-deploy-*.yaml from DFXServer/server. @@ -17,8 +19,12 @@ on: description: "Target environment label (dev | prd) — used in job name + smoke log lines" required: true type: string + ref: + description: "Git ref of THIS repo to build the handbook from — the pushed branch (staging for DEV, develop for PRD). Determines the deployed handbook 'Stand'." + required: true + type: string docker_tag: - description: "Full Docker image tag, e.g. dfxswiss/realunit-app-handbook:beta" + description: "Full Docker image tag, e.g. dfxswiss/realunit-app-handbook:beta (DEV) / :latest (PRD)" required: true type: string smoke_url: @@ -56,16 +62,26 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + # Build the handbook from the environment's source branch: staging + # for DEV, develop for PRD (passed by handbook-deploy.yaml as the + # pushed branch). This ref governs the deployed handbook content; + # the DFXswiss/api checkout below is a SEPARATE, intentionally + # develop-pinned source for the mail previews and does not vary + # with this input. + ref: ${{ inputs.ref }} # RealUnit mail previews are the single source of truth in DFXswiss/api # (scripts/generate-realunit-previews.js). We pull them in at build time # instead of checking them into this repo, so a change to a template or # i18n string in the api repo flows into the handbook image on the next - # build without a manual sync PR. A handbook-relevant push to develop - # (or a manual workflow_dispatch on handbook-deploy.yaml in this repo) - # rebuilds the image and re-pulls api@develop here — so mail-template - # changes in the api repo only flow in after such a push/dispatch in - # this repo. There is NO auto-dispatch from the api repo. + # build without a manual sync PR. A handbook-relevant push to staging + # (→DEV) or develop (→PRD) — or a manual workflow_dispatch on + # handbook-deploy.yaml in this repo — rebuilds the image and re-pulls + # api@develop here — so mail-template changes in the api repo only flow + # in after such a push/dispatch in this repo. There is NO auto-dispatch + # from the api repo. The api ref stays `develop` for both environments + # (it does not track the handbook's staging/develop split). - name: Check out DFXswiss/api at develop into _api-checkout/ uses: actions/checkout@v4 with: diff --git a/README.md b/README.md index ffaf02d9..6feaef2b 100644 --- a/README.md +++ b/README.md @@ -169,7 +169,7 @@ Tier 1 specs live under `test/integration/**` and run inside the same `flutter t | `auto-tag.yaml` | Push `develop` | Creates the next `vX.Y.Z` patch tag (PATCH = previous + 1, MINOR/MAJOR from pubspec floor) | | `release.yaml` | Tag `v*` · manual | Single store-release pipeline. Guard job routes by PATCH: `vX.Y.0` → production candidate (GitHub release, prerelease: false); `vX.Y.Z` (Z >= 1) → internal release (GitHub pre-release). Both lanes deploy Android + iOS to Play Internal + TestFlight; production promotion stays manual in the store backends. | | `store-metadata.yaml` | Push `main` under `*/fastlane/metadata/**` or `ios/fastlane/screenshots/**` · manual `workflow_dispatch` | Sync App Store + Play Store listing text + screenshots without rebuilding the app. A `preflight` gate rejects `FIXME-` placeholders and over-length text fields before either store upload runs. | -| `handbook-deploy.yaml` | Push `develop` under `docs/handbook/**`, `Dockerfile.handbook`, `handbook.nginx.conf`, `handbook.htpasswd`, or the workflow files · manual | Builds the handbook image once and rolls it out to DEV (`:beta`) then PRD (`:latest`) sequentially via the reusable `handbook.yaml` — PRD only runs after DEV is green | +| `handbook-deploy.yaml` | Push `staging` (→ DEV) or `develop` (→ PRD) under `docs/handbook/**`, `Dockerfile.handbook`, `handbook.nginx.conf`, `handbook.htpasswd`, or the workflow files · manual | Builds the handbook image from the pushed branch and deploys it to the matching environment via the reusable `handbook.yaml`: `staging` → DEV (`:beta`, dev-handbook.realunit.app), `develop` → PRD (`:latest`, handbook.realunit.app). Independent per-branch runs with distinct image tags; "DEV green before PRD" is enforced by the staging→develop promotion flow, not an in-run `needs:` | | `handbook.yaml` | Called by `handbook-deploy.yaml` (`workflow_call`) | Reusable build → Docker Hub push → server pull/recreate → smoke check, parameterised per environment | ## Release versioning diff --git a/docs/handbook/README.md b/docs/handbook/README.md index c882ed19..4dd4951c 100644 --- a/docs/handbook/README.md +++ b/docs/handbook/README.md @@ -36,8 +36,8 @@ Workflow: regeneriert auf dfx01 und committet die neuen PNGs als `github-actions[bot]` zurück auf den Branch (siehe [`../visual-regression-tests.md`](../visual-regression-tests.md)) -4. Pullen → Handbook-Deploy pickt die neue Baseline beim nächsten - develop-Push automatisch auf. +4. Pullen → der nächste Handbook-Deploy zeigt die neue Baseline automatisch + (Push auf `staging` → DEV bzw. `develop` → PRD). ## Selektive Läufe (Teilmenge) @@ -113,12 +113,16 @@ divergieren Image-Stand und Source-of-Truth. ### Trigger -Der Handbook-Deploy läuft bei einem `push` auf `develop` mit Änderungen -unter handbook-relevanten Pfaden (siehe `handbook-deploy.yaml`) oder bei -einem manuellen `workflow_dispatch` auf `handbook-deploy.yaml` in -**diesem** Repo. Eine reine Mail-Template-, i18n- oder Generator-Änderung -im api-Repo löst **keinen** automatischen Rebuild aus — sie fliesst erst -mit dem nächsten Handbook-Deploy hier rein. +Der Handbook-Deploy läuft pro Branch in genau ein Environment: ein `push` +auf `staging` deployt nach **DEV** (`dev-handbook.realunit.app`), ein `push` +auf `develop` nach **PRD** (`handbook.realunit.app`) — jeweils mit Änderungen +unter handbook-relevanten Pfaden (siehe `handbook-deploy.yaml`) oder per +manuellem `workflow_dispatch` auf `handbook-deploy.yaml` in **diesem** Repo +(das Ziel-Environment richtet sich nach dem dispatchten Branch). DEV und PRD +nutzen getrennte Image-Tags (`:beta` bzw. `:latest`), damit sich staging- und +develop-Builds nicht gegenseitig überschreiben. Eine reine Mail-Template-, +i18n- oder Generator-Änderung im api-Repo löst **keinen** automatischen +Rebuild aus — sie fliesst erst mit dem nächsten Handbook-Deploy hier rein. Wer eine reine Mail-Änderung sofort live haben will, hat zwei Optionen im realunit-app-Repo: diff --git a/docs/handbook/de/index.html b/docs/handbook/de/index.html index ac69db45..85887157 100644 --- a/docs/handbook/de/index.html +++ b/docs/handbook/de/index.html @@ -897,10 +897,11 @@
Pipeline: Page-Edit → flutter test --update-goldens test/goldens/screens/<feature>
- auf dfx01 (Hardware-Determinismus) → neue Baseline committen → Push auf
- develop triggert handbook-deploy.yaml → Docker-Build
- assembliert die 52 Slots aus test/goldens/screens/ → DEV-Image,
- dann PRD-Image, beide via Cloudflare Tunnel.
+ auf dfx01 (Hardware-Determinismus) → neue Baseline committen →
+ handbook-deploy.yaml baut das Docker-Image aus dem gepushten Branch
+ und assembliert die 52 Slots aus test/goldens/screens/ → Push auf
+ staging deployt das DEV-Image, Push auf develop das
+ PRD-Image, beide via Cloudflare Tunnel.
develop mit
- handbook-relevanten Pfaden oder manueller
- workflow_dispatch auf handbook-deploy.yaml
- im realunit-app-Repo) reingezogen.
+ Handbook-Deploy (Push auf staging → DEV bzw.
+ develop → PRD mit handbook-relevanten Pfaden oder
+ manueller workflow_dispatch auf
+ handbook-deploy.yaml im realunit-app-Repo) reingezogen.