summaryrefslogtreecommitdiff
path: root/docs/handbook/ci/overview.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/handbook/ci/overview.md')
-rw-r--r--docs/handbook/ci/overview.md494
1 files changed, 494 insertions, 0 deletions
diff --git a/docs/handbook/ci/overview.md b/docs/handbook/ci/overview.md
new file mode 100644
index 0000000000..19d42cfe2a
--- /dev/null
+++ b/docs/handbook/ci/overview.md
@@ -0,0 +1,494 @@
+# CI Infrastructure — Overview
+
+## Purpose
+
+The `ci/` directory contains the Continuous Integration infrastructure for the Project Tick monorepo.
+It provides reproducible builds, automated code quality checks, commit message validation,
+pull request lifecycle management, and code ownership enforcement — all orchestrated through
+Nix expressions and JavaScript-based GitHub Actions scripts.
+
+The CI system is designed around three core principles:
+
+1. **Reproducibility** — Pinned Nix dependencies ensure identical builds across environments
+2. **Conventional Commits** — Enforced commit message format for automated changelog generation
+3. **Ownership-driven review** — CODEOWNERS-style file ownership with automated review routing
+
+---
+
+## Directory Structure
+
+```
+ci/
+├── OWNERS # Code ownership file (CODEOWNERS format)
+├── README.md # CI README with local testing instructions
+├── default.nix # Nix CI entry point — treefmt, codeowners-validator, shell
+├── pinned.json # Pinned Nixpkgs + treefmt-nix revisions (npins format)
+├── update-pinned.sh # Script to update pinned.json via npins
+├── supportedBranches.js # Branch classification logic for CI decisions
+├── codeowners-validator/ # Builds codeowners-validator from source (Go)
+│ ├── default.nix # Nix derivation for codeowners-validator
+│ ├── owners-file-name.patch # Patch: custom OWNERS file path via OWNERS_FILE env var
+│ └── permissions.patch # Patch: remove write-access check (not needed for non-native CODEOWNERS)
+└── github-script/ # JavaScript CI scripts for GitHub Actions
+ ├── run # CLI entry point for local testing (commander-based)
+ ├── lint-commits.js # Commit message linter (Conventional Commits)
+ ├── prepare.js # PR preparation: mergeability, branch targeting, touched files
+ ├── reviews.js # Review lifecycle: post, dismiss, minimize bot reviews
+ ├── get-pr-commit-details.js # Extract commit SHAs, subjects, changed paths via git
+ ├── withRateLimit.js # GitHub API rate limiting with Bottleneck
+ ├── package.json # Node.js dependencies (@actions/core, @actions/github, bottleneck, commander)
+ ├── package-lock.json # Lockfile for reproducible npm installs
+ ├── shell.nix # Nix dev shell for github-script (Node.js + gh CLI)
+ ├── README.md # Local testing documentation
+ ├── .editorconfig # Editor configuration
+ ├── .gitignore # Git ignore rules
+ └── .npmrc # npm configuration
+```
+
+---
+
+## How CI Works End-to-End
+
+### 1. Triggering
+
+CI runs are triggered by GitHub Actions workflows (defined in `.github/workflows/`) when
+pull requests are opened, updated, or merged against supported branches. The `supportedBranches.js`
+module classifies branches to determine which checks to run.
+
+### 2. Environment Setup
+
+The CI environment is bootstrapped via `ci/default.nix`, which:
+
+- Reads pinned dependency revisions from `ci/pinned.json`
+- Fetches the exact Nixpkgs tarball at the pinned commit
+- Imports `treefmt-nix` for code formatting
+- Builds the `codeowners-validator` tool with Project Tick–specific patches
+- Exposes a development shell with all CI tools available
+
+```nix
+# ci/default.nix — entry point
+let
+ pinned = (builtins.fromJSON (builtins.readFile ./pinned.json)).pins;
+in
+{
+ system ? builtins.currentSystem,
+ nixpkgs ? null,
+}:
+let
+ nixpkgs' =
+ if nixpkgs == null then
+ fetchTarball {
+ inherit (pinned.nixpkgs) url;
+ sha256 = pinned.nixpkgs.hash;
+ }
+ else
+ nixpkgs;
+
+ pkgs = import nixpkgs' {
+ inherit system;
+ config = { };
+ overlays = [ ];
+ };
+```
+
+### 3. Code Formatting (treefmt)
+
+The `default.nix` configures `treefmt-nix` with multiple formatters:
+
+| Formatter | Purpose | Configuration |
+|-------------|--------------------------------------|----------------------------------------------|
+| `actionlint` | GitHub Actions workflow linting | Enabled, no custom config |
+| `biome` | JavaScript/TypeScript formatting | Single quotes, no semicolons, no JSON format |
+| `keep-sorted`| Sorted list enforcement | Enabled, no custom config |
+| `nixfmt` | Nix expression formatting | Uses `pkgs.nixfmt` |
+| `yamlfmt` | YAML formatting | Retains line breaks |
+| `zizmor` | GitHub Actions security scanning | Enabled, no custom config |
+
+Biome is configured with specific style rules:
+
+```nix
+programs.biome = {
+ enable = true;
+ validate.enable = false;
+ settings.formatter = {
+ useEditorconfig = true;
+ };
+ settings.javascript.formatter = {
+ quoteStyle = "single";
+ semicolons = "asNeeded";
+ };
+ settings.json.formatter.enabled = false;
+};
+settings.formatter.biome.excludes = [
+ "*.min.js"
+];
+```
+
+### 4. Commit Linting
+
+When a PR is opened or updated, `ci/github-script/lint-commits.js` validates every commit
+message against the Conventional Commits specification. It checks:
+
+- Format: `type(scope): subject`
+- No `fixup!`, `squash!`, or `amend!` prefixes (must be rebased before merge)
+- No trailing period on subject line
+- Lowercase first letter in subject
+- Known scopes matching monorepo project directories
+
+The supported types are:
+
+```javascript
+const CONVENTIONAL_TYPES = [
+ 'build', 'chore', 'ci', 'docs', 'feat', 'fix',
+ 'perf', 'refactor', 'revert', 'style', 'test',
+]
+```
+
+And the known scopes correspond to monorepo directories:
+
+```javascript
+const KNOWN_SCOPES = [
+ 'archived', 'cgit', 'ci', 'cmark', 'corebinutils',
+ 'forgewrapper', 'genqrcode', 'hooks', 'images4docker',
+ 'json4cpp', 'libnbtplusplus', 'meshmc', 'meta', 'mnv',
+ 'neozip', 'tomlplusplus', 'repo', 'deps',
+]
+```
+
+### 5. PR Preparation and Validation
+
+The `ci/github-script/prepare.js` script handles PR lifecycle:
+
+1. **Mergeability check** — Polls GitHub's mergeability computation with exponential backoff
+ (5s, 10s, 20s, 40s, 80s retries)
+2. **Branch classification** — Classifies base and head branches using `supportedBranches.js`
+3. **Base branch suggestion** — For WIP branches, computes the optimal base branch by comparing
+ merge-base commit distances across `master` and all release branches
+4. **Merge conflict detection** — If the PR has conflicts, uses the head SHA directly; otherwise
+ uses the merge commit SHA
+5. **Touched file detection** — Identifies which CI-relevant paths were modified:
+ - `ci` — any file under `ci/`
+ - `pinned` — `ci/pinned.json` specifically
+ - `github` — any file under `.github/`
+
+### 6. Review Lifecycle Management
+
+The `ci/github-script/reviews.js` module manages bot reviews:
+
+- **`postReview()`** — Posts or updates a review with a tracking comment tag
+ (`<!-- projt review key: <key>; resolved: false -->`)
+- **`dismissReviews()`** — Dismisses, minimizes (marks as outdated), or resolves bot reviews
+ when the underlying issue is fixed
+- Reviews are tagged with a `reviewKey` to allow multiple independent review concerns
+ on the same PR
+
+### 7. Rate Limiting
+
+All GitHub API calls go through `ci/github-script/withRateLimit.js`, which uses the
+Bottleneck library for request throttling:
+
+- Read requests: controlled by a reservoir updated from the GitHub rate limit API
+- Write requests (`POST`, `PUT`, `PATCH`, `DELETE`): minimum 1 second between calls
+- The reservoir keeps 1000 spare requests for other concurrent jobs
+- Reservoir is refreshed every 60 seconds
+- Requests to `github.com` (not the API), `/rate_limit`, and `/search/` endpoints bypass throttling
+
+### 8. Code Ownership Validation
+
+The `ci/codeowners-validator/` builds a patched version of the
+[codeowners-validator](https://github.com/mszostok/codeowners-validator) tool:
+
+- Fetched from GitHub at a specific pinned commit
+- Two patches applied:
+ - `owners-file-name.patch` — Adds support for custom CODEOWNERS file path via `OWNERS_FILE` env var
+ - `permissions.patch` — Removes the write-access permission check (not needed since Project Tick
+ uses an `OWNERS` file rather than GitHub's native `CODEOWNERS`)
+
+This validates the `ci/OWNERS` file against the actual repository structure and GitHub
+organization membership.
+
+---
+
+## Component Interaction Flow
+
+```
+┌─────────────────────────────────────────┐
+│ GitHub Actions Workflow │
+│ (.github/workflows/*.yml) │
+└──────────────┬──────────────────────────┘
+ │ triggers
+ ▼
+┌──────────────────────────────────────────┐
+│ ci/default.nix │
+│ ┌─────────┐ ┌──────────────────────┐ │
+│ │pinned. │ │ treefmt-nix │ │
+│ │json │──│ (formatting checks) │ │
+│ └─────────┘ └──────────────────────┘ │
+│ ┌──────────────────────┐ │
+│ │ codeowners-validator │ │
+│ │ (OWNERS validation) │ │
+│ └──────────────────────┘ │
+└──────────────┬───────────────────────────┘
+ │ also triggers
+ ▼
+┌──────────────────────────────────────────┐
+│ ci/github-script/ │
+│ ┌────────────────┐ ┌───────────────┐ │
+│ │ prepare.js │ │ lint-commits │ │
+│ │ (PR validation) │ │ (commit msg) │ │
+│ └───────┬────────┘ └──────┬────────┘ │
+│ │ │ │
+│ ┌───────▼────────┐ ┌──────▼────────┐ │
+│ │ reviews.js │ │ supported │ │
+│ │ (bot reviews) │ │ Branches.js │ │
+│ └───────┬────────┘ └───────────────┘ │
+│ │ │
+│ ┌───────▼────────┐ │
+│ │ withRateLimit │ │
+│ │ (API throttle) │ │
+│ └────────────────┘ │
+└──────────────────────────────────────────┘
+```
+
+---
+
+## Key Design Decisions
+
+### Why Nix for CI?
+
+Nix ensures that every CI run uses the exact same versions of tools, compilers, and
+libraries. The `pinned.json` file locks specific commits of Nixpkgs and treefmt-nix,
+eliminating "works on my machine" problems.
+
+### Why a custom OWNERS file?
+
+GitHub's native CODEOWNERS has limitations:
+- Must be in `.github/CODEOWNERS`, `CODEOWNERS`, or `docs/CODEOWNERS`
+- Requires repository write access for all listed owners
+- Cannot be extended with custom validation
+
+Project Tick uses `ci/OWNERS` with the same glob pattern syntax but adds:
+- Custom file path support (via the `OWNERS_FILE` environment variable)
+- No write-access requirement (via the permissions patch)
+- Integration with the codeowners-validator for structural validation
+
+### Why Bottleneck for rate limiting?
+
+GitHub Actions can run many jobs in parallel, and each job makes API calls. Without
+throttling, a large CI run could exhaust the GitHub API rate limit (5000 requests/hour
+for authenticated requests). Bottleneck provides:
+- Concurrency control (1 concurrent request by default)
+- Reservoir-based rate limiting (dynamically updated from the API)
+- Separate throttling for mutative requests (1 second minimum between writes)
+
+### Why local testing support?
+
+The `ci/github-script/run` CLI allows developers to test CI scripts locally before
+pushing. This accelerates development and reduces CI feedback loops:
+
+```bash
+cd ci/github-script
+nix-shell # sets up Node.js + dependencies
+gh auth login # authenticate with GitHub
+./run lint-commits YongDo-Hyun Project-Tick 123
+./run prepare YongDo-Hyun Project-Tick 123
+```
+
+---
+
+## Pinned Dependencies
+
+The CI system pins two external Nix sources:
+
+| Dependency | Source | Branch | Purpose |
+|-------------|----------------------------------------------|--------------------|--------------------------------|
+| `nixpkgs` | `github:NixOS/nixpkgs` | `nixpkgs-unstable` | Base package set for CI tools |
+| `treefmt-nix`| `github:numtide/treefmt-nix` | `main` | Multi-formatter orchestrator |
+
+Pins are stored in `ci/pinned.json` in npins v5 format:
+
+```json
+{
+ "pins": {
+ "nixpkgs": {
+ "type": "Git",
+ "repository": {
+ "type": "GitHub",
+ "owner": "NixOS",
+ "repo": "nixpkgs"
+ },
+ "branch": "nixpkgs-unstable",
+ "revision": "bde09022887110deb780067364a0818e89258968",
+ "url": "https://github.com/NixOS/nixpkgs/archive/bde09022887110deb780067364a0818e89258968.tar.gz",
+ "hash": "13mi187zpa4rw680qbwp7pmykjia8cra3nwvjqmsjba3qhlzif5l"
+ },
+ "treefmt-nix": {
+ "type": "Git",
+ "repository": {
+ "type": "GitHub",
+ "owner": "numtide",
+ "repo": "treefmt-nix"
+ },
+ "branch": "main",
+ "revision": "e96d59dff5c0d7fddb9d113ba108f03c3ef99eca",
+ "url": "https://github.com/numtide/treefmt-nix/archive/e96d59dff5c0d7fddb9d113ba108f03c3ef99eca.tar.gz",
+ "hash": "02gqyxila3ghw8gifq3mns639x86jcq079kvfvjm42mibx7z5fzb"
+ }
+ },
+ "version": 5
+}
+```
+
+To update pins:
+
+```bash
+cd ci/
+./update-pinned.sh
+```
+
+This runs `npins --lock-file pinned.json update` to fetch the latest revisions.
+
+---
+
+## Node.js Dependencies (github-script)
+
+The `ci/github-script/package.json` declares:
+
+```json
+{
+ "private": true,
+ "dependencies": {
+ "@actions/core": "1.11.1",
+ "@actions/github": "6.0.1",
+ "bottleneck": "2.19.5",
+ "commander": "14.0.3"
+ }
+}
+```
+
+| Package | Version | Purpose |
+|-------------------|----------|-----------------------------------------------|
+| `@actions/core` | `1.11.1` | GitHub Actions core utilities (logging, outputs) |
+| `@actions/github` | `6.0.1` | GitHub API client (Octokit wrapper) |
+| `bottleneck` | `2.19.5` | Rate limiting / request throttling |
+| `commander` | `14.0.3` | CLI argument parsing for local `./run` tool |
+
+These versions are kept in sync with the
+[actions/github-script](https://github.com/actions/github-script) action.
+
+---
+
+## Nix Dev Shell
+
+The `ci/github-script/shell.nix` provides a development environment for working on
+the CI scripts locally:
+
+```nix
+{
+ system ? builtins.currentSystem,
+ pkgs ? (import ../../ci { inherit system; }).pkgs,
+}:
+
+pkgs.callPackage (
+ {
+ gh,
+ importNpmLock,
+ mkShell,
+ nodejs,
+ }:
+ mkShell {
+ packages = [
+ gh
+ importNpmLock.hooks.linkNodeModulesHook
+ nodejs
+ ];
+
+ npmDeps = importNpmLock.buildNodeModules {
+ npmRoot = ./.;
+ inherit nodejs;
+ };
+ }
+) { }
+```
+
+This gives you:
+- `nodejs` — Node.js runtime
+- `gh` — GitHub CLI for authentication
+- `importNpmLock.hooks.linkNodeModulesHook` — Automatically links `node_modules` from the Nix store
+
+---
+
+## Outputs Exposed by default.nix
+
+The `ci/default.nix` exposes the following attributes:
+
+| Attribute | Type | Description |
+|----------------------|-----------|--------------------------------------------------|
+| `pkgs` | Nixpkgs | The pinned Nixpkgs package set |
+| `fmt.shell` | Derivation| Dev shell with treefmt formatter available |
+| `fmt.pkg` | Derivation| The treefmt wrapper binary |
+| `fmt.check` | Derivation| A check derivation that fails if formatting drifts|
+| `codeownersValidator`| Derivation| Patched codeowners-validator binary |
+| `shell` | Derivation| Combined CI dev shell (fmt + codeowners-validator)|
+
+```nix
+rec {
+ inherit pkgs fmt;
+ codeownersValidator = pkgs.callPackage ./codeowners-validator { };
+
+ shell = pkgs.mkShell {
+ packages = [
+ fmt.pkg
+ codeownersValidator
+ ];
+ };
+}
+```
+
+---
+
+## Integration with Root Flake
+
+The root `flake.nix` provides:
+
+- Dev shells for all supported systems (`aarch64-linux`, `x86_64-linux`, etc.)
+- A formatter (`nixfmt-rfc-style`)
+- The CI `default.nix` is imported indirectly via the flake for Nix-based CI runs
+
+```nix
+{
+ description = "Project Tick is a project dedicated to providing developers
+ with ease of use and users with long-lasting software.";
+
+ inputs = {
+ nixpkgs.url = "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz";
+ };
+ ...
+}
+```
+
+---
+
+## Summary of CI Checks
+
+| Check | Tool / Script | Scope |
+|--------------------------|---------------------------|------------------------------------|
+| Code formatting | treefmt (biome, nixfmt, yamlfmt, actionlint, zizmor) | All source files |
+| Commit message format | `lint-commits.js` | All commits in a PR |
+| PR mergeability | `prepare.js` | Every PR |
+| Base branch targeting | `prepare.js` + `supportedBranches.js` | WIP → development PRs |
+| Code ownership validity | `codeowners-validator` | `ci/OWNERS` file |
+| GitHub Actions security | `zizmor` (via treefmt) | `.github/workflows/*.yml` |
+| Sorted list enforcement | `keep-sorted` (via treefmt)| Files with keep-sorted markers |
+
+---
+
+## Related Documentation
+
+- [Nix Infrastructure](nix-infrastructure.md) — Deep dive into the Nix expressions
+- [Commit Linting](commit-linting.md) — Commit message conventions and validation rules
+- [PR Validation](pr-validation.md) — Pull request checks and lifecycle management
+- [Branch Strategy](branch-strategy.md) — Branch naming, classification, and release branches
+- [CODEOWNERS](codeowners.md) — Ownership file format and validation
+- [Formatting](formatting.md) — Code formatting configuration and tools
+- [Rate Limiting](rate-limiting.md) — GitHub API rate limiting strategy