Skip to content

Commit 1afb730

Browse files
committed
docs: split CI docs into focused files, add musl/feature/TLS details
- Split monolithic README.md into workflows.md, build.md, releases.md - README.md is now a short index linking to the three docs - Document musl static linking, CC/CXX env vars, rustls TLS backend - Document release feature flag and why tracy/dhat are excluded - Add retagging workflow and binary download examples
1 parent 8054bc4 commit 1afb730

File tree

4 files changed

+212
-158
lines changed

4 files changed

+212
-158
lines changed

docs/ci/README.md

Lines changed: 7 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -1,160 +1,9 @@
1-
# CI/CD Pipeline
1+
# CI/CD
22

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.
44

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 |

docs/ci/build.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Build Profiles & Features
2+
3+
## Cargo Features
4+
5+
Features are defined in `src/bin/Cargo.toml`:
6+
7+
| Feature | What it includes | Used in |
8+
|---|---|---|
9+
| `dashboard` | Web dashboard (Axum server) | Default, release builds |
10+
| `tracy` | Tracy profiler client | Local profiling only |
11+
| `dhat` | Heap profiler | Local profiling only |
12+
| `release` | All features suitable for distribution (`dashboard`) | Release builds |
13+
14+
Release builds use `--features release` (scoped to `-p ferrumc`) instead of `--all-features`. This is intentional — `tracy` and `dhat` are profiling tools that include C/C++ code incompatible with musl static linking (`tracy-client-sys` uses glibc-specific functions like `__snprintf_chk` and `__memcpy_chk`). When adding new features intended for release builds, add them to the `release` feature list.
15+
16+
## Build Profiles
17+
18+
| Profile | Use case | Key settings |
19+
|---|---|---|
20+
| `dev` | Local development | Default + per-package optimizations for heavy deps (yazi, bevy_ecs, tokio) |
21+
| `release` | Standard release | Cargo defaults |
22+
| `production` | CI release builds | release + `strip`, `lto`, `opt-level = 3`, `codegen-units = 1` |
23+
| `profiling` | Tracy profiling | release + `debug = true` |
24+
| `hyper` | Maximum performance | production + `panic = "abort"`, no overflow checks, no debug assertions |
25+
26+
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.
27+
28+
## Static Linking (Linux)
29+
30+
Linux binaries are statically linked via musl libc, producing fully self-contained binaries that run on any Linux distribution regardless of glibc version. This avoids the common `GLIBC_X.XX not found` error on older distros.
31+
32+
Requirements for musl builds:
33+
- `musl-tools` package (installed automatically in CI)
34+
- `CC=musl-gcc` and `CXX=g++` environment variables (set in CI build step)
35+
- `rustls` instead of `native-tls` for TLS (see below)
36+
37+
### TLS Backend
38+
39+
The project uses `rustls` (pure Rust TLS) instead of `native-tls` (OpenSSL) for the `reqwest` HTTP client. This is required for musl static builds — `native-tls` depends on system OpenSSL which cannot be statically linked with musl. The `rustls` backend has no native dependencies and works across all targets.
40+
41+
Configured in the root `Cargo.toml`:
42+
```toml
43+
reqwest = { version = "0.13.1", features = ["json", "rustls", "blocking", "http2"], default-features = false }
44+
```

docs/ci/releases.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Releases & Versioning
2+
3+
## Versioning
4+
5+
FerrumC follows [Semantic Versioning](https://semver.org/) (SemVer).
6+
7+
### Version Format
8+
9+
**`MAJOR.MINOR.PATCH`** — e.g., `1.4.2`
10+
11+
| Component | When to bump | Example |
12+
|---|---|---|
13+
| **MAJOR** | Breaking changes — config format changes, protocol rewrites, removed features | `1.0.0``2.0.0` |
14+
| **MINOR** | New features, backwards compatible — new commands, new packet support, new config options | `1.0.0``1.1.0` |
15+
| **PATCH** | Bug fixes only — no new features, no breaking changes | `1.0.0``1.0.1` |
16+
17+
### Pre-release Versions
18+
19+
A `0.x.x` major version means the project is not yet stable — any release can contain breaking changes.
20+
21+
Pre-release labels are appended with a hyphen to indicate the release isn't final:
22+
23+
| Label | Meaning | Example |
24+
|---|---|---|
25+
| `alpha` | Early preview. Features incomplete, expect breakage. | `v0.2.0-alpha.1` |
26+
| `beta` | Feature complete but not fully tested. | `v0.2.0-beta.1` |
27+
| `rc` | Release Candidate. "Believed to be ready, testing before making it official." | `v0.2.0-rc1` |
28+
| *(none)* | Final release. Stable, tested, ready for use. | `v0.2.0` |
29+
30+
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.
31+
32+
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).
33+
34+
### Versioning in Practice
35+
36+
FerrumC is currently at `0.1.0` (pre-stable). A realistic release flow:
37+
38+
1. Development happens on `master`, PRs get merged.
39+
2. A set of changes is deemed worth releasing.
40+
3. Tag `v0.1.0-rc1` to test the release pipeline and binaries.
41+
4. If everything works, tag `v0.1.0` as the final release.
42+
5. Bug fix needed? Fix on master, tag `v0.1.1`.
43+
6. New feature? Tag `v0.2.0`.
44+
7. Massive breaking change (stable protocol, config rewrite)? Tag `v1.0.0`.
45+
46+
## Creating a Release
47+
48+
1. Ensure `master` is in a releasable state (CI green).
49+
2. Tag the commit:
50+
```bash
51+
git tag v0.1.0 # final release
52+
git tag v0.1.0-rc1 # release candidate (for testing)
53+
```
54+
3. Push the tag:
55+
```bash
56+
git push origin v0.1.0
57+
```
58+
4. The release workflow runs automatically: validate → build (4 platforms) → publish GitHub Release.
59+
5. If validation or build fails, fix the issue on master, then tag again (e.g., `v0.1.0-rc2`).
60+
61+
## Retagging a Failed Release
62+
63+
To move a tag to a new commit (e.g., after fixing a build issue):
64+
65+
```bash
66+
git tag -d v0.1.0-rc2 # delete locally
67+
git push origin :refs/tags/v0.1.0-rc2 # delete from remote
68+
# fix the issue, commit, then:
69+
git tag v0.1.0-rc2 # retag on current HEAD
70+
git push origin v0.1.0-rc2
71+
```
72+
73+
Delete any draft/failed GitHub Release from the Releases page if one was created.
74+
75+
## Downloading Release Binaries
76+
77+
Latest release URL via GitHub API:
78+
```bash
79+
# Latest stable release (skips pre-releases)
80+
curl -s https://api.github.com/repos/ferrumc-rs/ferrumc/releases/latest
81+
82+
# Direct download (predictable URL pattern)
83+
curl -sL https://github.com/ferrumc-rs/ferrumc/releases/download/v0.1.0/ferrumc-v0.1.0-x86_64-unknown-linux-musl.tar.gz -o ferrumc.tar.gz
84+
```

docs/ci/workflows.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Workflows
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.
4+
5+
## `rust.yml` — PR & Push CI
6+
7+
**Triggers:** Pull requests to `master`, pushes to `master`, manual `workflow_dispatch`.
8+
9+
**Concurrency:** Grouped by PR head ref. New pushes to the same PR cancel in-progress runs.
10+
11+
| Job | Runner | What it does |
12+
|---|---|---|
13+
| **Formatting and Security** | `ubuntu-latest` | `cargo fmt --check`, `cargo clippy -D warnings`, `cargo audit` |
14+
| **Run Tests** | `ubuntu-latest` | `cargo nextest run` with `--all-targets --all-features` (excludes benchmarks) |
15+
16+
Both jobs run in parallel with no dependency between them.
17+
18+
Tests use `--all-features` to ensure gated features (dashboard, tracy, etc.) are always tested. This is safe on the gnu target used by CI — the musl incompatibility with tracy only affects release builds.
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 (with `--all-features` on gnu target) |
27+
| **Build Release** | 4-platform matrix | Builds with `--profile production --features release`, 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+
### 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+
### Platform-Specific Packaging
47+
48+
| Platform | Archive tool | Checksum tool |
49+
|---|---|---|
50+
| Linux | `tar -czf` | `sha256sum` |
51+
| macOS | `tar -czf` | `shasum -a 256` (macOS lacks `sha256sum`) |
52+
| Windows | PowerShell `Compress-Archive` (runs under `shell: pwsh`) | PowerShell `Get-FileHash` |
53+
54+
Windows steps use `shell: pwsh` explicitly since the workflow default shell is `bash`.
55+
56+
## Caching
57+
58+
Jobs use `Swatinem/rust-cache@v2`. Cache keys are set up intentionally:
59+
60+
- **`rust.yml` formatting job**: default key (job-name based). Compiles to `target/debug/` (no `--target` flag).
61+
- **`rust.yml` test job**: `shared-key: "ferrumc-test"`. Compiles to `target/x86_64-unknown-linux-gnu/debug/` (explicit `--target` flag).
62+
- **`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.
63+
- **`release.yml` build-release jobs**: `shared-key: "ferrumc"`. Separate from CI caches since these use `--profile production` on different platforms.
64+
65+
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.
66+
67+
### Cache Performance
68+
69+
With warm caches, typical CI times are:
70+
- Formatting and Security: ~30-40s
71+
- Run Tests: ~50-60s
72+
73+
Cold cache (first run or after Cargo.lock changes): ~2-3 minutes per job.
74+
75+
## Suppressed Advisories
76+
77+
`cargo audit` ignores `RUSTSEC-2023-0071`. If this advisory is resolved upstream, the ignore can be removed from the workflow.

0 commit comments

Comments
 (0)