ci: auto-release on version bump + PR changelog guard #11
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ci-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # PR-only guard: if a PR bumps the Cargo.toml version, it must also add a | |
| # matching CHANGELOG.md section. This never runs on `main` pushes (see the | |
| # event_name gate), so it can't block the release flow — only PRs. | |
| changelog: | |
| if: github.event_name == 'pull_request' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Require a changelog entry when the version is bumped | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| read_version() { grep -m1 '^version = ' | sed -E 's/^version = "([^"]+)".*/\1/'; } | |
| # Compare this PR's Cargo.toml version against the base branch's. | |
| git fetch --no-tags --depth=1 origin "${{ github.base_ref }}" | |
| head_version="$(read_version < Cargo.toml)" | |
| base_version="$(git show FETCH_HEAD:Cargo.toml | read_version)" | |
| if [ "$head_version" = "$base_version" ]; then | |
| echo "Version unchanged ($head_version); no changelog entry required." | |
| exit 0 | |
| fi | |
| echo "Version bump detected: $base_version -> $head_version" | |
| # Match a heading like '## [0.2.0]' or '## 0.2.0' (dots escaped). | |
| ver_re="${head_version//./\\.}" | |
| if grep -qE "^## \\[?${ver_re}(\\]|[[:space:]]|\$)" CHANGELOG.md; then | |
| echo "Found CHANGELOG.md entry for $head_version." | |
| else | |
| echo "::error file=CHANGELOG.md::Cargo.toml was bumped to $head_version but CHANGELOG.md has no '## [$head_version]' section. Add a changelog entry." | |
| exit 1 | |
| fi | |
| test: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - { os: macos-14, name: macos-arm64 } | |
| - { os: ubuntu-22.04, name: linux-x64 } | |
| - { os: windows-latest, name: windows-x64 } | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # wry (WebKitGTK backend) + tao (GTK windowing) need WebKitGTK + GTK | |
| # headers to compile on Linux. We pin webkit2gtk-4.1 because wry's | |
| # webkit2gtk-sys links the libsoup3 variant (4.0 uses libsoup2). | |
| - name: Install webview build deps (Linux) | |
| if: runner.os == 'Linux' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libwebkit2gtk-4.1-dev libgtk-3-dev | |
| - name: Install tools via mise | |
| uses: jdx/mise-action@6d1e696aa24c1aa1bcc1adea0212707c71ab78a8 # v3.6.1 | |
| with: | |
| version: 2026.5.3 | |
| # Don't cache mise's tool state: a cache hit restores rust as | |
| # "configured" but skips re-adding the rustfmt/clippy components | |
| # (they live in ~/.rustup, outside this cache), so fmt/clippy go | |
| # missing. A full install every run keeps it deterministic; the heavy | |
| # compile cache is handled separately by rust-cache below. | |
| cache: false | |
| - name: Cache cargo build | |
| uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0 | |
| - name: Check formatting and lint | |
| run: | | |
| cargo fmt --check | |
| cargo clippy --all-targets -- -D warnings | |
| # macOS runners have a working display + WebView, so the launch tests run | |
| # end-to-end there. Linux runs headless (DISPLAY unset → launch tests skip | |
| # automatically). Windows CI can't initialize WebView2 reliably and leaks | |
| # diagnostics to stderr, so we skip the launch tests there explicitly; the | |
| # unit tests still run on every platform. | |
| - name: Test | |
| env: | |
| WEBVIEW_SKIP_LAUNCH_TESTS: ${{ runner.os == 'Windows' && '1' || '' }} | |
| run: cargo test |