|
1 | | -# CI/CD Pipeline |
| 1 | +# CI/CD |
2 | 2 |
|
3 | | -FerrumC uses GitHub Actions for continuous integration and release automation. The pipeline is split into two workflows: one for PR validation and one for tagged releases. |
| 3 | +Documentation for the CI/CD pipeline, build system, and release process. |
4 | 4 |
|
5 | | -## Workflows |
6 | | - |
7 | | -### `rust.yml` — PR & Push CI |
8 | | - |
9 | | -**Triggers:** Pull requests to `master`, pushes to `master`, manual `workflow_dispatch`. |
10 | | - |
11 | | -**Concurrency:** Grouped by PR head ref. New pushes to the same PR cancel in-progress runs. |
12 | | - |
13 | | -| Job | Runner | What it does | |
14 | | -|---|---|---| |
15 | | -| **Formatting and Security** | `ubuntu-latest` | `cargo fmt --check`, `cargo clippy -D warnings`, `cargo audit` | |
16 | | -| **Run Tests** | `ubuntu-latest` | `cargo nextest run` with `--all-targets --all-features` (excludes benchmarks) | |
17 | | - |
18 | | -Both jobs run in parallel with no dependency between them. |
19 | | - |
20 | | -### `release.yml` — Tagged Release Pipeline |
21 | | - |
22 | | -**Triggers:** Push of tags matching `v*` (e.g., `v1.0.0`, `v0.2.0-rc1`). |
23 | | - |
24 | | -| Job | Runner | What it does | |
25 | | -|---|---|---| |
26 | | -| **Validate** | `ubuntu-latest` | Same checks as CI: fmt, clippy, nextest | |
27 | | -| **Build Release** | 4-platform matrix | Builds with `--profile production --all-features`, packages binaries, generates SHA256 checksums | |
28 | | -| **Publish Release** | `ubuntu-latest` | Creates GitHub Release with auto-generated notes, attaches all archives and checksums | |
29 | | - |
30 | | -#### Build Matrix |
31 | | - |
32 | | -| OS | Target | Archive Format | |
33 | | -|---|---|---| |
34 | | -| `ubuntu-latest` | `x86_64-unknown-linux-musl` | `.tar.gz` | |
35 | | -| `ubuntu-24.04-arm` | `aarch64-unknown-linux-musl` | `.tar.gz` | |
36 | | -| `windows-latest` | `x86_64-pc-windows-msvc` | `.zip` | |
37 | | -| `macos-14` | `aarch64-apple-darwin` | `.tar.gz` | |
38 | | - |
39 | | -#### Release Artifact Naming |
40 | | - |
41 | | -Archives: `ferrumc-{tag}-{target}.tar.gz` (or `.zip` for Windows) |
42 | | -Checksums: `ferrumc-{tag}-{target}.tar.gz.sha256` (or `.zip.sha256`) |
43 | | - |
44 | | -Example: `ferrumc-v1.0.0-x86_64-unknown-linux-musl.tar.gz` |
45 | | - |
46 | | -Linux binaries are statically linked via musl libc, so they run on any Linux distribution regardless of glibc version. The `musl-tools` package is installed during CI builds. The project uses `rustls-tls` (pure Rust) instead of `native-tls` (OpenSSL) to avoid native library dependencies. |
47 | | - |
48 | | -#### Platform-Specific Packaging |
49 | | - |
50 | | -| Platform | Archive tool | Checksum tool | |
51 | | -|---|---|---| |
52 | | -| Linux | `tar -czf` | `sha256sum` | |
53 | | -| macOS | `tar -czf` | `shasum -a 256` (macOS lacks `sha256sum`) | |
54 | | -| Windows | PowerShell `Compress-Archive` (runs under `shell: pwsh`) | PowerShell `Get-FileHash` | |
55 | | - |
56 | | -Windows steps use `shell: pwsh` explicitly since the workflow default shell is `bash`. |
57 | | - |
58 | | -## Build Profiles |
59 | | - |
60 | | -| Profile | Use case | Key settings | |
61 | | -|---|---|---| |
62 | | -| `dev` | Local development | Default + per-package optimizations for heavy deps (yazi, bevy_ecs, tokio) | |
63 | | -| `release` | Standard release | Cargo defaults | |
64 | | -| `production` | CI release builds | release + `strip`, `lto`, `opt-level = 3`, `codegen-units = 1` | |
65 | | -| `profiling` | Tracy profiling | release + `debug = true` | |
66 | | -| `hyper` | Maximum performance | production + `panic = "abort"`, no overflow checks, no debug assertions | |
67 | | - |
68 | | -The `production` profile is used by the release workflow. It's similar to `hyper` but keeps panic unwinding (no `panic = "abort"`), which is safer for a server binary — a panic unwinds and logs a backtrace instead of hard-crashing. |
69 | | - |
70 | | -## Caching |
71 | | - |
72 | | -Jobs use `Swatinem/rust-cache@v2`. Cache keys are set up intentionally: |
73 | | - |
74 | | -- **`rust.yml` formatting job**: default key (job-name based). Compiles to `target/debug/` (no `--target` flag). |
75 | | -- **`rust.yml` test job**: `shared-key: "ferrumc-test"`. Compiles to `target/x86_64-unknown-linux-gnu/debug/` (explicit `--target` flag). |
76 | | -- **`release.yml` validate job**: `shared-key: "ferrumc-test"`. Reuses the test job's cache from `rust.yml`, since both compile with the same target and features. Clippy does a small incremental rebuild for `target/debug/`, but all dependencies are already cached. |
77 | | -- **`release.yml` build-release jobs**: `shared-key: "ferrumc"`. Separate from CI caches since these use `--profile production` on different platforms. |
78 | | - |
79 | | -The formatting and test jobs in `rust.yml` must NOT share a cache key — they compile to different target directories, and GitHub Actions cache is immutable (first write wins). Sharing a key causes whichever job saves second to permanently lose its artifacts. |
80 | | - |
81 | | -### Cache performance |
82 | | - |
83 | | -With warm caches, typical CI times are: |
84 | | -- Formatting and Security: ~30-40s |
85 | | -- Run Tests: ~50-60s |
86 | | - |
87 | | -Cold cache (first run or after Cargo.lock changes): ~2-3 minutes per job. |
88 | | - |
89 | | -## Versioning |
90 | | - |
91 | | -FerrumC follows [Semantic Versioning](https://semver.org/) (SemVer). |
92 | | - |
93 | | -### Version Format |
94 | | - |
95 | | -**`MAJOR.MINOR.PATCH`** — e.g., `1.4.2` |
96 | | - |
97 | | -| Component | When to bump | Example | |
98 | | -|---|---|---| |
99 | | -| **MAJOR** | Breaking changes — config format changes, protocol rewrites, removed features | `1.0.0` → `2.0.0` | |
100 | | -| **MINOR** | New features, backwards compatible — new commands, new packet support, new config options | `1.0.0` → `1.1.0` | |
101 | | -| **PATCH** | Bug fixes only — no new features, no breaking changes | `1.0.0` → `1.0.1` | |
102 | | - |
103 | | -### Pre-release Versions |
104 | | - |
105 | | -A `0.x.x` major version means the project is not yet stable — any release can contain breaking changes. |
106 | | - |
107 | | -Pre-release labels are appended with a hyphen to indicate the release isn't final: |
108 | | - |
109 | | -| Label | Meaning | Example | |
110 | | -|---|---|---| |
111 | | -| `alpha` | Early preview. Features incomplete, expect breakage. | `v0.2.0-alpha.1` | |
112 | | -| `beta` | Feature complete but not fully tested. | `v0.2.0-beta.1` | |
113 | | -| `rc` | Release Candidate. "We think this is ready, testing before making it official." | `v0.2.0-rc1` | |
114 | | -| *(none)* | Final release. Stable, tested, ready for use. | `v0.2.0` | |
115 | | - |
116 | | -The typical progression is: **alpha → beta → rc → release**. Not all stages are required — most releases go straight from development to `rc` → final, or skip `rc` entirely for small patches. |
117 | | - |
118 | | -If a bug is found in `rc1`, the fix gets tagged as `rc2`. Once the RC is validated, the final version is tagged (same commit or a new one). |
119 | | - |
120 | | -### Versioning in Practice |
121 | | - |
122 | | -FerrumC is currently at `0.1.0` (pre-stable). A realistic release flow looks like: |
123 | | - |
124 | | -1. Development happens on `master`, PRs get merged. |
125 | | -2. A set of changes is deemed worth releasing. |
126 | | -3. Tag `v0.1.0-rc1` to test the release pipeline and binaries. |
127 | | -4. If everything works, tag `v0.1.0` as the final release. |
128 | | -5. Bug fix needed? Fix on master, tag `v0.1.1`. |
129 | | -6. New feature? Tag `v0.2.0`. |
130 | | -7. Massive breaking change (stable protocol, config rewrite)? Tag `v1.0.0`. |
131 | | - |
132 | | -## Creating a Release |
133 | | - |
134 | | -1. Ensure `master` is in a releasable state (CI green). |
135 | | -2. Tag the commit: |
136 | | - ```bash |
137 | | - git tag v0.1.0 # final release |
138 | | - git tag v0.1.0-rc1 # release candidate (for testing) |
139 | | - ``` |
140 | | -3. Push the tag: |
141 | | - ```bash |
142 | | - git push origin v0.1.0 |
143 | | - ``` |
144 | | -4. The release workflow runs automatically: validate → build (4 platforms) → publish GitHub Release. |
145 | | -5. If validation or build fails, fix the issue on master, then tag again (e.g., `v0.1.0-rc2`). |
146 | | - |
147 | | -### Deleting a Bad Tag |
148 | | - |
149 | | -To delete a tag that was pushed by mistake or needs to be redone: |
150 | | - |
151 | | -```bash |
152 | | -git tag -d v0.1.0-rc1 # delete locally |
153 | | -git push origin :refs/tags/v0.1.0-rc1 # delete from remote |
154 | | -``` |
155 | | - |
156 | | -Then delete the draft/failed GitHub Release from the Releases page if one was created. |
157 | | - |
158 | | -## Suppressed Advisories |
159 | | - |
160 | | -`cargo audit` ignores `RUSTSEC-2023-0071`. If this advisory is resolved upstream, the ignore can be removed from the workflow. |
| 5 | +| Document | What it covers | |
| 6 | +|---|---| |
| 7 | +| [Workflows](workflows.md) | GitHub Actions workflows, job structure, caching strategy | |
| 8 | +| [Build Profiles & Features](build.md) | Cargo profiles, feature flags, static linking, TLS backend | |
| 9 | +| [Releases](releases.md) | Versioning (SemVer), creating releases, retagging, downloading binaries | |
0 commit comments