| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| permissions: | |
| contents: read | |
| env: | |
| CARGO_TERM_COLOR: always | |
| RUSTFLAGS: -D warnings | |
| jobs: | |
| # Whether this push or pull request changes only Markdown outside the code, which cannot | |
| # change what builds (scripts/docs-only.sh says which files those are). The jobs below, all but `corpus`, skip on a yes; a job skipped by its | |
| # condition reports success, so a required check does not sit waiting for it. Anything | |
| # the diff cannot answer, a first push or a rewritten base, runs everything. | |
| changes: | |
| name: changes | |
| runs-on: ubuntu-latest | |
| outputs: | |
| docs_only: ${{ steps.diff.outputs.docs_only }} | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 0 | |
| - id: diff | |
| env: | |
| BASE: ${{ github.event.pull_request.base.sha || github.event.before }} | |
| run: | | |
| # judged by the base's copy of the script, so a change to it cannot skip the | |
| # job that tests it; a base without one runs everything | |
| if judge=$(git show "$BASE:scripts/docs-only.sh") && | |
| files=$(git diff --name-only --no-renames "$BASE" "$GITHUB_SHA") && | |
| printf '%s\n' "$files" | sh -c "$judge"; then | |
| echo "docs_only=true" >> "$GITHUB_OUTPUT" | |
| echo "only Markdown changed; the build and test jobs skip" | |
| else | |
| echo "docs_only=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| # The pre-commit gate, as `make check` runs it locally, plus the two checks that need | |
| # cargo extensions. Actions are pinned by commit; the comment says which release. | |
| check: | |
| name: check (linux) | |
| needs: changes | |
| if: ${{ !cancelled() && needs.changes.outputs.docs_only != 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # 2026-07-16, the commit the ASF allow-list pins | |
| with: | |
| toolchain: stable | |
| components: rustfmt, clippy | |
| # wasm32-unknown-unknown: dm-web's build script builds the browser reader | |
| targets: wasm32-unknown-unknown, wasm32-wasip2, x86_64-pc-windows-gnu | |
| - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 | |
| # Ubuntu's AppArmor lets an unprivileged process create a user namespace but not map | |
| # its uid in it, so no confined test could run. A laptop installs the amem profile in | |
| # packaging/apparmor; the tests' own probe is unshare, not amem, so this throwaway VM | |
| # turns the restriction off instead | |
| - run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 | |
| - run: make check | |
| # the embedded PostgreSQL for the ledger tests lists its releases through GitHub's | |
| # API; unauthenticated, a runner's address is soon refused | |
| env: | |
| GITHUB_TOKEN: ${{ github.token }} | |
| - uses: taiki-e/install-action@5488ac5a951645ce95062214902ac4b6bc1a1037 # v2.87.32 | |
| with: | |
| tool: cargo-machete | |
| - run: make machete | |
| # The same tests on Windows. Portability between the two is a stated goal, so a change | |
| # that passes on one and not the other does not merge. | |
| windows: | |
| name: test (windows) | |
| needs: changes | |
| if: ${{ !cancelled() && needs.changes.outputs.docs_only != 'true' }} | |
| runs-on: windows-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # 2026-07-16, the commit the ASF allow-list pins | |
| with: | |
| toolchain: stable | |
| targets: wasm32-unknown-unknown, wasm32-wasip2 | |
| - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 | |
| # The companion test loads an unpacked extension, which Google Chrome's own builds | |
| # refuse; the Windows image has no Chromium or Chrome for Testing, so this fetches | |
| # the stable Chrome for Testing and names it in CHROME | |
| - name: Chrome for Testing | |
| shell: pwsh | |
| run: | | |
| $known = Invoke-RestMethod https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions-with-downloads.json | |
| $url = ($known.channels.Stable.downloads.chrome | Where-Object platform -eq 'win64').url | |
| Invoke-WebRequest $url -OutFile "$env:RUNNER_TEMP\chrome.zip" | |
| Expand-Archive "$env:RUNNER_TEMP\chrome.zip" -DestinationPath "$env:RUNNER_TEMP\chrome" | |
| "CHROME=$env:RUNNER_TEMP\chrome\chrome-win64\chrome.exe" >> $env:GITHUB_ENV | |
| - run: cargo test --workspace | |
| # the embedded PostgreSQL for the ledger tests lists its releases through GitHub's | |
| # API; unauthenticated, a runner's address is soon refused | |
| env: | |
| GITHUB_TOKEN: ${{ github.token }} | |
| # The same tests on macOS, which is also the only place the Seatbelt backend's tests | |
| # that run sandbox-exec are compiled and run. | |
| macos: | |
| name: test (macos) | |
| needs: changes | |
| if: ${{ !cancelled() && needs.changes.outputs.docs_only != 'true' }} | |
| runs-on: macos-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # 2026-07-16, the commit the ASF allow-list pins | |
| with: | |
| toolchain: stable | |
| targets: wasm32-unknown-unknown, wasm32-wasip2 | |
| - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 | |
| - run: cargo test --workspace | |
| # the embedded PostgreSQL for the ledger tests lists its releases through GitHub's | |
| # API; unauthenticated, a runner's address is soon refused | |
| env: | |
| GITHUB_TOKEN: ${{ github.token }} | |
| # dm-core must build for the browser, or the reader and the plugins cannot. | |
| wasm: | |
| name: build (wasm32) | |
| needs: changes | |
| if: ${{ !cancelled() && needs.changes.outputs.docs_only != 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # 2026-07-16, the commit the ASF allow-list pins | |
| with: | |
| toolchain: stable | |
| targets: wasm32-unknown-unknown | |
| - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 | |
| - run: make wasm-check | |
| # The Markdown the demo reads, checked as the demo reads it (scripts/corpus-check.sh). | |
| # It runs on every change, a docs-only one included: docs/ and examples/decisions/ are | |
| # the demo's record, and a heading renamed there breaks a golden question or an eval. | |
| corpus: | |
| name: corpus | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # 2026-07-16, the commit the ASF allow-list pins | |
| with: | |
| toolchain: stable | |
| - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 | |
| - run: make corpus-check | |
| # The rust-version in Cargo.toml, built with that release of Rust (`make msrv-check`), so | |
| # the declared minimum cannot fall behind what the locked dependencies need. | |
| # RUSTUP_TOOLCHAIN outranks rust-toolchain.toml, which would otherwise fetch stable and | |
| # its targets the first time anything runs cargo or rustc. | |
| msrv: | |
| name: build (msrv) | |
| needs: changes | |
| if: ${{ !cancelled() && needs.changes.outputs.docs_only != 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - id: msrv | |
| run: echo "version=$(sed -n 's/^rust-version = "\(.*\)"$/\1/p' Cargo.toml)" >> "$GITHUB_OUTPUT" | |
| - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # 2026-07-16, the commit the ASF allow-list pins | |
| with: | |
| toolchain: ${{ steps.msrv.outputs.version }} | |
| targets: wasm32-unknown-unknown | |
| - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 | |
| env: | |
| RUSTUP_TOOLCHAIN: ${{ steps.msrv.outputs.version }} | |
| - run: make msrv-check | |
| env: | |
| RUSTUP_TOOLCHAIN: ${{ steps.msrv.outputs.version }} | |
| # Advisories, licences, duplicate versions, sources. Configured in deny.toml. The | |
| # cargo-deny action is not on the ASF allow-list, so the tool is installed instead. | |
| deny: | |
| name: dependencies | |
| needs: changes | |
| if: ${{ !cancelled() && needs.changes.outputs.docs_only != 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - uses: taiki-e/install-action@5488ac5a951645ce95062214902ac4b6bc1a1037 # v2.87.32 | |
| with: | |
| tool: cargo-deny | |
| - run: make deny | |
| # Line coverage against COVERAGE_MIN in the Makefile, which is a ratchet. The lcov | |
| # report is attached to the run for anyone who wants to look at the lines. | |
| coverage: | |
| name: coverage | |
| needs: changes | |
| if: ${{ !cancelled() && needs.changes.outputs.docs_only != 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # 2026-07-16, the commit the ASF allow-list pins | |
| with: | |
| toolchain: stable | |
| components: llvm-tools-preview | |
| targets: wasm32-unknown-unknown, wasm32-wasip2 | |
| - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 | |
| - uses: taiki-e/install-action@5488ac5a951645ce95062214902ac4b6bc1a1037 # v2.87.32 | |
| with: | |
| tool: cargo-llvm-cov | |
| # the confined tests run here too, as in the check job | |
| - run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 | |
| - run: make coverage | |
| # the embedded PostgreSQL for the ledger tests lists its releases through GitHub's | |
| # API; unauthenticated, a runner's address is soon refused | |
| env: | |
| GITHUB_TOKEN: ${{ github.token }} | |
| - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 | |
| with: | |
| name: lcov | |
| path: target/lcov.info | |
| # The browser tests: the pages driven by Chromium in the Playwright image, as | |
| # `make e2e` runs them, with every page's screenshots attached to the run for review. | |
| e2e: | |
| name: e2e (chromium) | |
| needs: changes | |
| if: ${{ !cancelled() && needs.changes.outputs.docs_only != 'true' }} | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # 2026-07-16, the commit the ASF allow-list pins | |
| with: | |
| toolchain: stable | |
| targets: wasm32-unknown-unknown | |
| - uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3 | |
| - run: make e2e | |
| env: | |
| CI: 'true' | |
| - if: always() | |
| uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 | |
| with: | |
| name: e2e-screenshots | |
| path: | | |
| e2e/screenshots/ | |
| e2e/playwright-report/ | |
| retention-days: 14 |