diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..76614dd --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,68 @@ +name: "Test" + +on: + push: + branches: + - "main" + +jobs: + test: + name: "Test on ${{ matrix.config.os-name }}" + runs-on: "${{ matrix.config.runner }}" + strategy: + matrix: + config: + - os-name: "Linux" + runner: "ubuntu-latest" + test-label: "ci-test-linux" + - os-name: "macOS" + runner: "macos-latest" + test-label: "ci-test-macos" + - os-name: "Windows" + runner: "windows-latest" + test-label: "ci-test-windows" + fail-fast: false + + steps: + - name: "Show environment (pre)" + shell: "bash" + run: env | sort + + - name: "Checkout" + uses: "actions/checkout@v4" + + - name: "Setup Python" + id: "setup-python" + uses: "actions/setup-python@v4" + with: + python-version: | + 3.9 + 3.10 + 3.11 + pypy-3.9 + allow-prereleases: true + + - name: "Show environment (post)" + shell: "bash" + run: env | sort + + - name: "Linux / macOS" + id: linux + if: "runner.os != 'windows'" + shell: "bash" + run: | + bash ./finder.sh + bash ./finder.sh > "$GITHUB_OUTPUT" + + - name: "Windows" + id: "windows" + if: "runner.os == 'windows'" + shell: "powershell" + run: | + & .\finder.ps1 + & .\finder.ps1 > "$env:GITHUB_OUTPUT" + + - name: "Show results" + shell: "bash" + run: | + echo "${{ steps.linux.outputs.python-paths }}${{ steps.windows.outputs.python-paths }}" diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..e228417 --- /dev/null +++ b/action.yml @@ -0,0 +1,47 @@ +name: 'Detect Python versions' +description: | + Find Python paths and output them as "python-versions". + This can be useful for cache busting of tox and/or virtual environments. + +inputs: + search-runner-tool-cache: + description: | + By default, only paths in the PATH environment variable will be searched + because the "actions/setup-python" action typically modifies the PATH + after installing various Python versions. + + Because it is possible to prevent "actions/setup-python" from modifying the PATH, + and because some GitHub runner images have multiple Python versions pre-installed, + it may be desirable to find every Python installed on the system, + even if their paths don't appear in the PATH environment variable. + + If this input is specified, its value must be the string value "true". + Use quotation marks to ensure the correct value is passed. + required: false + default: "false" + +outputs: + python-paths: + description: "A string of sorted Python executable paths" + value: ${{ steps.final-step.outputs.python-path }} + +runs: + using: "composite" + steps: + - name: "Find Pythons on Linux / macOS" + id: "linux" + if: "runner.os != 'windows'" + shell: "bash" + run: 'bash ./finder.sh "${{ inputs.search-runner-tool-cache }}" > "$GITHUB_OUTPUT"' + + - name: "Find Pythons on Windows" + id: "windows" + if: "runner.os == 'windows'" + shell: "powershell" + run: '& .\finder.ps1 "${{ inputs.search-runner-tool-cache }}" > "$env:GITHUB_OUTPUT"' + + - name: "Output" + id: "final-step" + shell: "bash" + run: | + echo "${{ steps.linux.outputs.python-paths }}${{ steps.windows.outputs.python-paths }}" > $GITHUB_OUTPUT diff --git a/finder.ps1 b/finder.ps1 new file mode 100644 index 0000000..5662e8a --- /dev/null +++ b/finder.ps1 @@ -0,0 +1,30 @@ +$search_runner_tool_cache = $args[0] + +if ($search_runner_tool_cache -eq "true") { + # Search paths in $RUNNER_TOOL_CACHE for Python interpreters. + $all_paths = ` + Get-ChildItem ` + -Path ` + "$env:RUNNER_TOOL_CACHE\Python\*\*", ` + "$env:RUNNER_TOOL_CACHE\PyPy\*\*" ` + -Filter "x??" ` + -Directory ` + | Sort-Object -Property FullName ` + | Select-Object -ExpandProperty "FullName" +} else { + # Search paths in $PATH for Python interpreters. + $all_paths = ` + $env:PATH -split ";" ` + | Sort-Object +} + +$paths = @() +foreach ($path in $all_paths) { + Write-Error $path + if (Test-Path "$path\python.exe") { + $paths += $path + } +} + +$result = $paths -join ";" +Write-Output "python-paths=$result" diff --git a/finder.sh b/finder.sh new file mode 100644 index 0000000..cf91f06 --- /dev/null +++ b/finder.sh @@ -0,0 +1,35 @@ +search_runner_tool_cache="$1" + +if [ "$search_runner_tool_cache" = "true" ]; then + # Search paths in $RUNNER_TOOL_CACHE for Python interpreters. + read -r -a all_paths <<< "$( + find \ + "$RUNNER_TOOL_CACHE/Python" \ + "$RUNNER_TOOL_CACHE/PyPy" \ + -mindepth 2 \ + -maxdepth 2 \ + -name 'x86' \ + -o \ + -name 'x64' \ + | sort + )" +else + # Search paths in $PATH for Python interpreters. + read -r -a all_paths <<< "$( + echo "$PATH" \ + | tr ':' '\n' \ + | sort + )" +fi + +paths=() +for path in "${all_paths[@]}"; do + if [[ -x "${path}/bin/python" ]]; then + paths+=("${path}/bin") + elif [[ -x "${path}/python" ]]; then + paths+=("${path}") + fi +done + +result="$(echo "${paths[*]}" | tr ' ' ':')" +echo "python-paths=${result}"