Files
KisaniCal/docs/CICD.md
2026-07-03 02:01:11 +03:00

76 lines
3.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CI/CD Flow
How a change travels from a local branch to TestFlight, and where the gates are.
```mermaid
flowchart TD
A["feature/* branch · local<br/><i>pre-push hook blocks main</i>"]
B["Pull request → develop<br/><i>develop is the default branch</i>"]
C["CI · ci.yml (macOS runner)<br/><i>xcodebuild build + test</i>"]
D{"Merge gate<br/>CI green + 1 approval"}
E["Pull request develop → main<br/><i>same gate</i>"]
F["Release · release.yml<br/><i>archive → IPA → TestFlight</i>"]
A -->|git push · open PR| B
B -->|PR triggers CI| C
C -->|status check: build-and-test| D
D -->|promote when ready| E
E -->|on merge to main| F
```
## Steps
1. **`feature/*` branch (local).** Branch off `develop`. A local
`.git/hooks/pre-push` hook rejects any direct push to `main`, so nothing
reaches the protected branch outside a PR.
2. **PR → `develop`.** `develop` is the default branch and the integration
target for all feature work.
3. **CI runs** — [`.gitea/workflows/ci.yml`](../.gitea/workflows/ci.yml) on the
self-hosted **macOS runner**. It runs `xcodebuild build` then
`xcodebuild test` (the `KisaniCalTests` target on an iOS simulator). The
result is published as a commit status named **`build-and-test`**.
4. **Merge gate.** Gitea branch protection blocks the merge until:
- the `build-and-test` status check is **green**,
- there is **≥ 1 approval**,
- there are no rejected reviews, and
- the branch is up to date with its base.
The same gate guards both `develop` and `main`.
5. **Promote `develop` → `main`** via a second PR when a release is ready. It
passes through the identical gate.
6. **Release runs** — [`.gitea/workflows/release.yml`](../.gitea/workflows/release.yml)
fires **only** on push to `main` (i.e. after a PR merges). It archives,
exports an IPA via [`ExportOptions.plist`](../ExportOptions.plist), and
uploads to **TestFlight** (currently a commented-out placeholder awaiting the
App Store Connect API-key secrets).
## Two automation halves
- **CI** (steps 34) gates **every** PR into `main`/`develop`.
- **Release** (step 6) runs **only** on `main`.
Blue/manual steps are actions you take; CI and Release run unattended on the
runner.
## Requirements & gotchas
- **Runner labels.** Both workflows use `runs-on: [self-hosted, macOS]`. The
registered runner must carry **both** labels or jobs queue forever. Check at
Settings → Actions → Runners.
- **Status-check name.** Branch protection requires a check literally named
`build-and-test` (the CI job name). If the rendered context differs, update
the rule (`scripts/gitea-setup.sh`, `STATUS_CONTEXT`).
- **Simulator.** The runner needs an installed iOS runtime (Xcode → Settings →
Components) — CI auto-selects the first available iPhone simulator.
- **Signing.** CI builds with `CODE_SIGNING_ALLOWED=NO`. The Release job needs a
distribution cert + profile in the runner's login keychain.
- **Build number.** `CURRENT_PROJECT_VERSION` in `project.yml` must increase for
every TestFlight upload — App Store Connect rejects a repeated build number.
See also [CONTRIBUTING.md](../CONTRIBUTING.md) for the branch workflow.