From 2291b6bb42d0e5730203c5649b6e1de6108f68e7 Mon Sep 17 00:00:00 2001 From: Justin Chung <20733699+justin13888@users.noreply.github.com> Date: Thu, 11 Jun 2026 01:44:32 -0400 Subject: [PATCH] ci: enforce conventional commits (convco) and pin release tooling (mise) --- .github/workflows/ci.yml | 20 ++++++++++++++++-- .versionrc | 44 ++++++++++++++++++++++++++++++++++++++++ justfile | 22 ++++++++++++++++++++ lefthook.yml | 11 ++++++++++ mise.toml | 15 ++++++++++++++ 5 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 .versionrc create mode 100644 mise.toml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 30ee3d1..d54bc32 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,6 +69,22 @@ jobs: - 'detekt.yml' - '.github/workflows/ci.yml' + # Enforce Conventional Commits across a PR's commits (convco skips merge commits). + # Runs on pull_request only; on push to master it is skipped (the `required` gate + # treats skipped as pass). Tooling is pinned in the root mise.toml. + commit-lint: + name: Commit lint (convco) + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Set up mise tools (convco) + uses: jdx/mise-action@v2 + - name: Check commits follow Conventional Commits + run: convco check --first-parent --ignore-reverts ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} + rust: name: Rust (fmt + clippy + build) needs: changes @@ -300,12 +316,12 @@ jobs: required: name: required if: always() - needs: [changes, rust, rust-test, rust-cross, web, docs, vision, markdown, kotlin] + needs: [changes, commit-lint, rust, rust-test, rust-cross, web, docs, vision, markdown, kotlin] runs-on: ubuntu-latest steps: - name: Verify required jobs succeeded run: | - for r in "${{ needs.rust.result }}" "${{ needs.rust-cross.result }}" \ + for r in "${{ needs.commit-lint.result }}" "${{ needs.rust.result }}" "${{ needs.rust-cross.result }}" \ "${{ needs.web.result }}" \ "${{ needs.docs.result }}" "${{ needs.vision.result }}" \ "${{ needs.markdown.result }}" "${{ needs.kotlin.result }}"; do diff --git a/.versionrc b/.versionrc new file mode 100644 index 0000000..2083b41 --- /dev/null +++ b/.versionrc @@ -0,0 +1,44 @@ +# convco configuration (auto-discovered as `.versionrc`). +# Drives `convco check` (commit linting), `convco version` (next semver), and +# `convco changelog` (CHANGELOG.md generation). YAML or JSON are both accepted. +host: github.com +owner: Capsulsaurus +repository: Capsule + +# Pre-1.0: breaking changes bump the minor (0.x), not the major. +preMajor: true + +# Changelog sections. The commit types already in use across the repo all get a +# home; scope is left optional (conventional commits permit scope-less subjects, +# e.g. `chore: bump dependencies`). +types: + - type: feat + section: Features + hidden: false + - type: fix + section: Bug Fixes + hidden: false + - type: perf + section: Performance + hidden: false + - type: refactor + section: Refactoring + hidden: false + - type: build + section: Build System + hidden: false + - type: ci + section: Continuous Integration + hidden: false + - type: docs + section: Documentation + hidden: false + - type: style + section: Styling + hidden: true + - type: test + section: Tests + hidden: true + - type: chore + section: Chores + hidden: true diff --git a/justfile b/justfile index 59a5790..6ef15a1 100644 --- a/justfile +++ b/justfile @@ -399,6 +399,28 @@ lint-md: lint-check-md: bunx markdownlint-cli2 +# ── Commits / release ──────────────────────────────────────────────────────── +# convco enforces Conventional Commits (https://www.conventionalcommits.org). +# `commit-check` validates a single in-progress message (commit-msg hook); +# `check-commits` validates a range (pre-push and CI on PRs). convco skips merge +# commits in a range on its own; the single-message path skips the auto-generated +# merge/revert/fixup/squash subjects that tooling — not the author — writes. + +[group('release')] +commit-check msg_file: + #!/usr/bin/env bash + set -euo pipefail + # Skip the auto-generated subjects tooling writes (merge/revert/fixup/squash); + # everything else must be conventional. `--strip` drops comments/whitespace. + case "$(sed -n '1p' "{{ msg_file }}")" in + Merge\ *|Revert\ *|fixup!\ *|squash!\ *) exit 0 ;; + esac + convco check --from-stdin --strip < "{{ msg_file }}" + +[group('release')] +check-commits base="origin/master": + convco check --first-parent --ignore-reverts {{ base }}..HEAD + # ── Setup ──────────────────────────────────────────────────────────────────── [group('setup')] diff --git a/lefthook.yml b/lefthook.yml index b0484f8..6c6760c 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -61,6 +61,11 @@ pre-commit: pre-push: parallel: false commands: + # Priority 0: Conventional Commits check over the range being pushed. + check-commits: + priority: 0 + run: just check-commits + # Priority 1: all format/lint checks (read-only, no writes) format-check-rust: priority: 1 @@ -128,3 +133,9 @@ pre-push: priority: 2 glob: "capsule-web/**/*.{ts,tsx,js,jsx}" run: just test-web + +# Validate the message of the commit being written (Conventional Commits). +commit-msg: + commands: + convco: + run: just commit-check {1} diff --git a/mise.toml b/mise.toml new file mode 100644 index 0000000..5a5de62 --- /dev/null +++ b/mise.toml @@ -0,0 +1,15 @@ +# Repo-wide dev tooling, pinned so local and CI install identical versions. +# Install everything with: mise install (run from the repo root) +# +# Scope: the release/commit toolchain shared across every package. Language +# toolchains stay where they belong — Rust in /rust-toolchain.toml, the Apple +# client's Swift tools in capsule-swift/mise.toml (mise layers child configs on +# top of this one). +[tools] +just = "1" +lefthook = "2" +# convco isn't in the mise registry. Its GitHub release assets aren't named in a way the +# `ubi` backend can resolve on Linux (ambiguous ubuntu/deb zips), so use the `cargo` +# backend — it fetches a prebuilt binary via cargo-binstall when possible and otherwise +# builds from source, working uniformly on every OS in CI and locally. +"cargo:convco" = "0.6.4"