diff --git a/.github/workflows/clean-machine-install-ci.yml b/.github/workflows/clean-machine-install-ci.yml index 4afc55c45e..4012276f42 100644 --- a/.github/workflows/clean-machine-install-ci.yml +++ b/.github/workflows/clean-machine-install-ci.yml @@ -404,7 +404,7 @@ jobs: run: | # WSL2 is present on windows-2022+ runner images; only a distro is missing. wsl --set-default-version 2 - $url = 'https://cloud-images.ubuntu.com/wsl/releases/24.04/current/ubuntu-noble-wsl-amd64-24.04lts.rootfs.tar.gz' + $url = 'https://cloud-images.ubuntu.com/wsl/releases/24.04/20240423/ubuntu-noble-wsl-amd64-24.04lts.rootfs.tar.gz' $expected = '2a790896740b14d637dbdc583cce1ba081ac53b9e9cdb46dc09a2f73abbd9934' New-Item -ItemType Directory -Force -Path wsl-dist, logs | Out-Null Invoke-WebRequest -Uri $url -OutFile wsl-dist/rootfs.tar.gz -UseBasicParsing -TimeoutSec 900 @@ -542,6 +542,17 @@ jobs: -Value "@`"$($wingetCmd.Source)`" %*" $kept = @($shim) + $kept } + # Take the toolcache Python off disk, not just off PATH. py.exe lives in + # C:\Windows (which must stay) and uv does its own interpreter discovery, so + # both reach the toolcache no matter what PATH says -- which is how a leg + # printing `python ABSENT` still installed with the runner's 3.13.14. + foreach ($tc in @("$env:AGENT_TOOLSDIRECTORY\Python", 'C:\hostedtoolcache\windows\Python')) { + if ($tc -and (Test-Path $tc)) { + try { Rename-Item -LiteralPath $tc -NewName 'Python.masked' -ErrorAction Stop + Write-Host "masked toolcache python: $tc" } + catch { Write-Host "::error::could not mask $tc ($($_.Exception.Message)); the leg would not be clean"; exit 1 } + } + } $newPath = ($kept -join ';') "PATH=$newPath" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8 # install.ps1 calls Refresh-SessionPath (defined install.ps1:318-337, called at @@ -570,9 +581,20 @@ jobs: - name: Verify the simulation took effect shell: pwsh run: | - foreach ($t in 'python','git','cmake','cl') { + $leaked = @() + # `py` too: the launcher lives in C:\Windows, which the scrub keeps, and it + # finds the toolcache Python the scrub just removed from PATH. + foreach ($t in 'python','py','git','cmake','cl') { $f = Get-Command $t -ErrorAction SilentlyContinue Write-Host ("{0,-8} {1}" -f $t, $(if ($f) { $f.Source } else { 'ABSENT' })) + if ($f -and $t -ne 'py') { $leaked += "$t -> $($f.Source)" } + } + # Printing alone could not fail, and the leg was green while not clean: + # run 30365014702 logged `python ABSENT` and then `Python 3.13 already + # installed` / `Using CPython ... C:\hostedtoolcache\windows\Python\...`. + if ($leaked) { + Write-Host "::error::developer tooling survived the scrub: $($leaked -join '; ')" + exit 1 } $winget = Get-Command winget -ErrorAction SilentlyContinue Write-Host ("winget {0}" -f $(if ($winget) { $winget.Source } else { 'ABSENT' })) diff --git a/.github/workflows/desktop-app-clean-machine-ci.yml b/.github/workflows/desktop-app-clean-machine-ci.yml index 190dd3bdf9..aaa9c3a19a 100644 --- a/.github/workflows/desktop-app-clean-machine-ci.yml +++ b/.github/workflows/desktop-app-clean-machine-ci.yml @@ -166,11 +166,15 @@ jobs: # does: --tauri, stdin closed, no tty. --tauri rejects a custom studio # home (install.sh:102-114), so drop the workspace-scoped override. env -u UNSLOTH_STUDIO_HOME \ - bash "$APP/Contents/Resources/install.sh" --tauri --no-torch \ + bash "$APP/Contents/Resources/install.sh" --tauri \ < /dev/null 2>&1 | tee logs/bundled-install.log PY="$HOME/.unsloth/studio/unsloth_studio/bin/python" [ -x "$PY" ] || { echo "::error::bundled installer left no venv at $PY"; exit 1; } "$PY" -V + # install.rs passes only --tauri, so torch is part of first launch. Dropping + # --no-torch here and asserting torch keeps the venv check from passing over + # a bundle whose only failure is the torch install. + "$PY" -c "import torch; print('torch', torch.__version__)" - name: Launch and prove it stays up run: | @@ -204,7 +208,13 @@ jobs: tail -60 "$f" # The two fields the bug report turned on. grep -E "disposition=|can_auto_repair=|Xcode Command Line|ModuleNotFoundError" "$f" || true + found=1 done + # Everything above is `|| true`, so on its own this step could not fail while + # the header sells the tauri.log disposition as an acceptance criterion. + # setup_logging (src-tauri/src/main.rs:50-67) opens tauri.log unconditionally + # at process start, so no log at all means the binary never got that far. + [ "${found:-0}" = "1" ] || { echo "::error::the app wrote no tauri.log; it never reached setup_logging"; exit 1; } - name: Restore the runner if: always()