Replace every remaining reference to the old Gitea infrastructure with the new GitHub-hosted equivalents across all documentation, wiki pages, test files, and historical ticket summaries. - README.md: CI badge, clone URL, releases link, CI/CD section, project structure - docs/wiki/CICD-Pipeline.md: full rewrite for GitHub Actions + ghcr.io - docs/wiki/Home.md: CI badge, releases link, phase status, tech stack - docs/wiki/Troubleshooting.md: rewrite CI troubleshooting for GitHub Actions - docs/architecture/README.md: update CI/CD pipeline diagram - AGENTS.md: CI/CD section, environment references - PLAN.md: directory structure, pipeline table - SECURITY_AUDIT.md: mark C3 and L4 findings as resolved - ticket-git-cliff-changelog.md: workflow path updated - tickets/ci-runner-speed-optimization.md: image registry updated - 2026-hackathon_AgenticFeature.md: workflow path updated - tests: workflow path assertions updated in all three test files
254 lines
9.8 KiB
Markdown
254 lines
9.8 KiB
Markdown
# CI/CD Pipeline
|
|
|
|
## Infrastructure
|
|
|
|
| Component | URL | Notes |
|
|
|-----------|-----|-------|
|
|
| GitHub | `https://github.com/msicie/apollo_nxt-trcaa` | Git server and CI/CD platform |
|
|
| GitHub Actions | Native to GitHub | Hosted runners (`ubuntu-latest`, `macos-latest`, `macos-13`) |
|
|
| ghcr.io | `ghcr.io/msicie/` | GitHub Container Registry for pre-baked CI images |
|
|
|
|
---
|
|
|
|
## Pre-baked Builder Images
|
|
|
|
CI build and test jobs use pre-baked Docker images pushed to `ghcr.io/msicie/`. These images bake in all system dependencies (Tauri libs, Node.js, Rust toolchain, cross-compilers) so that CI jobs skip package installation entirely.
|
|
|
|
| Image | Used by jobs | Contents |
|
|
|-------|-------------|----------|
|
|
| `ghcr.io/msicie/trcaa-linux-amd64:rust1.88-node22` | `rust-test`, `build-linux-amd64` | Rust 1.88 + rustfmt + clippy + Tauri amd64 libs + Node.js 22 |
|
|
| `ghcr.io/msicie/trcaa-windows-cross:rust1.88-node22` | `build-windows-amd64` | Rust 1.88 + mingw-w64 + NSIS + Node.js 22 |
|
|
| `ghcr.io/msicie/trcaa-linux-arm64:rust1.88-node22` | `build-linux-arm64` | Rust 1.88 + aarch64 cross-toolchain + arm64 multiarch libs + Node.js 22 |
|
|
|
|
**Rebuild triggers:** Rust toolchain version bump, webkit2gtk/gtk major version change, Node.js major version change.
|
|
|
|
**How to rebuild images:**
|
|
1. Trigger `build-images.yml` via Actions → Build CI Docker Images → Run workflow
|
|
2. Confirm all 3 images appear in `ghcr.io/msicie/`
|
|
3. Only then merge workflow changes that depend on the new image contents
|
|
|
|
---
|
|
|
|
## Cargo and npm Caching
|
|
|
|
All Rust and build jobs use `actions/cache@v4` to cache downloaded package artifacts.
|
|
|
|
**Cargo cache** (Rust jobs):
|
|
```yaml
|
|
- name: Cache cargo registry
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: |
|
|
~/.cargo/registry/index
|
|
~/.cargo/registry/cache
|
|
~/.cargo/git/db
|
|
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-cargo-
|
|
```
|
|
|
|
**npm cache** (frontend and build jobs):
|
|
```yaml
|
|
- name: Cache npm
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: ~/.npm
|
|
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-npm-
|
|
```
|
|
|
|
Cache keys for cross-compile jobs use a suffix to avoid collisions:
|
|
- Windows build: `${{ runner.os }}-cargo-windows-${{ hashFiles('**/Cargo.lock') }}`
|
|
- arm64 build: `${{ runner.os }}-cargo-arm64-${{ hashFiles('**/Cargo.lock') }}`
|
|
|
|
---
|
|
|
|
## Test Pipeline (`.github/workflows/test.yml`)
|
|
|
|
**Triggers:** Every push to `main`, `feature/**`, `bug/**`, `fix/**` branches; pull requests targeting `main`.
|
|
|
|
```
|
|
Jobs (run in parallel):
|
|
rust-test → cargo fmt --check
|
|
→ cargo clippy -- -D warnings
|
|
→ cargo test (64 tests)
|
|
frontend-test → npx tsc --noEmit
|
|
→ npm run test:run (Vitest tests)
|
|
```
|
|
|
|
**Docker image used:**
|
|
- `ghcr.io/msicie/trcaa-linux-amd64:rust1.88-node22` — both Rust and frontend steps
|
|
|
|
Job names `rust-test` and `frontend-test` must match exactly — these are the required status check names in branch protection on `main`.
|
|
|
|
---
|
|
|
|
## Release Pipeline (`.github/workflows/release.yml`)
|
|
|
|
**Triggers:** Push to `main` (auto-tag job), then release build/upload jobs run after `autotag` completes on `v*` tags.
|
|
|
|
Auto-tags are created by the `autotag` job using `git tag` + `git push`. Release jobs depend on `autotag` and run in parallel.
|
|
|
|
```
|
|
Jobs (run in parallel after autotag):
|
|
build-linux-amd64 → image: ghcr.io/msicie/trcaa-linux-amd64:rust1.88-node22
|
|
→ cargo tauri build (x86_64-unknown-linux-gnu)
|
|
→ {.deb, .rpm, .AppImage} uploaded to GitHub Release
|
|
→ fails fast if no Linux artifacts are produced
|
|
|
|
build-windows-amd64 → image: ghcr.io/msicie/trcaa-windows-cross:rust1.88-node22
|
|
→ cargo tauri build (x86_64-pc-windows-gnu) via mingw-w64
|
|
→ {.exe, .msi} uploaded to GitHub Release
|
|
→ fails fast if no Windows artifacts are produced
|
|
|
|
build-linux-arm64 → image: ghcr.io/msicie/trcaa-linux-arm64:rust1.88-node22
|
|
→ cargo tauri build (aarch64-unknown-linux-gnu)
|
|
→ {.deb, .rpm, .AppImage} uploaded to GitHub Release
|
|
→ fails fast if no Linux artifacts are produced
|
|
|
|
build-macos-arm64 → runs-on: macos-latest (Apple Silicon)
|
|
→ cargo tauri build (aarch64-apple-darwin) natively
|
|
→ {.dmg} uploaded to GitHub Release
|
|
→ existing same-name assets are deleted before upload (rerun-safe)
|
|
→ unsigned; after install run: xattr -cr /Applications/TRCAA.app
|
|
|
|
build-macos-intel → runs-on: macos-13 (Intel x86_64)
|
|
→ cargo tauri build (x86_64-apple-darwin) natively
|
|
→ {.dmg} uploaded to GitHub Release
|
|
```
|
|
|
|
**Windows cross-compile environment:**
|
|
```yaml
|
|
env:
|
|
TARGET: x86_64-pc-windows-gnu
|
|
CC_x86_64_pc_windows_gnu: x86_64-w64-mingw32-gcc
|
|
CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER: x86_64-w64-mingw32-gcc
|
|
OPENSSL_NO_VENDOR: "0"
|
|
OPENSSL_STATIC: "1"
|
|
```
|
|
|
|
**Artifacts per platform:**
|
|
- Linux amd64: `.deb`, `.rpm`, `.AppImage`
|
|
- Windows amd64: `.exe` (NSIS installer), `.msi`
|
|
- Linux arm64: `.deb`, `.rpm`, `.AppImage`
|
|
- macOS ARM64: `.dmg`
|
|
- macOS Intel: `.dmg`
|
|
|
|
---
|
|
|
|
## Build Images Workflow (`.github/workflows/build-images.yml`)
|
|
|
|
**Triggers:** Changes to `.docker/**` on `main`; manual `workflow_dispatch`.
|
|
|
|
Builds and pushes all three pre-baked CI images to `ghcr.io/msicie/`:
|
|
```
|
|
Jobs (all run on ubuntu-latest):
|
|
build-linux-amd64-image → .docker/Dockerfile.linux-amd64
|
|
→ ghcr.io/msicie/trcaa-linux-amd64:rust1.88-node22
|
|
|
|
build-windows-cross-image → .docker/Dockerfile.windows-cross
|
|
→ ghcr.io/msicie/trcaa-windows-cross:rust1.88-node22
|
|
|
|
build-linux-arm64-image → .docker/Dockerfile.linux-arm64
|
|
→ ghcr.io/msicie/trcaa-linux-arm64:rust1.88-node22
|
|
```
|
|
|
|
Authentication: `docker login ghcr.io -u ${{ github.actor }} --password-stdin <<< "${{ secrets.GITHUB_TOKEN }}"`. Requires `packages: write` permission.
|
|
|
|
---
|
|
|
|
## Branch Protection
|
|
|
|
`main` branch requires:
|
|
- All changes via PR
|
|
- 1 approving review
|
|
- CODEOWNER review (`@Shaun-Arman-VFK387_moto` and `@github-copilot`)
|
|
- Required status checks: `rust-test`, `frontend-test`
|
|
- `enforce_admins: false` — owner and admins can bypass with `gh pr merge --admin`
|
|
|
|
---
|
|
|
|
## Changelog Generation
|
|
|
|
Changelogs are generated automatically by **git-cliff** on every release.
|
|
Configuration lives in `cliff.toml` at the repo root.
|
|
|
|
### How it works
|
|
|
|
A `changelog` job in `release.yml` runs in parallel with the build jobs, immediately
|
|
after `autotag` completes:
|
|
|
|
1. Clones the full repo history with all tags (`--depth=2147483647` — git-cliff needs
|
|
every tag to compute version boundaries).
|
|
2. Downloads the git-cliff v2.7.0 static musl binary (~5 MB, no image change needed).
|
|
3. Runs `git-cliff --output CHANGELOG.md` to regenerate the full cumulative changelog.
|
|
4. Runs `git-cliff --latest --strip all` to produce release notes for the new tag only.
|
|
5. Updates the GitHub Release body with those notes via `gh release edit`.
|
|
6. Commits `CHANGELOG.md` to `main` with `[skip ci]` appended to the message.
|
|
The `[skip ci]` token prevents `release.yml` from re-triggering on the CHANGELOG commit.
|
|
7. Uploads `CHANGELOG.md` as a release asset (replaces any previous version).
|
|
|
|
### cliff.toml reference
|
|
|
|
| Setting | Value |
|
|
|---------|-------|
|
|
| `tag_pattern` | `v[0-9].*` |
|
|
| `ignore_tags` | `rc\|alpha\|beta` |
|
|
| `filter_unconventional` | `true` — non-conventional commits are dropped |
|
|
| Included types | `feat`, `fix`, `perf`, `docs`, `refactor` |
|
|
| Excluded types | `ci`, `chore`, `build`, `test`, `style` |
|
|
|
|
### Loop prevention
|
|
|
|
The `[skip ci]` suffix on the CHANGELOG commit message is recognised by GitHub Actions
|
|
and causes the workflow to be skipped for that push. Without it, the CHANGELOG commit
|
|
would trigger `release.yml` again, incrementing the patch version forever.
|
|
|
|
---
|
|
|
|
## Known Issues & Fixes
|
|
|
|
### Debian Multiarch Breaks arm64 Cross-Compile (`held broken packages`)
|
|
When using `rust:1.88-slim` (Debian Bookworm) with `dpkg --add-architecture arm64`, apt
|
|
resolves amd64 and arm64 simultaneously against the same mirror. The `binary-all` package
|
|
index is duplicated and certain `-dev` package pairs cannot be co-installed because they
|
|
don't declare `Multi-Arch: same`. This produces `E: Unable to correct problems, you have
|
|
held broken packages` and cannot be fixed by tweaking `sources.list` entries.
|
|
|
|
**Fix**: Use `ubuntu:22.04` as the container image (see `Dockerfile.linux-arm64`). Ubuntu
|
|
routes arm64 through `ports.ubuntu.com/ubuntu-ports` — a separate mirror from
|
|
`archive.ubuntu.com` (amd64). There are no cross-arch index overlaps and the dependency
|
|
resolver succeeds. Rust must be installed manually via `rustup`.
|
|
|
|
### `CI=true` Required by Tauri CLI
|
|
GitHub Actions sets `CI=true` by default — `cargo tauri build` accepts this without
|
|
modification. Prefix the command explicitly if your runner environment is unusual:
|
|
```yaml
|
|
- run: CI=true cargo tauri build --target $TARGET
|
|
```
|
|
|
|
### Windows DLL Export Ordinal Too Large
|
|
`/usr/bin/x86_64-w64-mingw32-ld: error: export ordinal too large: 106290`
|
|
|
|
Fix: `src-tauri/.cargo/config.toml`:
|
|
```toml
|
|
[target.x86_64-pc-windows-gnu]
|
|
rustflags = ["-C", "link-arg=-Wl,--exclude-all-symbols"]
|
|
```
|
|
|
|
### Release Artifacts Not Uploaded
|
|
|
|
**Cause:** `GITHUB_TOKEN` needs `contents: write` permission in the workflow.
|
|
|
|
Verify the `release.yml` permissions block includes:
|
|
```yaml
|
|
permissions:
|
|
contents: write
|
|
```
|
|
|
|
### Runner Group Restrictions (Enterprise)
|
|
GitHub Enterprise organizations may restrict which repositories can use GitHub-hosted
|
|
runners. If jobs are stuck in queue, contact your org admin to add the repository to the
|
|
allowed runner group, or temporarily make the repo public for the bootstrap run.
|