diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index fa478ac6f..9b94893b8 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -38,7 +38,7 @@ jobs: - name: Verify 3.9.13 run: python __tests__/verify-python.py 3.9.13 - - name: Run with setup-python 3.9.13 + - name: Run with setup-python 3.10.11 uses: ./ with: python-version: 3.10.11 @@ -89,7 +89,57 @@ jobs: python-version: '<3.13' - name: Verify <3.13 run: python __tests__/verify-python.py 3.12 + - name: Test Raw Endpoint Access run: | curl -L https://raw.githubusercontent.com/actions/python-versions/main/versions-manifest.json | jq empty shell: bash + + verify-install-path: + name: Verify Install Path + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [windows-11-arm] + architecture: [x86, arm64] + python-version: ['3.11', '3.12', '3.13.1', '3.14.0-beta.2'] + freethreaded: ['false'] + include: + - os: windows-11-arm + architecture: x86 + python-version: '3.13.1' + freethreaded: true + - os: windows-11-arm + architecture: arm64 + python-version: '3.13.1' + freethreaded: true + - os: windows-11-arm + architecture: x86 + python-version: '3.14.0-beta.2' + freethreaded: true + - os: windows-11-arm + architecture: arm64 + python-version: '3.14.0-beta.2' + freethreaded: true + - os: windows-latest + architecture: x86 + python-version: '3.10' + freethreaded: false + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: ./ + with: + python-version: ${{ matrix.python-version }} + architecture: ${{ matrix.architecture }} + freethreaded: ${{ matrix.freethreaded }} + + - name: Verify Install Path + shell: pwsh + run: python __tests__/verify-windows-install-path.py ` + ${{ matrix.python-version }} ` + ${{ matrix.architecture }} ` + ${{ matrix.freethreaded }} diff --git a/.github/workflows/test-python-freethreaded.yml b/.github/workflows/test-python-freethreaded.yml index c769046af..39e69a474 100644 --- a/.github/workflows/test-python-freethreaded.yml +++ b/.github/workflows/test-python-freethreaded.yml @@ -24,7 +24,6 @@ jobs: [ macos-latest, windows-latest, - ubuntu-20.04, ubuntu-22.04, ubuntu-22.04-arm, macos-13, @@ -62,7 +61,6 @@ jobs: [ macos-latest, windows-latest, - ubuntu-20.04, ubuntu-22.04, ubuntu-22.04-arm, macos-13, @@ -103,7 +101,6 @@ jobs: [ macos-latest, windows-latest, - ubuntu-20.04, ubuntu-22.04, ubuntu-22.04-arm, macos-13, @@ -142,7 +139,6 @@ jobs: [ macos-latest, windows-latest, - ubuntu-20.04, ubuntu-22.04, ubuntu-22.04-arm, macos-13, @@ -184,7 +180,6 @@ jobs: [ macos-latest, windows-latest, - ubuntu-20.04, ubuntu-22.04, ubuntu-22.04-arm, macos-13, @@ -226,7 +221,6 @@ jobs: [ macos-latest, windows-latest, - ubuntu-20.04, ubuntu-22.04, ubuntu-22.04-arm, macos-13, @@ -258,7 +252,6 @@ jobs: [ macos-latest, windows-latest, - ubuntu-20.04, ubuntu-22.04, ubuntu-22.04-arm, macos-13, @@ -371,7 +364,6 @@ jobs: [ macos-latest, windows-latest, - ubuntu-20.04, ubuntu-22.04, ubuntu-22.04-arm, macos-13, @@ -461,7 +453,6 @@ jobs: [ macos-latest, windows-latest, - ubuntu-20.04, ubuntu-22.04, ubuntu-22.04-arm, macos-13, diff --git a/__tests__/verify-windows-install-path.py b/__tests__/verify-windows-install-path.py new file mode 100644 index 000000000..46bf78839 --- /dev/null +++ b/__tests__/verify-windows-install-path.py @@ -0,0 +1,57 @@ +import os +import sys +import re + +def build_expected_path(python_version, architecture, freethreaded): + print("Inputs received:") + print(f" Python Version : {python_version}") + print(f" Architecture : {architecture}") + print(f" Freethreaded : {freethreaded}") + + # Extract major and minor from version like "3.13.1" or "3.14.0-beta.2" + match = re.match(r"^(\d+)\.(\d+)", python_version) + if not match: + print(f"Invalid python version format: {python_version}") + sys.exit(1) + + major, minor = match.groups() + version_suffix = f"{major}{minor}" + + if freethreaded == "true": + version_suffix += "t" + if architecture == "x86": + version_suffix += "-32" + elif architecture == "arm64": + version_suffix += "-arm64" + else: + if architecture == "x86": + version_suffix += "-32" + elif architecture == "arm64": + version_suffix += "-arm64" + + base_path = os.getenv("APPDATA", "") + full_path = os.path.join(base_path, "Python", f"Python{version_suffix}", "Scripts") + print(f"Constructed expected path: {full_path}") + return full_path + +def main(): + if len(sys.argv) != 4: + print("Usage: python verify_windows_install_path.py ") + sys.exit(1) + + python_version = sys.argv[1] + architecture = sys.argv[2] + freethreaded = sys.argv[3] + + expected_path = build_expected_path(python_version, architecture, freethreaded) + + print("Validating against PATH environment variable...") + path_env = os.getenv("PATH", "") + if expected_path.lower() in path_env.lower(): + print("Correct path present in PATH") + else: + print("Expected path not found in PATH") + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/dist/setup/index.js b/dist/setup/index.js index ec5261efc..b0c41ae49 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -96883,13 +96883,32 @@ function useCpythonVersion(version, architecture, updateEnvironment, checkLatest core.addPath(installDir); core.addPath(_binDir); if (utils_1.IS_WINDOWS) { - // Add --user directory - // `installDir` from tool cache should look like $RUNNER_TOOL_CACHE/Python//x64/ - // So if `findLocalTool` succeeded above, we must have a conformant `installDir` + // Extract version details const version = path.basename(path.dirname(installDir)); const major = semver.major(version); const minor = semver.minor(version); - const userScriptsDir = path.join(process.env['APPDATA'] || '', 'Python', `Python${major}${minor}`, 'Scripts'); + const basePath = process.env['APPDATA'] || ''; + let versionSuffix = `${major}${minor}`; + // Append '-32' for x86 architecture if Python version is >= 3.10 + if (architecture === 'x86' && + (major > 3 || (major === 3 && minor >= 10))) { + versionSuffix += '-32'; + } + else if (architecture === 'arm64') { + versionSuffix += '-arm64'; + } + // Append 't' for freethreaded builds + if (freethreaded) { + versionSuffix += 't'; + if (architecture === 'x86-freethreaded') { + versionSuffix += '-32'; + } + else if (architecture === 'arm64-freethreaded') { + versionSuffix += '-arm64'; + } + } + // Add user Scripts path + const userScriptsDir = path.join(basePath, 'Python', `Python${versionSuffix}`, 'Scripts'); core.addPath(userScriptsDir); } // On Linux and macOS, pip will create the --user directory and add it to PATH as needed. diff --git a/src/find-python.ts b/src/find-python.ts index ddb027cb7..2e317d9c6 100644 --- a/src/find-python.ts +++ b/src/find-python.ts @@ -49,8 +49,8 @@ export async function useCpythonVersion( // Use the freethreaded version if it was specified in the input, e.g., 3.13t freethreaded = true; } - core.debug(`Semantic version spec of ${version} is ${semanticVersionSpec}`); + core.debug(`Semantic version spec of ${version} is ${semanticVersionSpec}`); if (freethreaded) { // Free threaded versions use an architecture suffix like `x64-freethreaded` core.debug(`Using freethreaded version of ${semanticVersionSpec}`); @@ -152,17 +152,36 @@ export async function useCpythonVersion( core.addPath(_binDir); if (IS_WINDOWS) { - // Add --user directory - // `installDir` from tool cache should look like $RUNNER_TOOL_CACHE/Python//x64/ - // So if `findLocalTool` succeeded above, we must have a conformant `installDir` + // Extract version details const version = path.basename(path.dirname(installDir)); const major = semver.major(version); const minor = semver.minor(version); + const basePath = process.env['APPDATA'] || ''; + let versionSuffix = `${major}${minor}`; + // Append '-32' for x86 architecture if Python version is >= 3.10 + if ( + architecture === 'x86' && + (major > 3 || (major === 3 && minor >= 10)) + ) { + versionSuffix += '-32'; + } else if (architecture === 'arm64') { + versionSuffix += '-arm64'; + } + // Append 't' for freethreaded builds + if (freethreaded) { + versionSuffix += 't'; + if (architecture === 'x86-freethreaded') { + versionSuffix += '-32'; + } else if (architecture === 'arm64-freethreaded') { + versionSuffix += '-arm64'; + } + } + // Add user Scripts path const userScriptsDir = path.join( - process.env['APPDATA'] || '', + basePath, 'Python', - `Python${major}${minor}`, + `Python${versionSuffix}`, 'Scripts' ); core.addPath(userScriptsDir);