diff --git a/.github/actions/compute-native-cache-input-hash/action.yml b/.github/actions/compute-native-cache-input-hash/action.yml index f89222f2b6..40c269bc41 100644 --- a/.github/actions/compute-native-cache-input-hash/action.yml +++ b/.github/actions/compute-native-cache-input-hash/action.yml @@ -41,6 +41,7 @@ runs: 'packages/cli/binding/Cargo.toml', 'packages/cli/binding/index.*', 'packages/cli/src/vite-config-entry-basenames.json', + 'packages/cli/src/vitest-v5-entry-points.json', 'package.json', 'pnpm-lock.yaml', 'pnpm-workspace.yaml', diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fecace7384..52d5c06a36 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -105,10 +105,10 @@ jobs: - uses: ./.github/actions/download-rolldown-binaries with: github-token: ${{ secrets.GITHUB_TOKEN }} - test: + check: needs: detect-changes if: needs.detect-changes.outputs.code-changed == 'true' - name: Test + name: Check strategy: fail-fast: false matrix: @@ -125,33 +125,45 @@ jobs: - uses: ./.github/actions/setup-rust with: save-cache: ${{ github.ref_name == 'main' }} - cache-key: test - tools: just + cache-key: check - run: cargo check --all-targets --all-features env: RUSTFLAGS: '-D warnings --cfg tokio_unstable' # also update .cargo/config.toml + test: + needs: detect-changes + if: needs.detect-changes.outputs.code-changed == 'true' + name: Test + strategy: + fail-fast: false + matrix: + include: + - os: namespace-profile-linux-x64-default + target: x86_64-unknown-linux-gnu + - os: namespace-profile-mac-default + target: aarch64-apple-darwin + runs-on: ${{ matrix.os }} + steps: + - uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2 + - uses: ./.github/actions/clone + + - uses: ./.github/actions/setup-rust + with: + save-cache: ${{ github.ref_name == 'main' }} + cache-key: test + tools: just + - run: just test - # Windows tests are cross-compiled on a fast Linux runner with cargo-xwin - # (clang-cl + lld-link against the xwin-downloaded MSVC CRT/Windows SDK) - # and packed into a portable nextest archive. The test-windows job then - # only downloads the archive and runs it: no Rust toolchain, dev drive, or - # compilation on the slow Windows runner. Same approach as - # voidzero-dev/vite-task#443. - build-windows-tests: + # Platform checks run independently so test execution does not wait for them. + check-windows: needs: detect-changes if: needs.detect-changes.outputs.code-changed == 'true' - name: Build Windows tests + name: Check (Windows) runs-on: namespace-profile-linux-x64-default env: XWIN_ACCEPT_LICENSE: '1' - # The MSVC STL from xwin's VS17 manifest static-asserts a minimum Clang - # version newer than what runner images ship. Microsoft's documented - # escape hatch lets Detours (C++, via the fspy git dependency) compile - # with the runner's clang-cl; cargo-xwin folds a pre-set CXXFLAGS into - # the per-target CXXFLAGS it generates. CXXFLAGS: -D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH steps: - uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2 @@ -160,8 +172,7 @@ jobs: - uses: ./.github/actions/setup-xwin with: save-cache: ${{ github.ref_name == 'main' }} - cache-key: windows-cross - tools: cargo-nextest + cache-key: windows-check # `cargo xwin env` resolves the rustflags configured in # .cargo/config.toml (including the cfg-based Windows section), appends @@ -189,6 +200,47 @@ jobs: export CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_RUSTFLAGS="$CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_RUSTFLAGS -D warnings" cargo check --all-targets --all-features --target x86_64-pc-windows-msvc + # Windows tests are cross-compiled on a fast Linux runner with cargo-xwin + # (clang-cl + lld-link against the xwin-downloaded MSVC CRT/Windows SDK) + # and packed into a portable nextest archive. The test-windows job then + # only downloads the archive and runs it: no Rust toolchain, dev drive, or + # compilation on the slow Windows runner. Same approach as + # voidzero-dev/vite-task#443. + build-windows-tests: + needs: detect-changes + if: needs.detect-changes.outputs.code-changed == 'true' + name: Build Windows tests + runs-on: namespace-profile-linux-x64-default + env: + XWIN_ACCEPT_LICENSE: '1' + # The MSVC STL from xwin's VS17 manifest static-asserts a minimum Clang + # version newer than what runner images ship. Microsoft's documented + # escape hatch lets Detours (C++, via the fspy git dependency) compile + # with the runner's clang-cl; cargo-xwin folds a pre-set CXXFLAGS into + # the per-target CXXFLAGS it generates. + CXXFLAGS: -D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH + steps: + - uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2 + - uses: ./.github/actions/clone + + - uses: ./.github/actions/compute-native-cache-input-hash + id: native-cache-inputs + + # Reuse the compiled archive when its source and build settings match. + # Test jobs still run the full archive against the current checkout. + - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + id: test-archive-cache + with: + path: windows-tests.tar.zst + key: windows-test-archive-v1-${{ steps.native-cache-inputs.outputs.hash }}-${{ hashFiles('.github/workflows/ci.yml', 'crates/vp_cli_snapshots/**', 'packages/cli/rules/vite-tools.yml') }} + + - uses: ./.github/actions/setup-xwin + if: steps.test-archive-cache.outputs.cache-hit != 'true' + with: + save-cache: ${{ github.ref_name == 'main' }} + cache-key: windows-cross + tools: cargo-nextest + # Keep the package selection in sync with the `test` recipe in justfile. # vp_cli_snapshots is excluded there too: its snapshot suite needs a # built vp and node at runtime and joins the Windows archive later. @@ -196,6 +248,7 @@ jobs: # Run its portable parser and layout tests on Unix. # The Windows CLI snapshot suite tests Windows shim behavior. - name: Build test archive + if: steps.test-archive-cache.outputs.cache-hit != 'true' run: | eval "$(cargo xwin env --target x86_64-pc-windows-msvc | grep '^export ')" unset RUSTFLAGS @@ -208,13 +261,43 @@ jobs: path: windows-tests.tar.zst retention-days: 7 + # Snapshot shards need only the PTY runner, not the workspace check or unit tests. + build-windows-snapshots: + needs: detect-changes + if: needs.detect-changes.outputs.code-changed == 'true' + name: Build Windows snapshot tests + runs-on: namespace-profile-linux-x64-default + env: + XWIN_ACCEPT_LICENSE: '1' + CXXFLAGS: -D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH + steps: + - uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2 + - uses: ./.github/actions/clone + + - uses: ./.github/actions/compute-native-cache-input-hash + id: native-cache-inputs + + - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + id: test-archive-cache + with: + path: windows-snapshot-tests.tar.zst + key: windows-snapshot-test-archive-v1-${{ steps.native-cache-inputs.outputs.hash }}-${{ hashFiles('.github/workflows/ci.yml', 'crates/vp_cli_snapshots/**', 'packages/cli/rules/vite-tools.yml') }} + + - uses: ./.github/actions/setup-xwin + if: steps.test-archive-cache.outputs.cache-hit != 'true' + with: + save-cache: ${{ github.ref_name == 'main' }} + cache-key: windows-snapshot-tests + tools: cargo-nextest + # Separate archive for the PTY snapshot suite (excluded from the - # unit-test archive above): its suite needs vp, node, and a built + # unit-test archive): its suite needs vp, node, and a built # packages/cli/dist at runtime, which only cli-snapshot-test-windows # provides. The archive carries the cli_snapshots test binary plus the # vpt helper; nextest rewrites CARGO_MANIFEST_DIR/CARGO_BIN_EXE_vpt at # run time so the relocated binaries find fixtures and helpers. - name: Build snapshot test archive + if: steps.test-archive-cache.outputs.cache-hit != 'true' run: | eval "$(cargo xwin env --target x86_64-pc-windows-msvc | grep '^export ')" unset RUSTFLAGS @@ -229,7 +312,11 @@ jobs: test-windows: needs: build-windows-tests - name: Test (Windows) + name: Test (Windows, shard ${{ matrix.shard }}/3) + strategy: + fail-fast: false + matrix: + shard: [1, 2, 3] runs-on: namespace-profile-windows-4c-8g steps: - uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2 @@ -250,11 +337,10 @@ jobs: # --test-threads=1: nextest runs each test in its own process, so # serial_test's in-process locks no longer serialize tests that contend # on cross-process shared state (fixed temp paths, e.g. - # `vp-test-custom-home` in vp_shared::home tests). The whole suite is - # only ~1 minute of test time, so full serialization is cheap - # insurance; revisit if it becomes the bottleneck. + # `vp-test-custom-home` in vp_shared::home tests). Separate runners + # isolate the shards while tests within each shard remain serial. - name: Run tests - run: cargo-nextest nextest run -E 'platform(target)' --archive-file windows-tests.tar.zst --workspace-remap . --test-threads 1 + run: cargo-nextest nextest run -E 'platform(target)' --archive-file windows-tests.tar.zst --workspace-remap . --partition hash:${{ matrix.shard }}/3 --test-threads 1 env: RUST_MIN_STACK: '8388608' # Keep Windows env parity with the `test` recipe in justfile. @@ -287,7 +373,8 @@ jobs: steps: - name: Install Alpine dependencies shell: sh {0} - run: apk add --no-cache bash curl git just musl-dev gcc g++ python3 cmake make + # GitHub cache archives require GNU tar and zstd. + run: apk add --no-cache bash curl git just musl-dev gcc g++ python3 cmake make tar zstd - uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2 @@ -314,6 +401,14 @@ jobs: - name: Install Rust toolchain run: rustup show + # The trampoline shares target/. A second workspace entry would + # clean the same directory again with a different dependency list. + - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 + with: + prefix-key: v1-rust + shared-key: test-musl + save-if: ${{ github.ref_name == 'main' }} + # Skip separate cargo check — cargo test already compiles everything. - run: just test @@ -952,27 +1047,42 @@ jobs: - uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2 - uses: ./.github/actions/clone + - uses: ./.github/actions/compute-native-cache-input-hash + id: native-cache-inputs + + # Reuse the complete producer artifact to skip Rust setup and dependency + # installation. The utility tests below still run on every checkout. + - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + id: cli-test-cache + with: + path: ${{ runner.temp }}/cli-test-binaries.tar.gz + key: cli-test-binaries-v1-${{ matrix.target }}-${{ steps.native-cache-inputs.outputs.hash }}-${{ hashFiles('.github/workflows/ci.yml', 'crates/vp_cli_snapshots/**') }} + - uses: ./.github/actions/setup-rust + if: steps.cli-test-cache.outputs.cache-hit != 'true' with: save-cache: ${{ github.ref_name == 'main' }} cache-key: cli-snapshot-test-${{ matrix.target }}-ci - uses: ./.github/actions/setup-ci-node + if: steps.cli-test-cache.outputs.cache-hit != 'true' - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + if: steps.cli-test-cache.outputs.cache-hit != 'true' with: name: rolldown-binaries path: ./rolldown/packages/rolldown/src merge-multiple: true - name: Build with upstream + if: steps.cli-test-cache.outputs.cache-hit != 'true' uses: ./.github/actions/build-upstream with: profile: ci target: ${{ matrix.target }} - name: Ensure no unexpected file changes after build - if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }} + if: steps.cli-test-cache.outputs.cache-hit != 'true' && matrix.target == 'x86_64-unknown-linux-gnu' run: | if [[ -n "$(git status --porcelain)" ]]; then echo "::error::Unexpected file changes detected after build" @@ -982,12 +1092,11 @@ jobs: fi - name: Build snapshot test binaries + if: steps.cli-test-cache.outputs.cache-hit != 'true' run: cargo test -p vp_cli_snapshots --no-run --message-format=json > "$RUNNER_TEMP/snapshot-test-build.json" - - name: Test snapshot runner utilities - run: cargo test -p vp_cli_snapshots --test redact_unit --test shard_unit --test registry_pack_unit --test report_unit --test schedule_unit - - name: Package CLI test binaries + if: steps.cli-test-cache.outputs.cache-hit != 'true' run: | artifact_dir="$(mktemp -d)" trap 'rm -rf "$artifact_dir"' EXIT @@ -1001,7 +1110,7 @@ jobs: | jq '{packages: [.packages[] | {name, version, source}]}' \ > "$binding_dir/vite-plus.cargo-metadata.json" cp "${CARGO_TARGET_DIR:-target}/$BUILD_TARGET/release/vp" "$cli_dir/" - for binary in cli_snapshots vpt; do + for binary in cli_snapshots vpt redact_unit shard_unit registry_pack_unit report_unit schedule_unit; do binary_path="$(jq -er --arg name "$binary" \ 'select(.reason == "compiler-artifact" and .target.name == $name and .executable != null) | .executable' \ "$RUNNER_TEMP/snapshot-test-build.json")" @@ -1011,6 +1120,16 @@ jobs: env: BUILD_TARGET: ${{ matrix.target }} + - name: Test snapshot runner utilities + working-directory: crates/vp_cli_snapshots + run: | + utility_dir="$(mktemp -d)" + trap 'rm -rf "$utility_dir"' EXIT + tar -xzf "$RUNNER_TEMP/cli-test-binaries.tar.gz" -C "$utility_dir" ./target/snapshot-tests + for binary in "$utility_dir"/target/snapshot-tests/*_unit; do + "$binary" + done + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: cli-test-binaries-${{ matrix.target }} @@ -1131,14 +1250,14 @@ jobs: # Runs the PTY snapshot suite (crates/vp_cli_snapshots) on Windows with # BOTH vp flavors, without a Rust toolchain on the runner: the test binary # and vpt arrive cross-compiled in the nextest archive from - # build-windows-tests, the global vp comes prebuilt from build-windows-cli, + # build-windows-snapshots, the global vp comes prebuilt from build-windows-cli, # and the JS CLI is built here (skip-native) for the local flavor. cli-snapshot-test-windows: name: CLI snapshot test (Windows, shard ${{ matrix.shard }}/3) needs: - download-previous-rolldown-binaries - build-windows-cli - - build-windows-tests + - build-windows-snapshots strategy: fail-fast: false matrix: @@ -1439,10 +1558,30 @@ jobs: ' install-e2e-test: - name: Local CLI `vp install` E2E test + name: Local CLI `vp install` E2E test (${{ matrix.repository }}) needs: - build-cli-test-binaries runs-on: namespace-profile-linux-x64-default + strategy: + fail-fast: false + matrix: + include: + # Keep a fixed pnpm 11 workspace for compatibility coverage. + - repository: pnpm/pnpm + directory: pnpm + ref: v11.11.0 + - repository: vitejs/vite + directory: vite + # yarn workspace + - repository: napi-rs/napi-rs + directory: napi-rs + - repository: toeverything/AFFiNE + directory: AFFiNE + # npm workspace + - repository: npm/cli + directory: npm + - repository: redhat-developer/vscode-extension-tester + directory: vscode-extension-tester # Run if: not a PR, OR PR has 'test: install-e2e' label if: >- github.event_name != 'pull_request' || @@ -1475,43 +1614,27 @@ jobs: echo "$HOME/.vite-plus/bin" >> $GITHUB_PATH - name: Run local CLI `vp install` + env: + REPO: ${{ matrix.repository }} + REPO_DIR: ${{ matrix.directory }} + REPO_REF: ${{ matrix.ref }} run: | export PATH=$PWD/node_modules/.bin:$PATH vp -h - # Test vp install on various repositories with different package managers - # Entry format: "owner/repo:dir" or "owner/repo:dir:ref" (tag or branch to clone) - repos=( - # pnpm workspace - # Keep a fixed pnpm 11 workspace for compatibility coverage. - "pnpm/pnpm:pnpm:v11.11.0" - "vitejs/vite:vite" - # yarn workspace - "napi-rs/napi-rs:napi-rs" - "toeverything/AFFiNE:AFFiNE" - # npm workspace - "npm/cli:npm" - "redhat-developer/vscode-extension-tester:vscode-extension-tester" - ) - - for repo_info in "${repos[@]}"; do - IFS=':' read -r repo dir_name ref <<< "$repo_info" - echo "Testing vp install on $repo${ref:+ ($ref)}…" - # remove the directory if it exists - if [ -d "$RUNNER_TEMP/$dir_name" ]; then - rm -rf "$RUNNER_TEMP/$dir_name" - fi - clone_args=(--depth 1) - if [ -n "$ref" ]; then - clone_args+=(--branch "$ref") - fi - git clone "${clone_args[@]}" "https://github.com/$repo.git" "$RUNNER_TEMP/$dir_name" - cd "$RUNNER_TEMP/$dir_name" - vp install --no-frozen-lockfile - # run again to show install cache increase by time - time vp install - echo "✓ Successfully installed dependencies for $repo" - echo "" - done + echo "Testing vp install on $REPO${REPO_REF:+ ($REPO_REF)}…" + if [ -d "$RUNNER_TEMP/$REPO_DIR" ]; then + rm -rf "${RUNNER_TEMP:?}/${REPO_DIR:?}" + fi + clone_args=(--depth 1) + if [ -n "$REPO_REF" ]; then + clone_args+=(--branch "$REPO_REF") + fi + git clone "${clone_args[@]}" "https://github.com/$REPO.git" "$RUNNER_TEMP/$REPO_DIR" + cd "$RUNNER_TEMP/$REPO_DIR" + vp install --no-frozen-lockfile + # Keep the second install in this job so it uses the first install's cache. + time vp install + echo "✓ Successfully installed dependencies for $REPO" install-e2e-test-sfw: name: Local CLI `vp install` E2E test (Socket Firewall Free) @@ -1648,8 +1771,11 @@ jobs: if: always() needs: - docs-fmt + - check + - check-windows - test - build-windows-tests + - build-windows-snapshots - test-windows - build-windows-cli - test-musl