diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6187246578..ebebb0e677 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,9 @@ # nightly. The reference tests and the doc tests run in the merge queue, on main and nightly, not # on pull requests (the fast lane, in Select checks); a break there is fixed forward on main. The # Windows jobs (D3D12 shaders and app startup) run nightly, and in the merge queue only for a group -# that changes what they exercise. Only main saves the build caches; pull requests restore them. +# that changes what they exercise. The wasm compile check runs in the merge queue for a group that +# touches the crates below the apps, the web app or the manifests. Dependency advisories run nightly +# and on any pull request or merge group that changes Cargo.lock or a Cargo.toml. Only main saves the build caches; pull requests restore them. # sccache is on a Blacksmith sticky disk that only main commits. # A push to main runs only the repository checks when a passing merge-queue run tested that very # commit, or when nothing a build reads changed since the last push to main whose run passed. @@ -78,8 +80,13 @@ env: jobs: dependency-advisories: + # Nightly and by hand: advisories, bans and sources for everything. A pull request or merge + # group that changes Cargo.lock or a Cargo.toml (Select checks' `deps`) checks the advisories + # only, so a dependency with a known vulnerability is caught before it lands, not the next + # morning; other pull requests skip it. `ci` requires it whenever `deps` is true. name: Dependency advisories - if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' + needs: changes + if: ${{ !cancelled() && (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || needs.changes.outputs.deps == 'true') }} runs-on: blacksmith-4vcpu-ubuntu-2404 timeout-minutes: 20 steps: @@ -88,7 +95,12 @@ jobs: - name: Install advisory scanner run: cargo install cargo-deny --version 0.20.2 --locked - name: Check locked dependencies + if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' run: cargo deny --locked check --warn unmaintained advisories bans sources + # deny.toml denies unmaintained crates; like the nightly, they are reported, not fatal. + - name: Check advisories for the changed dependencies + if: github.event_name != 'schedule' && github.event_name != 'workflow_dispatch' + run: cargo deny --locked check --warn unmaintained advisories changes: name: Select checks @@ -115,6 +127,10 @@ jobs: packages: ${{ steps.paths.outputs.packages }} oracle: ${{ steps.paths.outputs.oracle }} doctests: ${{ steps.paths.outputs.doctests }} + # Cargo.lock or a Cargo.toml changed (pull requests and merge groups): Dependency advisories. + deps: ${{ steps.paths.outputs.deps }} + # A merge group reaches the wasm build: Compile WebAssembly. + wasm: ${{ steps.paths.outputs.wasm }} # The passing run a merge of main carries forward (its URL), when this push is only that. carried: ${{ steps.paths.outputs.carried }} steps: @@ -143,6 +159,8 @@ jobs: goldens=false windows=false gpu_paths=false + deps=false + wasm=false full=true packages= # Whether the NUL-separated paths in $1 reach any code: scripts/ci/affected.py selects @@ -183,6 +201,21 @@ jobs: esac done < "$1" } + # Whether the NUL-separated paths in $1 change the dependencies (Cargo.lock or any + # Cargo.toml: deps), and whether they reach what `cargo xtask wasm` compiles (wasm): the + # crates below the apps, the web app, the vendored crates, the manifests and lockfile, the + # toolchain and cargo config, and this workflow. #8227 put a native-only call in + # crates/ui-egui and the merge queue passed it, because nothing built for wasm there. + deps_wasm_paths() { + while IFS= read -r -d '' path; do + case "$path" in + Cargo.lock|Cargo.toml|*/Cargo.toml) deps=true ;; + esac + case "$path" in + crates/*|apps/solidcraft-web/*|vendor/*|Cargo.lock|Cargo.toml|rust-toolchain*|.cargo/*|.github/workflows/ci.yml) wasm=true ;; + esac + done < "$1" + } # Opt-in for a big render change: a pull request labelled render-tests, or a merge group # holding one (its pull requests are the (#N) of its squash commits), runs them whatever # the paths say. @@ -228,14 +261,17 @@ jobs: if git diff --no-renames --name-only -z "$GROUP_BASE_SHA...$GROUP_HEAD_SHA" > "$RUNNER_TEMP/ci-paths"; then windows_paths "$RUNNER_TEMP/ci-paths" "$GROUP_BASE_SHA...$GROUP_HEAD_SHA" gpu_paths "$RUNNER_TEMP/ci-paths" + deps_wasm_paths "$RUNNER_TEMP/ci-paths" if [ "$gpu_paths" = false ] && group_has_render_label "$GROUP_BASE_SHA..$GROUP_HEAD_SHA"; then gpu_paths=true fi else windows=true gpu_paths=true + deps=true + wasm=true fi - echo "windows=$windows gpu_paths=$gpu_paths for $GROUP_BASE_SHA...$GROUP_HEAD_SHA" + echo "windows=$windows gpu_paths=$gpu_paths deps=$deps wasm=$wasm for $GROUP_BASE_SHA...$GROUP_HEAD_SHA" elif [ "$EVENT_NAME" != pull_request ]; then # The nightly run and Run workflow: everything, Windows included. native=true @@ -256,6 +292,10 @@ jobs: done < "$RUNNER_TEMP/ci-paths" # Computed as for a merge group, then turned off below (the fast lane). windows_paths "$RUNNER_TEMP/ci-paths" "$BASE_SHA...$HEAD_SHA" + # The advisories run on the pull request itself (it builds nothing of ours: about two minutes, most of it installing cargo-deny); + # the wasm compile waits for the merge queue. + deps_wasm_paths "$RUNNER_TEMP/ci-paths" + wasm=false # Pull requests build and test the touched packages and their dependents; nothing # selected means no code changed. select_packages "$RUNNER_TEMP/ci-paths" @@ -327,6 +367,8 @@ jobs: echo "windows=$windows" echo "oracle=$oracle" echo "doctests=$doctests" + echo "deps=$deps" + echo "wasm=$wasm" echo "carried=$carried" echo "full=$full" echo "quick=$quick" @@ -946,7 +988,7 @@ jobs: # commit's real run instead: the merge queue reads `ci` from the newest run of a commit, so a # run without a passing `ci` would block a pull request that passed (#1850, #3182, #3252). name: ci - needs: [changes, checks, quick-compile, clippy, build-tests, tests, gpu-path-tests, doc-tests, oracle, windows-fxc, windows-startup] + needs: [changes, checks, quick-compile, clippy, build-tests, tests, gpu-path-tests, doc-tests, oracle, windows-fxc, windows-startup, dependency-advisories, wasm] if: always() && (github.event_name != 'pull_request' || !github.event.pull_request.draft) runs-on: blacksmith-2vcpu-ubuntu-2404 permissions: @@ -1000,6 +1042,10 @@ jobs: ORACLE: ${{ needs.oracle.result }} WINDOWS_FXC: ${{ needs.windows-fxc.result }} WINDOWS_STARTUP: ${{ needs.windows-startup.result }} + DEPS_RUN: ${{ needs.changes.outputs.deps }} + ADVISORIES: ${{ needs.dependency-advisories.result }} + WASM_RUN: ${{ needs.changes.outputs.wasm }} + WASM: ${{ needs.wasm.result }} run: | test "$CHANGES" = success test "$CHECKS" = success @@ -1029,6 +1075,14 @@ jobs: test "$WINDOWS_FXC" = success test "$WINDOWS_STARTUP" = success fi + # Cargo.lock or a Cargo.toml changed on a pull request or in a merge group. + if [ "$DEPS_RUN" = true ]; then + test "$ADVISORIES" = success + fi + # A merge group that reaches the wasm build. + if [ "$WASM_RUN" = true ]; then + test "$WASM" = success + fi - name: Note a carried result if: needs.changes.outputs.carried != '' env: @@ -1036,9 +1090,13 @@ jobs: run: | echo "This push only merges main into a change that already passed; the heavy checks were not repeated. Passing run: $CARRIED" >> "$GITHUB_STEP_SUMMARY" + # Every crate below the apps and the web app must build for the browser (`cargo xtask wasm`, a + # cargo check, no tests). In the merge queue for a group that reaches the wasm build (Select + # checks' `wasm`), where `ci` requires it; by hand with cross_compile. wasm: - name: Compile WebAssembly (manual) - if: github.event_name == 'workflow_dispatch' && inputs.cross_compile + name: Compile WebAssembly + needs: changes + if: ${{ !cancelled() && ((github.event_name == 'workflow_dispatch' && inputs.cross_compile) || needs.changes.outputs.wasm == 'true') }} runs-on: blacksmith-8vcpu-ubuntu-2404 timeout-minutes: 30 steps: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 25ff99359f..7d444429d1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -117,7 +117,8 @@ The [architecture page](docs/architecture.md) has the layer table. The short ver not.) Permissive dependencies are fine. Note which one you're adding and why in the PR. THIRD-PARTY-LICENSES.txt lists it once the change lands: the Generated files workflow rewrites it on `main`. - Nightly/manual CI also scans advisories, bans and sources with cargo-deny; see + Nightly/manual CI also scans advisories, bans and sources with cargo-deny, and a PR that + changes Cargo.lock or a Cargo.toml checks the advisories; see [the local command and coverage limits](docs/book/src/dev/testing.md#dependency-advisories). 3. **Every asset is original or openly licensed and has a row in [ATTRIBUTION.md](ATTRIBUTION.md).** Icons are drawn in code (`crates/ui-egui/src/icons.rs`). diff --git a/docs/book/src/dev/testing.md b/docs/book/src/dev/testing.md index 1deb65bea4..981bdb531d 100644 --- a/docs/book/src/dev/testing.md +++ b/docs/book/src/dev/testing.md @@ -17,8 +17,11 @@ profile and the wasm build check. ## Dependency advisories -Scheduled and manually dispatched CI runs have a separate **Dependency advisories** job; -new advisories do not fail unrelated pull requests. To run the same scan locally: +Scheduled and manually dispatched CI runs have a separate **Dependency advisories** job that +checks advisories, bans and sources. A pull request or merge group that changes `Cargo.lock` or +any `Cargo.toml` runs the same job for advisories only, and `ci` requires it then; other pull +requests skip it, so a new advisory does not fail an unrelated change. To run the nightly scan +locally: ```sh cargo install cargo-deny --version 0.20.2 --locked