Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/handbook-build-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
46 changes: 31 additions & 15 deletions .github/workflows/handbook-deploy.yaml
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
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
# separation.
#
# 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/**"
Expand All @@ -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:
Expand All @@ -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 }}
Expand Down
34 changes: 25 additions & 9 deletions .github/workflows/handbook.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 12 additions & 8 deletions docs/handbook/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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:
Expand Down
17 changes: 9 additions & 8 deletions docs/handbook/de/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -897,10 +897,11 @@ <h3 style="margin-top: 0">Single Source of Truth</h3>
<div class="callout info">
<p>
<b>Pipeline:</b> Page-Edit → <code>flutter test --update-goldens test/goldens/screens/&lt;feature&gt;</code>
auf dfx01 (Hardware-Determinismus) → neue Baseline committen → Push auf
<code>develop</code> triggert <code>handbook-deploy.yaml</code> → Docker-Build
assembliert die 52 Slots aus <code>test/goldens/screens/</code> → DEV-Image,
dann PRD-Image, beide via Cloudflare Tunnel.
auf dfx01 (Hardware-Determinismus) → neue Baseline committen →
<code>handbook-deploy.yaml</code> baut das Docker-Image aus dem gepushten Branch
und assembliert die 52 Slots aus <code>test/goldens/screens/</code> → Push auf
<code>staging</code> deployt das DEV-Image, Push auf <code>develop</code> das
PRD-Image, beide via Cloudflare Tunnel.
</p>
</div>
</section>
Expand Down Expand Up @@ -2407,10 +2408,10 @@ <h2><span class="num">M</span>E-Mails</h2>
Eine Änderung an Mail-Vorlage, i18n-Übersetzung oder
Generator-Skript im api-Repo löst hier <b>keinen</b> automatischen
Rebuild aus. Die neue Version wird mit dem nächsten
Handbook-Deploy (Push auf <code>develop</code> mit
handbook-relevanten Pfaden oder manueller
<code>workflow_dispatch</code> auf <code>handbook-deploy.yaml</code>
im realunit-app-Repo) reingezogen.
Handbook-Deploy (Push auf <code>staging</code> → DEV bzw.
<code>develop</code> → PRD mit handbook-relevanten Pfaden oder
manueller <code>workflow_dispatch</code> auf
<code>handbook-deploy.yaml</code> im realunit-app-Repo) reingezogen.
</p>
</details>

Expand Down
Loading