name: "E2E: Rust Windows interactive" on: workflow_dispatch: inputs: ref: description: "Optional full 40-character commit SHA; defaults to dispatch SHA" required: false default: "" runner: description: "Runner label; use the Azure RDP runner label for VM e2e" required: true default: "windows-latest" permissions: contents: read actions: read jobs: source: name: "Resolve exact source" runs-on: ubuntu-latest outputs: sha: ${{ steps.resolve.outputs.sha }} steps: - id: resolve name: Validate source SHA shell: bash env: REQUESTED_SHA: ${{ inputs.ref }} DISPATCH_SHA: ${{ github.sha }} run: | sha="${REQUESTED_SHA:-$DISPATCH_SHA}" if [[ ! "$sha" =~ ^[0-9a-fA-F]{40}$ ]]; then echo "ref must be a full 40-character commit SHA" >&2 exit 2 fi echo "sha=${sha,,}" >> "$GITHUB_OUTPUT" shared: name: "Windows / shared Electron + Tauri" needs: source runs-on: ${{ inputs.runner }} timeout-minutes: 90 env: CUA_E2E_SOURCE_SHA: ${{ needs.source.outputs.sha }} steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: ref: ${{ needs.source.outputs.sha }} - name: Ensure FFmpeg for trajectory video shell: pwsh run: | if (-not (Get-Command ffmpeg.exe -ErrorAction SilentlyContinue)) { choco install ffmpeg -y --no-progress } ffmpeg -version ffprobe -version - name: Run shared Rust behavior matrix shell: pwsh env: CUA_E2E_INTERNAL_LANE: shared run: .\scripts\ci\windows\run-rust-e2e.ps1 -RequireGui - name: Collect logs if: always() shell: pwsh run: .\scripts\ci\windows\collect-artifacts.ps1 - name: Upload shared results if: always() uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4 with: name: rust-windows-shared path: artifacts/cua-driver/windows if-no-files-found: ignore compression-level: 0 retention-days: 14 native: name: "Windows / native WPF + WinUI3 + WebView2" needs: source runs-on: ${{ inputs.runner }} timeout-minutes: 90 env: CUA_E2E_SOURCE_SHA: ${{ needs.source.outputs.sha }} steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: ref: ${{ needs.source.outputs.sha }} - name: Ensure FFmpeg for trajectory video shell: pwsh run: | if (-not (Get-Command ffmpeg.exe -ErrorAction SilentlyContinue)) { choco install ffmpeg -y --no-progress } ffmpeg -version ffprobe -version - name: Run native Rust harnesses shell: pwsh env: CUA_E2E_INTERNAL_LANE: native run: .\scripts\ci\windows\run-rust-e2e.ps1 -RequireGui - name: Collect logs if: always() shell: pwsh run: .\scripts\ci\windows\collect-artifacts.ps1 - name: Upload native results if: always() uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4 with: name: rust-windows-native path: artifacts/cua-driver/windows if-no-files-found: ignore compression-level: 0 retention-days: 14 capture: name: "Windows / capture and desktop scope" needs: source runs-on: ${{ inputs.runner }} timeout-minutes: 90 env: CUA_E2E_SOURCE_SHA: ${{ needs.source.outputs.sha }} steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: ref: ${{ needs.source.outputs.sha }} - name: Ensure FFmpeg for trajectory video shell: pwsh run: | if (-not (Get-Command ffmpeg.exe -ErrorAction SilentlyContinue)) { choco install ffmpeg -y --no-progress } ffmpeg -version ffprobe -version - name: Run capture and desktop-scope contracts shell: pwsh env: CUA_E2E_INTERNAL_LANE: capture run: .\scripts\ci\windows\run-rust-e2e.ps1 -RequireGui - name: Collect logs if: always() shell: pwsh run: .\scripts\ci\windows\collect-artifacts.ps1 - name: Upload capture results if: always() uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4 with: name: rust-windows-capture path: artifacts/cua-driver/windows if-no-files-found: ignore compression-level: 0 retention-days: 14 summary: if: always() needs: [source, shared, native, capture] name: "Windows / matrix summary" runs-on: ubuntu-latest timeout-minutes: 10 steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: ref: ${{ needs.source.outputs.sha }} - name: Download lane results uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4 with: path: artifacts - name: Publish matrix summary shell: bash env: GH_TOKEN: ${{ github.token }} run: | summary_path=matrix-summary.md { echo "# CUA Rust Windows E2E matrix" echo echo "The lane jobs above are independent; a failure in one lane does not hide the others." echo } > "$summary_path" artifacts_json=$(gh api \ "repos/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID/artifacts?per_page=100") found=0 while IFS= read -r summary; do found=1 artifact=$(basename "$(dirname "$summary")") echo "## $artifact" >> "$summary_path" artifact_id=$(jq -r --arg name "$artifact" \ '.artifacts[] | select(.name == $name) | .id' <<< "$artifacts_json" | head -n 1) if [[ -n "$artifact_id" && "$artifact_id" != "null" ]]; then artifact_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID/artifacts/$artifact_id" scripts/ci/link-e2e-evidence.sh "$summary" "$artifact_url" >> "$summary_path" else cat "$summary" >> "$summary_path" fi echo >> "$summary_path" done < <(find artifacts -type f -name summary.md -print | sort) if [[ "$found" == 0 ]]; then echo "No lane summary artifact was produced." >> "$summary_path" fi { echo echo "## Trajectory videos" echo echo "Full-desktop MP4s are retained for 14 days inside each lane artifact." echo echo "| Lane | Videos | Artifact |" echo "| --- | ---: | --- |" } >> "$summary_path" while IFS='|' read -r lane artifact; do recording_dir="artifacts/$artifact/recordings" if [[ -d "$recording_dir" ]]; then video_count=$(find "$recording_dir" -type f -name recording.mp4 | wc -l | tr -d ' ') else video_count=0 fi artifact_id=$(jq -r --arg name "$artifact" \ '.artifacts[] | select(.name == $name) | .id' <<< "$artifacts_json" | head -n 1) if [[ -n "$artifact_id" && "$artifact_id" != "null" ]]; then artifact_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID/artifacts/$artifact_id" artifact_link="[Download $artifact]($artifact_url)" else artifact_link="Not produced in this dispatch" fi echo "| $lane | $video_count | $artifact_link |" >> "$summary_path" done <<'EOF' Electron + Tauri|rust-windows-shared WPF + WinUI3 + WebView2|rust-windows-native Capture + desktop scope|rust-windows-capture EOF { echo echo "Each evidence link opens its owning lane artifact; the row text is the exact \`recordings/-pid-/recording.mp4\` path, with an adjacent \`trajectory.json\`." } >> "$summary_path" cat "$summary_path" >> "$GITHUB_STEP_SUMMARY" - name: Upload matrix summary if: always() uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4 with: name: rust-windows-matrix-summary path: matrix-summary.md if-no-files-found: error