mirror of
				https://gitea.com/actions/setup-python.git
				synced 2025-10-31 07:47:08 +00:00 
			
		
		
		
	Compare commits
	
		
			9 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | b64ffcaf5b | ||
|   | 8d2896179a | ||
|   | 7bc6abb01e | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | e8111cec9d | ||
|   | a00ea43da6 | ||
|   | 8635b1ccc5 | ||
|   | f6cc428f53 | ||
|   | 5f2af211d6 | ||
|   | 3467d92d48 | 
							
								
								
									
										10
									
								
								.github/workflows/e2e-cache.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.github/workflows/e2e-cache.yml
									
									
									
									
										vendored
									
									
								
							| @@ -23,7 +23,7 @@ jobs: | |||||||
|         os: [ubuntu-latest, windows-latest, macos-latest] |         os: [ubuntu-latest, windows-latest, macos-latest] | ||||||
|         python-version: ['3.9', 'pypy-3.7-v7.x'] |         python-version: ['3.9', 'pypy-3.7-v7.x'] | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v3 |       - uses: actions/checkout@v4 | ||||||
|       - name: Setup Python |       - name: Setup Python | ||||||
|         uses: ./ |         uses: ./ | ||||||
|         with: |         with: | ||||||
| @@ -41,7 +41,7 @@ jobs: | |||||||
|         os: [ubuntu-latest, windows-latest, macos-latest] |         os: [ubuntu-latest, windows-latest, macos-latest] | ||||||
|         python-version: ['3.9', 'pypy-3.9-v7.x'] |         python-version: ['3.9', 'pypy-3.9-v7.x'] | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v3 |       - uses: actions/checkout@v4 | ||||||
|       - name: Setup Python |       - name: Setup Python | ||||||
|         id: cache-pipenv |         id: cache-pipenv | ||||||
|         uses: ./ |         uses: ./ | ||||||
| @@ -77,7 +77,7 @@ jobs: | |||||||
|         os: [ubuntu-latest, windows-latest, macos-latest] |         os: [ubuntu-latest, windows-latest, macos-latest] | ||||||
|         python-version: ['3.9', 'pypy-3.8'] |         python-version: ['3.9', 'pypy-3.8'] | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v3 |       - uses: actions/checkout@v4 | ||||||
|       - name: Install poetry |       - name: Install poetry | ||||||
|         run: pipx install poetry |         run: pipx install poetry | ||||||
|       - name: Init pyproject.toml |       - name: Init pyproject.toml | ||||||
| @@ -99,7 +99,7 @@ jobs: | |||||||
|         os: [ubuntu-latest, windows-latest, macos-latest] |         os: [ubuntu-latest, windows-latest, macos-latest] | ||||||
|         python-version: ['3.9', 'pypy-3.7-v7.x'] |         python-version: ['3.9', 'pypy-3.7-v7.x'] | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v3 |       - uses: actions/checkout@v4 | ||||||
|       - name: Setup Python |       - name: Setup Python | ||||||
|         uses: ./ |         uses: ./ | ||||||
|         with: |         with: | ||||||
| @@ -118,7 +118,7 @@ jobs: | |||||||
|         os: [ubuntu-latest, windows-latest, macos-latest] |         os: [ubuntu-latest, windows-latest, macos-latest] | ||||||
|         python-version: ['3.9', 'pypy-3.9-v7.x'] |         python-version: ['3.9', 'pypy-3.9-v7.x'] | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v3 |       - uses: actions/checkout@v4 | ||||||
|       - name: Setup Python |       - name: Setup Python | ||||||
|         id: cache-pipenv |         id: cache-pipenv | ||||||
|         uses: ./ |         uses: ./ | ||||||
|   | |||||||
							
								
								
									
										9
									
								
								.github/workflows/e2e-tests.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								.github/workflows/e2e-tests.yml
									
									
									
									
										vendored
									
									
								
							| @@ -19,7 +19,7 @@ jobs: | |||||||
|         operating-system: [ubuntu-20.04, windows-latest] |         operating-system: [ubuntu-20.04, windows-latest] | ||||||
|     steps: |     steps: | ||||||
|       - name: Checkout |       - name: Checkout | ||||||
|         uses: actions/checkout@v3 |         uses: actions/checkout@v4 | ||||||
|  |  | ||||||
|       - name: Run with setup-python 3.5 |       - name: Run with setup-python 3.5 | ||||||
|         uses: ./ |         uses: ./ | ||||||
| @@ -93,10 +93,3 @@ jobs: | |||||||
|           python-version: '<3.11' |           python-version: '<3.11' | ||||||
|       - name: Verify <3.11 |       - name: Verify <3.11 | ||||||
|         run: python __tests__/verify-python.py 3.10 |         run: python __tests__/verify-python.py 3.10 | ||||||
|  |  | ||||||
|       - name: Run with setup-python >3.8 |  | ||||||
|         uses: ./ |  | ||||||
|         with: |  | ||||||
|           python-version: '>3.8' |  | ||||||
|       - name: Verify >3.8 |  | ||||||
|         run: python __tests__/verify-python.py 3.11 |  | ||||||
|   | |||||||
							
								
								
									
										116
									
								
								.github/workflows/test-graalpy.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								.github/workflows/test-graalpy.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,116 @@ | |||||||
|  | name: Validate GraalPy e2e | ||||||
|  |  | ||||||
|  | on: | ||||||
|  |   push: | ||||||
|  |     branches: | ||||||
|  |       - main | ||||||
|  |     paths-ignore: | ||||||
|  |       - '**.md' | ||||||
|  |   pull_request: | ||||||
|  |     paths-ignore: | ||||||
|  |       - '**.md' | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   setup-graalpy: | ||||||
|  |     name: Setup GraalPy ${{ matrix.graalpy }} ${{ matrix.os }} | ||||||
|  |     runs-on: ${{ matrix.os }} | ||||||
|  |     strategy: | ||||||
|  |       fail-fast: false | ||||||
|  |       matrix: | ||||||
|  |         os: [macos-latest, ubuntu-20.04, ubuntu-latest] | ||||||
|  |         graalpy: | ||||||
|  |           - 'graalpy-23.0' | ||||||
|  |           - 'graalpy-22.3' | ||||||
|  |  | ||||||
|  |     steps: | ||||||
|  |       - name: Checkout | ||||||
|  |         uses: actions/checkout@v4 | ||||||
|  |  | ||||||
|  |       - name: setup-python ${{ matrix.graalpy }} | ||||||
|  |         id: setup-python | ||||||
|  |         uses: ./ | ||||||
|  |         with: | ||||||
|  |           python-version: ${{ matrix.graalpy }} | ||||||
|  |  | ||||||
|  |       - name: Check python-path | ||||||
|  |         run: ./__tests__/check-python-path.sh '${{ steps.setup-python.outputs.python-path }}' | ||||||
|  |         shell: bash | ||||||
|  |  | ||||||
|  |       - name: GraalPy and Python version | ||||||
|  |         run: python --version | ||||||
|  |  | ||||||
|  |       - name: Run simple code | ||||||
|  |         run: python -c 'import math; print(math.factorial(5))' | ||||||
|  |  | ||||||
|  |       - name: Assert GraalPy is running | ||||||
|  |         run: | | ||||||
|  |           import platform | ||||||
|  |           assert platform.python_implementation().lower() == "graalvm" | ||||||
|  |         shell: python | ||||||
|  |  | ||||||
|  |       - name: Assert expected binaries (or symlinks) are present | ||||||
|  |         run: | | ||||||
|  |           EXECUTABLE=${{ matrix.graalpy }} | ||||||
|  |           EXECUTABLE=${EXECUTABLE/graalpy-/graalpy}  # remove the first '-' in "graalpy-X.Y" -> "graalpyX.Y" to match executable name | ||||||
|  |           EXECUTABLE=${EXECUTABLE%%-*}  # remove any -* suffixe | ||||||
|  |           ${EXECUTABLE} --version | ||||||
|  |         shell: bash | ||||||
|  |  | ||||||
|  |   setup-graalpy-noenv: | ||||||
|  |     name: Setup GraalPy ${{ matrix.graalpy }} ${{ matrix.os }} (noenv) | ||||||
|  |     runs-on: ${{ matrix.os }} | ||||||
|  |     strategy: | ||||||
|  |       fail-fast: false | ||||||
|  |       matrix: | ||||||
|  |         os: [macos-latest, ubuntu-20.04, ubuntu-latest] | ||||||
|  |         graalpy: ['graalpy23.0', 'graalpy22.3'] | ||||||
|  |  | ||||||
|  |     steps: | ||||||
|  |       - name: Checkout | ||||||
|  |         uses: actions/checkout@v4 | ||||||
|  |  | ||||||
|  |       - name: setup-python ${{ matrix.graalpy }} | ||||||
|  |         id: setup-python | ||||||
|  |         uses: ./ | ||||||
|  |         with: | ||||||
|  |           python-version: ${{ matrix.graalpy }} | ||||||
|  |           update-environment: false | ||||||
|  |  | ||||||
|  |       - name: GraalPy and Python version | ||||||
|  |         run: ${{ steps.setup-python.outputs.python-path }} --version | ||||||
|  |  | ||||||
|  |       - name: Run simple code | ||||||
|  |         run: ${{ steps.setup-python.outputs.python-path }} -c 'import math; print(math.factorial(5))' | ||||||
|  |  | ||||||
|  |   check-latest: | ||||||
|  |     runs-on: ${{ matrix.os }} | ||||||
|  |     strategy: | ||||||
|  |       fail-fast: false | ||||||
|  |       matrix: | ||||||
|  |         os: [ubuntu-latest, macos-latest] | ||||||
|  |     steps: | ||||||
|  |       - uses: actions/checkout@v4 | ||||||
|  |       - name: Setup GraalPy and check latest | ||||||
|  |         uses: ./ | ||||||
|  |         id: graalpy | ||||||
|  |         with: | ||||||
|  |           python-version: 'graalpy-23.x' | ||||||
|  |           check-latest: true | ||||||
|  |       - name: GraalPy and Python version | ||||||
|  |         run: python --version | ||||||
|  |  | ||||||
|  |       - name: Run simple code | ||||||
|  |         run: python -c 'import math; print(math.factorial(5))' | ||||||
|  |  | ||||||
|  |       - name: Assert GraalPy is running | ||||||
|  |         run: | | ||||||
|  |           import platform | ||||||
|  |           assert platform.python_implementation().lower() == "graalvm" | ||||||
|  |         shell: python | ||||||
|  |  | ||||||
|  |       - name: Assert expected binaries (or symlinks) are present | ||||||
|  |         run: | | ||||||
|  |           EXECUTABLE='${{ steps.graalpy.outputs.python-version }}' | ||||||
|  |           EXECUTABLE="${EXECUTABLE%.*}" | ||||||
|  |           ${EXECUTABLE} --version | ||||||
|  |         shell: bash | ||||||
							
								
								
									
										8
									
								
								.github/workflows/test-pypy.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/workflows/test-pypy.yml
									
									
									
									
										vendored
									
									
								
							| @@ -35,7 +35,7 @@ jobs: | |||||||
|  |  | ||||||
|     steps: |     steps: | ||||||
|       - name: Checkout |       - name: Checkout | ||||||
|         uses: actions/checkout@v3 |         uses: actions/checkout@v4 | ||||||
|  |  | ||||||
|       - name: setup-python ${{ matrix.pypy }} |       - name: setup-python ${{ matrix.pypy }} | ||||||
|         id: setup-python |         id: setup-python | ||||||
| @@ -78,7 +78,7 @@ jobs: | |||||||
|  |  | ||||||
|     steps: |     steps: | ||||||
|       - name: Checkout |       - name: Checkout | ||||||
|         uses: actions/checkout@v3 |         uses: actions/checkout@v4 | ||||||
|  |  | ||||||
|       - name: setup-python ${{ matrix.pypy }} |       - name: setup-python ${{ matrix.pypy }} | ||||||
|         id: setup-python |         id: setup-python | ||||||
| @@ -100,7 +100,7 @@ jobs: | |||||||
|       matrix: |       matrix: | ||||||
|         os: [ubuntu-latest, windows-latest, macos-latest] |         os: [ubuntu-latest, windows-latest, macos-latest] | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v3 |       - uses: actions/checkout@v4 | ||||||
|       - name: Setup PyPy and check latest |       - name: Setup PyPy and check latest | ||||||
|         uses: ./ |         uses: ./ | ||||||
|         with: |         with: | ||||||
| @@ -133,7 +133,7 @@ jobs: | |||||||
|       matrix: |       matrix: | ||||||
|         os: [ubuntu-latest, windows-latest, macos-latest] |         os: [ubuntu-latest, windows-latest, macos-latest] | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v3 |       - uses: actions/checkout@v4 | ||||||
|       - name: Setup PyPy and check latest |       - name: Setup PyPy and check latest | ||||||
|         uses: ./ |         uses: ./ | ||||||
|         with: |         with: | ||||||
|   | |||||||
							
								
								
									
										22
									
								
								.github/workflows/test-python.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								.github/workflows/test-python.yml
									
									
									
									
										vendored
									
									
								
							| @@ -33,7 +33,7 @@ jobs: | |||||||
|             python: 3.8.15 |             python: 3.8.15 | ||||||
|     steps: |     steps: | ||||||
|       - name: Checkout |       - name: Checkout | ||||||
|         uses: actions/checkout@v3 |         uses: actions/checkout@v4 | ||||||
|  |  | ||||||
|       - name: setup-python ${{ matrix.python }} |       - name: setup-python ${{ matrix.python }} | ||||||
|         id: setup-python |         id: setup-python | ||||||
| @@ -77,7 +77,7 @@ jobs: | |||||||
|             python: 3.8.15 |             python: 3.8.15 | ||||||
|     steps: |     steps: | ||||||
|       - name: Checkout |       - name: Checkout | ||||||
|         uses: actions/checkout@v3 |         uses: actions/checkout@v4 | ||||||
|  |  | ||||||
|       - name: build-version-file ${{ matrix.python }} |       - name: build-version-file ${{ matrix.python }} | ||||||
|         run: echo ${{ matrix.python }} > .python-version |         run: echo ${{ matrix.python }} > .python-version | ||||||
| @@ -124,7 +124,7 @@ jobs: | |||||||
|             python: 3.8.15 |             python: 3.8.15 | ||||||
|     steps: |     steps: | ||||||
|       - name: Checkout |       - name: Checkout | ||||||
|         uses: actions/checkout@v3 |         uses: actions/checkout@v4 | ||||||
|  |  | ||||||
|       - name: build-version-file ${{ matrix.python }} |       - name: build-version-file ${{ matrix.python }} | ||||||
|         run: echo ${{ matrix.python }} > .python-version |         run: echo ${{ matrix.python }} > .python-version | ||||||
| @@ -169,7 +169,7 @@ jobs: | |||||||
|             python: 3.8.15 |             python: 3.8.15 | ||||||
|     steps: |     steps: | ||||||
|       - name: Checkout |       - name: Checkout | ||||||
|         uses: actions/checkout@v3 |         uses: actions/checkout@v4 | ||||||
|  |  | ||||||
|       - name: build-version-file ${{ matrix.python }} |       - name: build-version-file ${{ matrix.python }} | ||||||
|         run: | |         run: | | ||||||
| @@ -219,7 +219,7 @@ jobs: | |||||||
|             python: 3.8.15 |             python: 3.8.15 | ||||||
|     steps: |     steps: | ||||||
|       - name: Checkout |       - name: Checkout | ||||||
|         uses: actions/checkout@v3 |         uses: actions/checkout@v4 | ||||||
|  |  | ||||||
|       - name: build-version-file ${{ matrix.python }} |       - name: build-version-file ${{ matrix.python }} | ||||||
|         run: | |         run: | | ||||||
| @@ -259,7 +259,7 @@ jobs: | |||||||
|         os: [macos-latest, windows-latest, ubuntu-20.04] |         os: [macos-latest, windows-latest, ubuntu-20.04] | ||||||
|     steps: |     steps: | ||||||
|       - name: Checkout |       - name: Checkout | ||||||
|         uses: actions/checkout@v3 |         uses: actions/checkout@v4 | ||||||
|  |  | ||||||
|       - name: setup-python 3.9.0-beta.4 |       - name: setup-python 3.9.0-beta.4 | ||||||
|         id: setup-python |         id: setup-python | ||||||
| @@ -293,7 +293,7 @@ jobs: | |||||||
|         os: [macos-latest, windows-latest, ubuntu-latest] |         os: [macos-latest, windows-latest, ubuntu-latest] | ||||||
|     steps: |     steps: | ||||||
|       - name: Checkout |       - name: Checkout | ||||||
|         uses: actions/checkout@v3 |         uses: actions/checkout@v4 | ||||||
|  |  | ||||||
|       - name: setup-python 3.9-dev |       - name: setup-python 3.9-dev | ||||||
|         id: setup-python |         id: setup-python | ||||||
| @@ -321,7 +321,7 @@ jobs: | |||||||
|         os: [macos-latest, windows-latest, ubuntu-latest] |         os: [macos-latest, windows-latest, ubuntu-latest] | ||||||
|     steps: |     steps: | ||||||
|       - name: Checkout |       - name: Checkout | ||||||
|         uses: actions/checkout@v3 |         uses: actions/checkout@v4 | ||||||
|  |  | ||||||
|       - name: setup-python 3.12 |       - name: setup-python 3.12 | ||||||
|         id: setup-python |         id: setup-python | ||||||
| @@ -351,7 +351,7 @@ jobs: | |||||||
|         python: ['3.7', '3.8', '3.9', '3.10'] |         python: ['3.7', '3.8', '3.9', '3.10'] | ||||||
|     steps: |     steps: | ||||||
|       - name: Checkout |       - name: Checkout | ||||||
|         uses: actions/checkout@v3 |         uses: actions/checkout@v4 | ||||||
|  |  | ||||||
|       - name: setup-python ${{ matrix.python }} |       - name: setup-python ${{ matrix.python }} | ||||||
|         id: setup-python |         id: setup-python | ||||||
| @@ -374,7 +374,7 @@ jobs: | |||||||
|         os: [ubuntu-latest, windows-latest, macos-latest] |         os: [ubuntu-latest, windows-latest, macos-latest] | ||||||
|         python-version: ['3.8', '3.9', '3.10'] |         python-version: ['3.8', '3.9', '3.10'] | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v3 |       - uses: actions/checkout@v4 | ||||||
|       - name: Setup Python and check latest |       - name: Setup Python and check latest | ||||||
|         uses: ./ |         uses: ./ | ||||||
|         with: |         with: | ||||||
| @@ -397,7 +397,7 @@ jobs: | |||||||
|       matrix: |       matrix: | ||||||
|         os: [ubuntu-latest, windows-latest, macos-latest] |         os: [ubuntu-latest, windows-latest, macos-latest] | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v3 |       - uses: actions/checkout@v4 | ||||||
|       - name: Setup Python and check latest |       - name: Setup Python and check latest | ||||||
|         uses: ./ |         uses: ./ | ||||||
|         with: |         with: | ||||||
|   | |||||||
| @@ -1,9 +1,9 @@ | |||||||
| --- | --- | ||||||
| name: semver | name: semver | ||||||
| version: 6.3.0 | version: 6.3.1 | ||||||
| type: npm | type: npm | ||||||
| summary: The semantic version parser used by npm. | summary: The semantic version parser used by npm. | ||||||
| homepage: https://github.com/npm/node-semver#readme | homepage:  | ||||||
| license: isc | license: isc | ||||||
| licenses: | licenses: | ||||||
| - sources: LICENSE | - sources: LICENSE | ||||||
| @@ -18,7 +18,7 @@ See [action.yml](action.yml) | |||||||
| **Python** | **Python** | ||||||
| ```yaml | ```yaml | ||||||
| steps: | steps: | ||||||
| - uses: actions/checkout@v3 | - uses: actions/checkout@v4 | ||||||
| - uses: actions/setup-python@v4 | - uses: actions/setup-python@v4 | ||||||
|   with: |   with: | ||||||
|     python-version: '3.10'  |     python-version: '3.10'  | ||||||
| @@ -28,7 +28,7 @@ steps: | |||||||
| **PyPy** | **PyPy** | ||||||
| ```yaml | ```yaml | ||||||
| steps: | steps: | ||||||
| - uses: actions/checkout@v3 | - uses: actions/checkout@v4 | ||||||
| - uses: actions/setup-python@v4  | - uses: actions/setup-python@v4  | ||||||
|   with: |   with: | ||||||
|     python-version: 'pypy3.9'  |     python-version: 'pypy3.9'  | ||||||
| @@ -62,7 +62,7 @@ The action defaults to searching for a dependency file (`requirements.txt` or `p | |||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
| steps: | steps: | ||||||
| - uses: actions/checkout@v3 | - uses: actions/checkout@v4 | ||||||
| - uses: actions/setup-python@v4 | - uses: actions/setup-python@v4 | ||||||
|   with: |   with: | ||||||
|     python-version: '3.9' |     python-version: '3.9' | ||||||
|   | |||||||
							
								
								
									
										5798
									
								
								__tests__/data/graalpy.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5798
									
								
								__tests__/data/graalpy.json
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										378
									
								
								__tests__/find-graalpy.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										378
									
								
								__tests__/find-graalpy.test.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,378 @@ | |||||||
|  | import fs from 'fs'; | ||||||
|  |  | ||||||
|  | import {HttpClient} from '@actions/http-client'; | ||||||
|  | import * as ifm from '@actions/http-client/interfaces'; | ||||||
|  | import * as tc from '@actions/tool-cache'; | ||||||
|  | import * as exec from '@actions/exec'; | ||||||
|  | import * as core from '@actions/core'; | ||||||
|  |  | ||||||
|  | import * as path from 'path'; | ||||||
|  | import * as semver from 'semver'; | ||||||
|  |  | ||||||
|  | import * as finder from '../src/find-graalpy'; | ||||||
|  | import {IGraalPyManifestRelease, IS_WINDOWS} from '../src/utils'; | ||||||
|  |  | ||||||
|  | import manifestData from './data/graalpy.json'; | ||||||
|  |  | ||||||
|  | const architecture = 'x64'; | ||||||
|  |  | ||||||
|  | const toolDir = path.join(__dirname, 'runner', 'tools'); | ||||||
|  | const tempDir = path.join(__dirname, 'runner', 'temp'); | ||||||
|  |  | ||||||
|  | /* GraalPy doesn't have a windows release yet */ | ||||||
|  | const describeSkipOnWindows = IS_WINDOWS ? describe.skip : describe; | ||||||
|  |  | ||||||
|  | describe('parseGraalPyVersion', () => { | ||||||
|  |   it.each([ | ||||||
|  |     ['graalpy-23', '23'], | ||||||
|  |     ['graalpy-23.0', '23.0'], | ||||||
|  |     ['graalpy23.0', '23.0'] | ||||||
|  |   ])('%s -> %s', (input, expected) => { | ||||||
|  |     expect(finder.parseGraalPyVersion(input)).toEqual(expected); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it.each(['', 'graalpy-', 'graalpy', 'p', 'notgraalpy-'])( | ||||||
|  |     'throw on invalid input "%s"', | ||||||
|  |     input => { | ||||||
|  |       expect(() => finder.parseGraalPyVersion(input)).toThrow( | ||||||
|  |         "Invalid 'version' property for GraalPy. GraalPy version should be specified as 'graalpy<python-version>' or 'graalpy-<python-version>'. See README for examples and documentation." | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |   ); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | describe('findGraalPyToolCache', () => { | ||||||
|  |   const actualGraalPyVersion = '23.0.0'; | ||||||
|  |   const graalpyPath = path.join('GraalPy', actualGraalPyVersion, architecture); | ||||||
|  |   let tcFind: jest.SpyInstance; | ||||||
|  |   let infoSpy: jest.SpyInstance; | ||||||
|  |   let warningSpy: jest.SpyInstance; | ||||||
|  |   let debugSpy: jest.SpyInstance; | ||||||
|  |   let addPathSpy: jest.SpyInstance; | ||||||
|  |   let exportVariableSpy: jest.SpyInstance; | ||||||
|  |   let setOutputSpy: jest.SpyInstance; | ||||||
|  |  | ||||||
|  |   beforeEach(() => { | ||||||
|  |     tcFind = jest.spyOn(tc, 'find'); | ||||||
|  |     tcFind.mockImplementation((toolname: string, pythonVersion: string) => { | ||||||
|  |       const semverVersion = new semver.Range(pythonVersion); | ||||||
|  |       return semver.satisfies(actualGraalPyVersion, semverVersion) | ||||||
|  |         ? graalpyPath | ||||||
|  |         : ''; | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     infoSpy = jest.spyOn(core, 'info'); | ||||||
|  |     infoSpy.mockImplementation(() => null); | ||||||
|  |  | ||||||
|  |     warningSpy = jest.spyOn(core, 'warning'); | ||||||
|  |     warningSpy.mockImplementation(() => null); | ||||||
|  |  | ||||||
|  |     debugSpy = jest.spyOn(core, 'debug'); | ||||||
|  |     debugSpy.mockImplementation(() => null); | ||||||
|  |  | ||||||
|  |     addPathSpy = jest.spyOn(core, 'addPath'); | ||||||
|  |     addPathSpy.mockImplementation(() => null); | ||||||
|  |  | ||||||
|  |     exportVariableSpy = jest.spyOn(core, 'exportVariable'); | ||||||
|  |     exportVariableSpy.mockImplementation(() => null); | ||||||
|  |  | ||||||
|  |     setOutputSpy = jest.spyOn(core, 'setOutput'); | ||||||
|  |     setOutputSpy.mockImplementation(() => null); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   afterEach(() => { | ||||||
|  |     jest.resetAllMocks(); | ||||||
|  |     jest.clearAllMocks(); | ||||||
|  |     jest.restoreAllMocks(); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('GraalPy exists on the path and versions are satisfied', () => { | ||||||
|  |     expect(finder.findGraalPyToolCache('23.0.0', architecture)).toEqual({ | ||||||
|  |       installDir: graalpyPath, | ||||||
|  |       resolvedGraalPyVersion: actualGraalPyVersion | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('GraalPy exists on the path and versions are satisfied with semver', () => { | ||||||
|  |     expect(finder.findGraalPyToolCache('23.0', architecture)).toEqual({ | ||||||
|  |       installDir: graalpyPath, | ||||||
|  |       resolvedGraalPyVersion: actualGraalPyVersion | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it("GraalPy exists on the path, but version doesn't match", () => { | ||||||
|  |     expect(finder.findGraalPyToolCache('22.3', architecture)).toEqual({ | ||||||
|  |       installDir: '', | ||||||
|  |       resolvedGraalPyVersion: '' | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | describeSkipOnWindows('findGraalPyVersion', () => { | ||||||
|  |   let getBooleanInputSpy: jest.SpyInstance; | ||||||
|  |   let warningSpy: jest.SpyInstance; | ||||||
|  |   let debugSpy: jest.SpyInstance; | ||||||
|  |   let infoSpy: jest.SpyInstance; | ||||||
|  |   let addPathSpy: jest.SpyInstance; | ||||||
|  |   let exportVariableSpy: jest.SpyInstance; | ||||||
|  |   let setOutputSpy: jest.SpyInstance; | ||||||
|  |   let tcFind: jest.SpyInstance; | ||||||
|  |   let spyExtractZip: jest.SpyInstance; | ||||||
|  |   let spyExtractTar: jest.SpyInstance; | ||||||
|  |   let spyHttpClient: jest.SpyInstance; | ||||||
|  |   let spyExistsSync: jest.SpyInstance; | ||||||
|  |   let spyExec: jest.SpyInstance; | ||||||
|  |   let spySymlinkSync: jest.SpyInstance; | ||||||
|  |   let spyDownloadTool: jest.SpyInstance; | ||||||
|  |   let spyFsReadDir: jest.SpyInstance; | ||||||
|  |   let spyCacheDir: jest.SpyInstance; | ||||||
|  |   let spyChmodSync: jest.SpyInstance; | ||||||
|  |   let spyCoreAddPath: jest.SpyInstance; | ||||||
|  |   let spyCoreExportVariable: jest.SpyInstance; | ||||||
|  |   const env = process.env; | ||||||
|  |  | ||||||
|  |   beforeEach(() => { | ||||||
|  |     getBooleanInputSpy = jest.spyOn(core, 'getBooleanInput'); | ||||||
|  |     getBooleanInputSpy.mockImplementation(() => false); | ||||||
|  |  | ||||||
|  |     infoSpy = jest.spyOn(core, 'info'); | ||||||
|  |     infoSpy.mockImplementation(() => {}); | ||||||
|  |  | ||||||
|  |     warningSpy = jest.spyOn(core, 'warning'); | ||||||
|  |     warningSpy.mockImplementation(() => null); | ||||||
|  |  | ||||||
|  |     debugSpy = jest.spyOn(core, 'debug'); | ||||||
|  |     debugSpy.mockImplementation(() => null); | ||||||
|  |  | ||||||
|  |     addPathSpy = jest.spyOn(core, 'addPath'); | ||||||
|  |     addPathSpy.mockImplementation(() => null); | ||||||
|  |  | ||||||
|  |     exportVariableSpy = jest.spyOn(core, 'exportVariable'); | ||||||
|  |     exportVariableSpy.mockImplementation(() => null); | ||||||
|  |  | ||||||
|  |     setOutputSpy = jest.spyOn(core, 'setOutput'); | ||||||
|  |     setOutputSpy.mockImplementation(() => null); | ||||||
|  |  | ||||||
|  |     jest.resetModules(); | ||||||
|  |     process.env = {...env}; | ||||||
|  |     tcFind = jest.spyOn(tc, 'find'); | ||||||
|  |     tcFind.mockImplementation((tool: string, version: string) => { | ||||||
|  |       const semverRange = new semver.Range(version); | ||||||
|  |       let graalpyPath = ''; | ||||||
|  |       if (semver.satisfies('23.0.0', semverRange)) { | ||||||
|  |         graalpyPath = path.join(toolDir, 'GraalPy', '23.0.0', architecture); | ||||||
|  |       } | ||||||
|  |       return graalpyPath; | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     spyDownloadTool = jest.spyOn(tc, 'downloadTool'); | ||||||
|  |     spyDownloadTool.mockImplementation(() => path.join(tempDir, 'GraalPy')); | ||||||
|  |  | ||||||
|  |     spyExtractZip = jest.spyOn(tc, 'extractZip'); | ||||||
|  |     spyExtractZip.mockImplementation(() => tempDir); | ||||||
|  |  | ||||||
|  |     spyExtractTar = jest.spyOn(tc, 'extractTar'); | ||||||
|  |     spyExtractTar.mockImplementation(() => tempDir); | ||||||
|  |  | ||||||
|  |     spyFsReadDir = jest.spyOn(fs, 'readdirSync'); | ||||||
|  |     spyFsReadDir.mockImplementation((directory: string) => ['GraalPyTest']); | ||||||
|  |  | ||||||
|  |     spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); | ||||||
|  |     spyHttpClient.mockImplementation( | ||||||
|  |       async (): Promise<ifm.ITypedResponse<IGraalPyManifestRelease[]>> => { | ||||||
|  |         const result = JSON.stringify(manifestData); | ||||||
|  |         return { | ||||||
|  |           statusCode: 200, | ||||||
|  |           headers: {}, | ||||||
|  |           result: JSON.parse(result) as IGraalPyManifestRelease[] | ||||||
|  |         }; | ||||||
|  |       } | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     spyExec = jest.spyOn(exec, 'exec'); | ||||||
|  |     spyExec.mockImplementation(() => undefined); | ||||||
|  |  | ||||||
|  |     spySymlinkSync = jest.spyOn(fs, 'symlinkSync'); | ||||||
|  |     spySymlinkSync.mockImplementation(() => undefined); | ||||||
|  |  | ||||||
|  |     spyExistsSync = jest.spyOn(fs, 'existsSync'); | ||||||
|  |     spyExistsSync.mockReturnValue(true); | ||||||
|  |  | ||||||
|  |     spyCoreAddPath = jest.spyOn(core, 'addPath'); | ||||||
|  |  | ||||||
|  |     spyCoreExportVariable = jest.spyOn(core, 'exportVariable'); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   afterEach(() => { | ||||||
|  |     jest.resetAllMocks(); | ||||||
|  |     jest.clearAllMocks(); | ||||||
|  |     jest.restoreAllMocks(); | ||||||
|  |     process.env = env; | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('found GraalPy in toolcache', async () => { | ||||||
|  |     await expect( | ||||||
|  |       finder.findGraalPyVersion( | ||||||
|  |         'graalpy-23.0', | ||||||
|  |         architecture, | ||||||
|  |         true, | ||||||
|  |         false, | ||||||
|  |         false | ||||||
|  |       ) | ||||||
|  |     ).resolves.toEqual('23.0.0'); | ||||||
|  |     expect(spyCoreAddPath).toHaveBeenCalled(); | ||||||
|  |     expect(spyCoreExportVariable).toHaveBeenCalledWith( | ||||||
|  |       'pythonLocation', | ||||||
|  |       expect.anything() | ||||||
|  |     ); | ||||||
|  |     expect(spyCoreExportVariable).toHaveBeenCalledWith( | ||||||
|  |       'PKG_CONFIG_PATH', | ||||||
|  |       expect.anything() | ||||||
|  |     ); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('throw on invalid input format', async () => { | ||||||
|  |     await expect( | ||||||
|  |       finder.findGraalPyVersion('graalpy-x23', architecture, true, false, false) | ||||||
|  |     ).rejects.toThrow(); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('found and install successfully', async () => { | ||||||
|  |     spyCacheDir = jest.spyOn(tc, 'cacheDir'); | ||||||
|  |     spyCacheDir.mockImplementation(() => | ||||||
|  |       path.join(toolDir, 'GraalPy', '23.0.0', architecture) | ||||||
|  |     ); | ||||||
|  |     spyChmodSync = jest.spyOn(fs, 'chmodSync'); | ||||||
|  |     spyChmodSync.mockImplementation(() => undefined); | ||||||
|  |     await expect( | ||||||
|  |       finder.findGraalPyVersion( | ||||||
|  |         'graalpy-23.0.0', | ||||||
|  |         architecture, | ||||||
|  |         true, | ||||||
|  |         false, | ||||||
|  |         false | ||||||
|  |       ) | ||||||
|  |     ).resolves.toEqual('23.0.0'); | ||||||
|  |     expect(spyCoreAddPath).toHaveBeenCalled(); | ||||||
|  |     expect(spyCoreExportVariable).toHaveBeenCalledWith( | ||||||
|  |       'pythonLocation', | ||||||
|  |       expect.anything() | ||||||
|  |     ); | ||||||
|  |     expect(spyCoreExportVariable).toHaveBeenCalledWith( | ||||||
|  |       'PKG_CONFIG_PATH', | ||||||
|  |       expect.anything() | ||||||
|  |     ); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('found and install successfully without environment update', async () => { | ||||||
|  |     spyCacheDir = jest.spyOn(tc, 'cacheDir'); | ||||||
|  |     spyCacheDir.mockImplementation(() => | ||||||
|  |       path.join(toolDir, 'GraalPy', '23.0.0', architecture) | ||||||
|  |     ); | ||||||
|  |     spyChmodSync = jest.spyOn(fs, 'chmodSync'); | ||||||
|  |     spyChmodSync.mockImplementation(() => undefined); | ||||||
|  |     await expect( | ||||||
|  |       finder.findGraalPyVersion( | ||||||
|  |         'graalpy-23.0.0', | ||||||
|  |         architecture, | ||||||
|  |         false, | ||||||
|  |         false, | ||||||
|  |         false | ||||||
|  |       ) | ||||||
|  |     ).resolves.toEqual('23.0.0'); | ||||||
|  |     expect(spyCoreAddPath).not.toHaveBeenCalled(); | ||||||
|  |     expect(spyCoreExportVariable).not.toHaveBeenCalled(); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('throw if release is not found', async () => { | ||||||
|  |     await expect( | ||||||
|  |       finder.findGraalPyVersion( | ||||||
|  |         'graalpy-19.0.0', | ||||||
|  |         architecture, | ||||||
|  |         true, | ||||||
|  |         false, | ||||||
|  |         false | ||||||
|  |       ) | ||||||
|  |     ).rejects.toThrow( | ||||||
|  |       `GraalPy version 19.0.0 with arch ${architecture} not found` | ||||||
|  |     ); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('check-latest enabled version found and used from toolcache', async () => { | ||||||
|  |     await expect( | ||||||
|  |       finder.findGraalPyVersion( | ||||||
|  |         'graalpy-23.0.0', | ||||||
|  |         architecture, | ||||||
|  |         false, | ||||||
|  |         true, | ||||||
|  |         false | ||||||
|  |       ) | ||||||
|  |     ).resolves.toEqual('23.0.0'); | ||||||
|  |  | ||||||
|  |     expect(infoSpy).toHaveBeenCalledWith('Resolved as GraalPy 23.0.0'); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('check-latest enabled version found and install successfully', async () => { | ||||||
|  |     spyCacheDir = jest.spyOn(tc, 'cacheDir'); | ||||||
|  |     spyCacheDir.mockImplementation(() => | ||||||
|  |       path.join(toolDir, 'GraalPy', '23.0.0', architecture) | ||||||
|  |     ); | ||||||
|  |     spyChmodSync = jest.spyOn(fs, 'chmodSync'); | ||||||
|  |     spyChmodSync.mockImplementation(() => undefined); | ||||||
|  |     await expect( | ||||||
|  |       finder.findGraalPyVersion( | ||||||
|  |         'graalpy-23.0.0', | ||||||
|  |         architecture, | ||||||
|  |         false, | ||||||
|  |         true, | ||||||
|  |         false | ||||||
|  |       ) | ||||||
|  |     ).resolves.toEqual('23.0.0'); | ||||||
|  |     expect(infoSpy).toHaveBeenCalledWith('Resolved as GraalPy 23.0.0'); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('check-latest enabled version is not found and used from toolcache', async () => { | ||||||
|  |     tcFind.mockImplementationOnce((tool: string, version: string) => { | ||||||
|  |       const semverRange = new semver.Range(version); | ||||||
|  |       let graalpyPath = ''; | ||||||
|  |       if (semver.satisfies('22.3.4', semverRange)) { | ||||||
|  |         graalpyPath = path.join(toolDir, 'GraalPy', '22.3.4', architecture); | ||||||
|  |       } | ||||||
|  |       return graalpyPath; | ||||||
|  |     }); | ||||||
|  |     await expect( | ||||||
|  |       finder.findGraalPyVersion( | ||||||
|  |         'graalpy-22.3.4', | ||||||
|  |         architecture, | ||||||
|  |         false, | ||||||
|  |         true, | ||||||
|  |         false | ||||||
|  |       ) | ||||||
|  |     ).resolves.toEqual('22.3.4'); | ||||||
|  |  | ||||||
|  |     expect(infoSpy).toHaveBeenCalledWith( | ||||||
|  |       'Failed to resolve GraalPy 22.3.4 from manifest' | ||||||
|  |     ); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('found and install successfully, pre-release fallback', async () => { | ||||||
|  |     spyCacheDir = jest.spyOn(tc, 'cacheDir'); | ||||||
|  |     spyCacheDir.mockImplementation(() => | ||||||
|  |       path.join(toolDir, 'GraalPy', '23.1', architecture) | ||||||
|  |     ); | ||||||
|  |     spyChmodSync = jest.spyOn(fs, 'chmodSync'); | ||||||
|  |     spyChmodSync.mockImplementation(() => undefined); | ||||||
|  |     await expect( | ||||||
|  |       finder.findGraalPyVersion( | ||||||
|  |         'graalpy23.1', | ||||||
|  |         architecture, | ||||||
|  |         false, | ||||||
|  |         false, | ||||||
|  |         false | ||||||
|  |       ) | ||||||
|  |     ).rejects.toThrow(); | ||||||
|  |     await expect( | ||||||
|  |       finder.findGraalPyVersion('graalpy23.1', architecture, false, false, true) | ||||||
|  |     ).resolves.toEqual('23.1.0-a.1'); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
							
								
								
									
										256
									
								
								__tests__/install-graalpy.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										256
									
								
								__tests__/install-graalpy.test.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,256 @@ | |||||||
|  | import fs from 'fs'; | ||||||
|  |  | ||||||
|  | import {HttpClient} from '@actions/http-client'; | ||||||
|  | import * as ifm from '@actions/http-client/interfaces'; | ||||||
|  | import * as tc from '@actions/tool-cache'; | ||||||
|  | import * as exec from '@actions/exec'; | ||||||
|  | import * as core from '@actions/core'; | ||||||
|  | import * as path from 'path'; | ||||||
|  |  | ||||||
|  | import * as installer from '../src/install-graalpy'; | ||||||
|  | import { | ||||||
|  |   IGraalPyManifestRelease, | ||||||
|  |   IGraalPyManifestAsset, | ||||||
|  |   IS_WINDOWS | ||||||
|  | } from '../src/utils'; | ||||||
|  |  | ||||||
|  | import manifestData from './data/graalpy.json'; | ||||||
|  |  | ||||||
|  | const architecture = 'x64'; | ||||||
|  |  | ||||||
|  | const toolDir = path.join(__dirname, 'runner', 'tools'); | ||||||
|  | const tempDir = path.join(__dirname, 'runner', 'temp'); | ||||||
|  |  | ||||||
|  | /* GraalPy doesn't have a windows release yet */ | ||||||
|  | const describeSkipOnWindows = IS_WINDOWS ? describe.skip : describe; | ||||||
|  |  | ||||||
|  | describe('graalpyVersionToSemantic', () => { | ||||||
|  |   it.each([ | ||||||
|  |     ['23.0.0a1', '23.0.0a1'], | ||||||
|  |     ['23.0.0', '23.0.0'], | ||||||
|  |     ['23.0.x', '23.0.x'], | ||||||
|  |     ['23.x', '23.x'] | ||||||
|  |   ])('%s -> %s', (input, expected) => { | ||||||
|  |     expect(installer.graalPyTagToVersion(input)).toEqual(expected); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | describeSkipOnWindows('findRelease', () => { | ||||||
|  |   const result = JSON.stringify(manifestData); | ||||||
|  |   const releases = JSON.parse(result) as IGraalPyManifestRelease[]; | ||||||
|  |   const extension = 'tar.gz'; | ||||||
|  |   const arch = installer.toGraalPyArchitecture(architecture); | ||||||
|  |   const platform = installer.toGraalPyPlatform(process.platform); | ||||||
|  |   const extensionName = `${platform}-${arch}.${extension}`; | ||||||
|  |   const files: IGraalPyManifestAsset = { | ||||||
|  |     name: `graalpython-23.0.0-${extensionName}`, | ||||||
|  |     browser_download_url: `https://github.com/oracle/graalpython/releases/download/graal-23.0.0/graalpython-23.0.0-${extensionName}` | ||||||
|  |   }; | ||||||
|  |   const filesRC1: IGraalPyManifestAsset = { | ||||||
|  |     name: `graalpython-23.1.0a1-${extensionName}`, | ||||||
|  |     browser_download_url: `https://github.com/oracle/graalpython/releases/download/graal-23.1.0a1/graalpython-23.1.0a1-${extensionName}` | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   let warningSpy: jest.SpyInstance; | ||||||
|  |   let debugSpy: jest.SpyInstance; | ||||||
|  |   let infoSpy: jest.SpyInstance; | ||||||
|  |  | ||||||
|  |   beforeEach(() => { | ||||||
|  |     infoSpy = jest.spyOn(core, 'info'); | ||||||
|  |     infoSpy.mockImplementation(() => {}); | ||||||
|  |  | ||||||
|  |     warningSpy = jest.spyOn(core, 'warning'); | ||||||
|  |     warningSpy.mockImplementation(() => null); | ||||||
|  |  | ||||||
|  |     debugSpy = jest.spyOn(core, 'debug'); | ||||||
|  |     debugSpy.mockImplementation(() => null); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it("GraalPy version doesn't match", () => { | ||||||
|  |     const graalpyVersion = '12.0.0'; | ||||||
|  |     expect( | ||||||
|  |       installer.findRelease(releases, graalpyVersion, architecture, false) | ||||||
|  |     ).toEqual(null); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('GraalPy version matches', () => { | ||||||
|  |     const graalpyVersion = '23.0.0'; | ||||||
|  |     expect( | ||||||
|  |       installer.findRelease(releases, graalpyVersion, architecture, false) | ||||||
|  |     ).toMatchObject({ | ||||||
|  |       foundAsset: files, | ||||||
|  |       resolvedGraalPyVersion: graalpyVersion | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('Preview version of GraalPy is found', () => { | ||||||
|  |     const graalpyVersion = installer.graalPyTagToVersion('vm-23.1.0a1'); | ||||||
|  |     expect( | ||||||
|  |       installer.findRelease(releases, graalpyVersion, architecture, false) | ||||||
|  |     ).toMatchObject({ | ||||||
|  |       foundAsset: { | ||||||
|  |         name: `graalpython-23.1.0a1-${extensionName}`, | ||||||
|  |         browser_download_url: `https://github.com/oracle/graalpython/releases/download/graal-23.1.0a1/graalpython-23.1.0a1-${extensionName}` | ||||||
|  |       }, | ||||||
|  |       resolvedGraalPyVersion: '23.1.0-a.1' | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('Latest GraalPy is found', () => { | ||||||
|  |     const graalpyVersion = 'x'; | ||||||
|  |     expect( | ||||||
|  |       installer.findRelease(releases, graalpyVersion, architecture, false) | ||||||
|  |     ).toMatchObject({ | ||||||
|  |       foundAsset: files, | ||||||
|  |       resolvedGraalPyVersion: '23.0.0' | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('GraalPy version matches semver (pre-release)', () => { | ||||||
|  |     const graalpyVersion = '23.1.x'; | ||||||
|  |     expect( | ||||||
|  |       installer.findRelease(releases, graalpyVersion, architecture, false) | ||||||
|  |     ).toBeNull(); | ||||||
|  |     expect( | ||||||
|  |       installer.findRelease(releases, graalpyVersion, architecture, true) | ||||||
|  |     ).toMatchObject({ | ||||||
|  |       foundAsset: filesRC1, | ||||||
|  |       resolvedGraalPyVersion: '23.1.0-a.1' | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | describeSkipOnWindows('installGraalPy', () => { | ||||||
|  |   let tcFind: jest.SpyInstance; | ||||||
|  |   let warningSpy: jest.SpyInstance; | ||||||
|  |   let debugSpy: jest.SpyInstance; | ||||||
|  |   let infoSpy: jest.SpyInstance; | ||||||
|  |   let spyExtractZip: jest.SpyInstance; | ||||||
|  |   let spyExtractTar: jest.SpyInstance; | ||||||
|  |   let spyFsReadDir: jest.SpyInstance; | ||||||
|  |   let spyFsWriteFile: jest.SpyInstance; | ||||||
|  |   let spyHttpClient: jest.SpyInstance; | ||||||
|  |   let spyExistsSync: jest.SpyInstance; | ||||||
|  |   let spyExec: jest.SpyInstance; | ||||||
|  |   let spySymlinkSync: jest.SpyInstance; | ||||||
|  |   let spyDownloadTool: jest.SpyInstance; | ||||||
|  |   let spyCacheDir: jest.SpyInstance; | ||||||
|  |   let spyChmodSync: jest.SpyInstance; | ||||||
|  |  | ||||||
|  |   beforeEach(() => { | ||||||
|  |     tcFind = jest.spyOn(tc, 'find'); | ||||||
|  |     tcFind.mockImplementation(() => | ||||||
|  |       path.join('GraalPy', '3.6.12', architecture) | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     spyDownloadTool = jest.spyOn(tc, 'downloadTool'); | ||||||
|  |     spyDownloadTool.mockImplementation(() => path.join(tempDir, 'GraalPy')); | ||||||
|  |  | ||||||
|  |     spyExtractZip = jest.spyOn(tc, 'extractZip'); | ||||||
|  |     spyExtractZip.mockImplementation(() => tempDir); | ||||||
|  |  | ||||||
|  |     spyExtractTar = jest.spyOn(tc, 'extractTar'); | ||||||
|  |     spyExtractTar.mockImplementation(() => tempDir); | ||||||
|  |  | ||||||
|  |     infoSpy = jest.spyOn(core, 'info'); | ||||||
|  |     infoSpy.mockImplementation(() => {}); | ||||||
|  |  | ||||||
|  |     warningSpy = jest.spyOn(core, 'warning'); | ||||||
|  |     warningSpy.mockImplementation(() => null); | ||||||
|  |  | ||||||
|  |     debugSpy = jest.spyOn(core, 'debug'); | ||||||
|  |     debugSpy.mockImplementation(() => null); | ||||||
|  |  | ||||||
|  |     spyFsReadDir = jest.spyOn(fs, 'readdirSync'); | ||||||
|  |     spyFsReadDir.mockImplementation(() => ['GraalPyTest']); | ||||||
|  |  | ||||||
|  |     spyFsWriteFile = jest.spyOn(fs, 'writeFileSync'); | ||||||
|  |     spyFsWriteFile.mockImplementation(() => undefined); | ||||||
|  |  | ||||||
|  |     spyHttpClient = jest.spyOn(HttpClient.prototype, 'getJson'); | ||||||
|  |     spyHttpClient.mockImplementation( | ||||||
|  |       async (): Promise<ifm.ITypedResponse<IGraalPyManifestRelease[]>> => { | ||||||
|  |         const result = JSON.stringify(manifestData); | ||||||
|  |         return { | ||||||
|  |           statusCode: 200, | ||||||
|  |           headers: {}, | ||||||
|  |           result: JSON.parse(result) as IGraalPyManifestRelease[] | ||||||
|  |         }; | ||||||
|  |       } | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     spyExec = jest.spyOn(exec, 'exec'); | ||||||
|  |     spyExec.mockImplementation(() => undefined); | ||||||
|  |  | ||||||
|  |     spySymlinkSync = jest.spyOn(fs, 'symlinkSync'); | ||||||
|  |     spySymlinkSync.mockImplementation(() => undefined); | ||||||
|  |  | ||||||
|  |     spyExistsSync = jest.spyOn(fs, 'existsSync'); | ||||||
|  |     spyExistsSync.mockImplementation(() => false); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   afterEach(() => { | ||||||
|  |     jest.resetAllMocks(); | ||||||
|  |     jest.clearAllMocks(); | ||||||
|  |     jest.restoreAllMocks(); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('throw if release is not found', async () => { | ||||||
|  |     await expect( | ||||||
|  |       installer.installGraalPy('7.3.3', architecture, false, undefined) | ||||||
|  |     ).rejects.toThrow( | ||||||
|  |       `GraalPy version 7.3.3 with arch ${architecture} not found` | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     expect(spyHttpClient).toHaveBeenCalled(); | ||||||
|  |     expect(spyDownloadTool).not.toHaveBeenCalled(); | ||||||
|  |     expect(spyExec).not.toHaveBeenCalled(); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('found and install GraalPy', async () => { | ||||||
|  |     spyCacheDir = jest.spyOn(tc, 'cacheDir'); | ||||||
|  |     spyCacheDir.mockImplementation(() => | ||||||
|  |       path.join(toolDir, 'GraalPy', '21.3.0', architecture) | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     spyChmodSync = jest.spyOn(fs, 'chmodSync'); | ||||||
|  |     spyChmodSync.mockImplementation(() => undefined); | ||||||
|  |  | ||||||
|  |     await expect( | ||||||
|  |       installer.installGraalPy('21.x', architecture, false, undefined) | ||||||
|  |     ).resolves.toEqual({ | ||||||
|  |       installDir: path.join(toolDir, 'GraalPy', '21.3.0', architecture), | ||||||
|  |       resolvedGraalPyVersion: '21.3.0' | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     expect(spyHttpClient).toHaveBeenCalled(); | ||||||
|  |     expect(spyDownloadTool).toHaveBeenCalled(); | ||||||
|  |     expect(spyCacheDir).toHaveBeenCalled(); | ||||||
|  |     expect(spyExec).toHaveBeenCalled(); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('found and install GraalPy, pre-release fallback', async () => { | ||||||
|  |     spyCacheDir = jest.spyOn(tc, 'cacheDir'); | ||||||
|  |     spyCacheDir.mockImplementation(() => | ||||||
|  |       path.join(toolDir, 'GraalPy', '23.1.0', architecture) | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     spyChmodSync = jest.spyOn(fs, 'chmodSync'); | ||||||
|  |     spyChmodSync.mockImplementation(() => undefined); | ||||||
|  |  | ||||||
|  |     await expect( | ||||||
|  |       installer.installGraalPy('23.1.x', architecture, false, undefined) | ||||||
|  |     ).rejects.toThrow(); | ||||||
|  |     await expect( | ||||||
|  |       installer.installGraalPy('23.1.x', architecture, true, undefined) | ||||||
|  |     ).resolves.toEqual({ | ||||||
|  |       installDir: path.join(toolDir, 'GraalPy', '23.1.0', architecture), | ||||||
|  |       resolvedGraalPyVersion: '23.1.0-a.1' | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     expect(spyHttpClient).toHaveBeenCalled(); | ||||||
|  |     expect(spyDownloadTool).toHaveBeenCalled(); | ||||||
|  |     expect(spyCacheDir).toHaveBeenCalled(); | ||||||
|  |     expect(spyExec).toHaveBeenCalled(); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
| @@ -11,7 +11,8 @@ import { | |||||||
|   isCacheFeatureAvailable, |   isCacheFeatureAvailable, | ||||||
|   getVersionInputFromFile, |   getVersionInputFromFile, | ||||||
|   getVersionInputFromPlainFile, |   getVersionInputFromPlainFile, | ||||||
|   getVersionInputFromTomlFile |   getVersionInputFromTomlFile, | ||||||
|  |   getNextPageUrl | ||||||
| } from '../src/utils'; | } from '../src/utils'; | ||||||
|  |  | ||||||
| jest.mock('@actions/cache'); | jest.mock('@actions/cache'); | ||||||
| @@ -136,3 +137,25 @@ describe('Version from file test', () => { | |||||||
|     } |     } | ||||||
|   ); |   ); | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | describe('getNextPageUrl', () => { | ||||||
|  |   it('GitHub API pagination next page is parsed correctly', () => { | ||||||
|  |     function generateResponse(link: string) { | ||||||
|  |       return { | ||||||
|  |         statusCode: 200, | ||||||
|  |         result: null, | ||||||
|  |         headers: { | ||||||
|  |           link: link | ||||||
|  |         } | ||||||
|  |       }; | ||||||
|  |     } | ||||||
|  |     const page1Links = | ||||||
|  |       '<https://api.github.com/repositories/129883600/releases?page=2>; rel="next", <https://api.github.com/repositories/129883600/releases?page=3>; rel="last"'; | ||||||
|  |     expect(getNextPageUrl(generateResponse(page1Links))).toStrictEqual( | ||||||
|  |       'https://api.github.com/repositories/129883600/releases?page=2' | ||||||
|  |     ); | ||||||
|  |     const page2Links = | ||||||
|  |       '<https://api.github.com/repositories/129883600/releases?page=1>; rel="prev", <https://api.github.com/repositories/129883600/releases?page=1>; rel="first"'; | ||||||
|  |     expect(getNextPageUrl(generateResponse(page2Links))).toBeNull(); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
|   | |||||||
							
								
								
									
										107
									
								
								dist/cache-save/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										107
									
								
								dist/cache-save/index.js
									
									
									
									
										vendored
									
									
								
							| @@ -3300,8 +3300,11 @@ var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || | |||||||
| // Max safe segment length for coercion.
 | // Max safe segment length for coercion.
 | ||||||
| var MAX_SAFE_COMPONENT_LENGTH = 16 | var MAX_SAFE_COMPONENT_LENGTH = 16 | ||||||
| 
 | 
 | ||||||
|  | var MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6 | ||||||
|  | 
 | ||||||
| // The actual regexps go on exports.re
 | // The actual regexps go on exports.re
 | ||||||
| var re = exports.re = [] | var re = exports.re = [] | ||||||
|  | var safeRe = exports.safeRe = [] | ||||||
| var src = exports.src = [] | var src = exports.src = [] | ||||||
| var t = exports.tokens = {} | var t = exports.tokens = {} | ||||||
| var R = 0 | var R = 0 | ||||||
| @@ -3310,6 +3313,31 @@ function tok (n) { | |||||||
|   t[n] = R++ |   t[n] = R++ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | var LETTERDASHNUMBER = '[a-zA-Z0-9-]' | ||||||
|  | 
 | ||||||
|  | // Replace some greedy regex tokens to prevent regex dos issues. These regex are
 | ||||||
|  | // used internally via the safeRe object since all inputs in this library get
 | ||||||
|  | // normalized first to trim and collapse all extra whitespace. The original
 | ||||||
|  | // regexes are exported for userland consumption and lower level usage. A
 | ||||||
|  | // future breaking change could export the safer regex only with a note that
 | ||||||
|  | // all input should have extra whitespace removed.
 | ||||||
|  | var safeRegexReplacements = [ | ||||||
|  |   ['\\s', 1], | ||||||
|  |   ['\\d', MAX_LENGTH], | ||||||
|  |   [LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH], | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | function makeSafeRe (value) { | ||||||
|  |   for (var i = 0; i < safeRegexReplacements.length; i++) { | ||||||
|  |     var token = safeRegexReplacements[i][0] | ||||||
|  |     var max = safeRegexReplacements[i][1] | ||||||
|  |     value = value | ||||||
|  |       .split(token + '*').join(token + '{0,' + max + '}') | ||||||
|  |       .split(token + '+').join(token + '{1,' + max + '}') | ||||||
|  |   } | ||||||
|  |   return value | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // The following Regular Expressions can be used for tokenizing,
 | // The following Regular Expressions can be used for tokenizing,
 | ||||||
| // validating, and parsing SemVer version strings.
 | // validating, and parsing SemVer version strings.
 | ||||||
| 
 | 
 | ||||||
| @@ -3319,14 +3347,14 @@ function tok (n) { | |||||||
| tok('NUMERICIDENTIFIER') | tok('NUMERICIDENTIFIER') | ||||||
| src[t.NUMERICIDENTIFIER] = '0|[1-9]\\d*' | src[t.NUMERICIDENTIFIER] = '0|[1-9]\\d*' | ||||||
| tok('NUMERICIDENTIFIERLOOSE') | tok('NUMERICIDENTIFIERLOOSE') | ||||||
| src[t.NUMERICIDENTIFIERLOOSE] = '[0-9]+' | src[t.NUMERICIDENTIFIERLOOSE] = '\\d+' | ||||||
| 
 | 
 | ||||||
| // ## Non-numeric Identifier
 | // ## Non-numeric Identifier
 | ||||||
| // Zero or more digits, followed by a letter or hyphen, and then zero or
 | // Zero or more digits, followed by a letter or hyphen, and then zero or
 | ||||||
| // more letters, digits, or hyphens.
 | // more letters, digits, or hyphens.
 | ||||||
| 
 | 
 | ||||||
| tok('NONNUMERICIDENTIFIER') | tok('NONNUMERICIDENTIFIER') | ||||||
| src[t.NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*' | src[t.NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-]' + LETTERDASHNUMBER + '*' | ||||||
| 
 | 
 | ||||||
| // ## Main Version
 | // ## Main Version
 | ||||||
| // Three dot-separated numeric identifiers.
 | // Three dot-separated numeric identifiers.
 | ||||||
| @@ -3368,7 +3396,7 @@ src[t.PRERELEASELOOSE] = '(?:-?(' + src[t.PRERELEASEIDENTIFIERLOOSE] + | |||||||
| // Any combination of digits, letters, or hyphens.
 | // Any combination of digits, letters, or hyphens.
 | ||||||
| 
 | 
 | ||||||
| tok('BUILDIDENTIFIER') | tok('BUILDIDENTIFIER') | ||||||
| src[t.BUILDIDENTIFIER] = '[0-9A-Za-z-]+' | src[t.BUILDIDENTIFIER] = LETTERDASHNUMBER + '+' | ||||||
| 
 | 
 | ||||||
| // ## Build Metadata
 | // ## Build Metadata
 | ||||||
| // Plus sign, followed by one or more period-separated build metadata
 | // Plus sign, followed by one or more period-separated build metadata
 | ||||||
| @@ -3448,6 +3476,7 @@ src[t.COERCE] = '(^|[^\\d])' + | |||||||
|               '(?:$|[^\\d])' |               '(?:$|[^\\d])' | ||||||
| tok('COERCERTL') | tok('COERCERTL') | ||||||
| re[t.COERCERTL] = new RegExp(src[t.COERCE], 'g') | re[t.COERCERTL] = new RegExp(src[t.COERCE], 'g') | ||||||
|  | safeRe[t.COERCERTL] = new RegExp(makeSafeRe(src[t.COERCE]), 'g') | ||||||
| 
 | 
 | ||||||
| // Tilde ranges.
 | // Tilde ranges.
 | ||||||
| // Meaning is "reasonably at or greater than"
 | // Meaning is "reasonably at or greater than"
 | ||||||
| @@ -3457,6 +3486,7 @@ src[t.LONETILDE] = '(?:~>?)' | |||||||
| tok('TILDETRIM') | tok('TILDETRIM') | ||||||
| src[t.TILDETRIM] = '(\\s*)' + src[t.LONETILDE] + '\\s+' | src[t.TILDETRIM] = '(\\s*)' + src[t.LONETILDE] + '\\s+' | ||||||
| re[t.TILDETRIM] = new RegExp(src[t.TILDETRIM], 'g') | re[t.TILDETRIM] = new RegExp(src[t.TILDETRIM], 'g') | ||||||
|  | safeRe[t.TILDETRIM] = new RegExp(makeSafeRe(src[t.TILDETRIM]), 'g') | ||||||
| var tildeTrimReplace = '$1~' | var tildeTrimReplace = '$1~' | ||||||
| 
 | 
 | ||||||
| tok('TILDE') | tok('TILDE') | ||||||
| @@ -3472,6 +3502,7 @@ src[t.LONECARET] = '(?:\\^)' | |||||||
| tok('CARETTRIM') | tok('CARETTRIM') | ||||||
| src[t.CARETTRIM] = '(\\s*)' + src[t.LONECARET] + '\\s+' | src[t.CARETTRIM] = '(\\s*)' + src[t.LONECARET] + '\\s+' | ||||||
| re[t.CARETTRIM] = new RegExp(src[t.CARETTRIM], 'g') | re[t.CARETTRIM] = new RegExp(src[t.CARETTRIM], 'g') | ||||||
|  | safeRe[t.CARETTRIM] = new RegExp(makeSafeRe(src[t.CARETTRIM]), 'g') | ||||||
| var caretTrimReplace = '$1^' | var caretTrimReplace = '$1^' | ||||||
| 
 | 
 | ||||||
| tok('CARET') | tok('CARET') | ||||||
| @@ -3493,6 +3524,7 @@ src[t.COMPARATORTRIM] = '(\\s*)' + src[t.GTLT] + | |||||||
| 
 | 
 | ||||||
| // this one has to use the /g flag
 | // this one has to use the /g flag
 | ||||||
| re[t.COMPARATORTRIM] = new RegExp(src[t.COMPARATORTRIM], 'g') | re[t.COMPARATORTRIM] = new RegExp(src[t.COMPARATORTRIM], 'g') | ||||||
|  | safeRe[t.COMPARATORTRIM] = new RegExp(makeSafeRe(src[t.COMPARATORTRIM]), 'g') | ||||||
| var comparatorTrimReplace = '$1$2$3' | var comparatorTrimReplace = '$1$2$3' | ||||||
| 
 | 
 | ||||||
| // Something like `1.2.3 - 1.2.4`
 | // Something like `1.2.3 - 1.2.4`
 | ||||||
| @@ -3521,6 +3553,14 @@ for (var i = 0; i < R; i++) { | |||||||
|   debug(i, src[i]) |   debug(i, src[i]) | ||||||
|   if (!re[i]) { |   if (!re[i]) { | ||||||
|     re[i] = new RegExp(src[i]) |     re[i] = new RegExp(src[i]) | ||||||
|  | 
 | ||||||
|  |     // Replace all greedy whitespace to prevent regex dos issues. These regex are
 | ||||||
|  |     // used internally via the safeRe object since all inputs in this library get
 | ||||||
|  |     // normalized first to trim and collapse all extra whitespace. The original
 | ||||||
|  |     // regexes are exported for userland consumption and lower level usage. A
 | ||||||
|  |     // future breaking change could export the safer regex only with a note that
 | ||||||
|  |     // all input should have extra whitespace removed.
 | ||||||
|  |     safeRe[i] = new RegExp(makeSafeRe(src[i])) | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -3545,7 +3585,7 @@ function parse (version, options) { | |||||||
|     return null |     return null | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   var r = options.loose ? re[t.LOOSE] : re[t.FULL] |   var r = options.loose ? safeRe[t.LOOSE] : safeRe[t.FULL] | ||||||
|   if (!r.test(version)) { |   if (!r.test(version)) { | ||||||
|     return null |     return null | ||||||
|   } |   } | ||||||
| @@ -3600,7 +3640,7 @@ function SemVer (version, options) { | |||||||
|   this.options = options |   this.options = options | ||||||
|   this.loose = !!options.loose |   this.loose = !!options.loose | ||||||
| 
 | 
 | ||||||
|   var m = version.trim().match(options.loose ? re[t.LOOSE] : re[t.FULL]) |   var m = version.trim().match(options.loose ? safeRe[t.LOOSE] : safeRe[t.FULL]) | ||||||
| 
 | 
 | ||||||
|   if (!m) { |   if (!m) { | ||||||
|     throw new TypeError('Invalid Version: ' + version) |     throw new TypeError('Invalid Version: ' + version) | ||||||
| @@ -4045,6 +4085,7 @@ function Comparator (comp, options) { | |||||||
|     return new Comparator(comp, options) |     return new Comparator(comp, options) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   comp = comp.trim().split(/\s+/).join(' ') | ||||||
|   debug('comparator', comp, options) |   debug('comparator', comp, options) | ||||||
|   this.options = options |   this.options = options | ||||||
|   this.loose = !!options.loose |   this.loose = !!options.loose | ||||||
| @@ -4061,7 +4102,7 @@ function Comparator (comp, options) { | |||||||
| 
 | 
 | ||||||
| var ANY = {} | var ANY = {} | ||||||
| Comparator.prototype.parse = function (comp) { | Comparator.prototype.parse = function (comp) { | ||||||
|   var r = this.options.loose ? re[t.COMPARATORLOOSE] : re[t.COMPARATOR] |   var r = this.options.loose ? safeRe[t.COMPARATORLOOSE] : safeRe[t.COMPARATOR] | ||||||
|   var m = comp.match(r) |   var m = comp.match(r) | ||||||
| 
 | 
 | ||||||
|   if (!m) { |   if (!m) { | ||||||
| @@ -4185,9 +4226,16 @@ function Range (range, options) { | |||||||
|   this.loose = !!options.loose |   this.loose = !!options.loose | ||||||
|   this.includePrerelease = !!options.includePrerelease |   this.includePrerelease = !!options.includePrerelease | ||||||
| 
 | 
 | ||||||
|   // First, split based on boolean or ||
 |   // First reduce all whitespace as much as possible so we do not have to rely
 | ||||||
|  |   // on potentially slow regexes like \s*. This is then stored and used for
 | ||||||
|  |   // future error messages as well.
 | ||||||
|   this.raw = range |   this.raw = range | ||||||
|   this.set = range.split(/\s*\|\|\s*/).map(function (range) { |     .trim() | ||||||
|  |     .split(/\s+/) | ||||||
|  |     .join(' ') | ||||||
|  | 
 | ||||||
|  |   // First, split based on boolean or ||
 | ||||||
|  |   this.set = this.raw.split('||').map(function (range) { | ||||||
|     return this.parseRange(range.trim()) |     return this.parseRange(range.trim()) | ||||||
|   }, this).filter(function (c) { |   }, this).filter(function (c) { | ||||||
|     // throw out any that are not relevant for whatever reason
 |     // throw out any that are not relevant for whatever reason
 | ||||||
| @@ -4195,7 +4243,7 @@ function Range (range, options) { | |||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   if (!this.set.length) { |   if (!this.set.length) { | ||||||
|     throw new TypeError('Invalid SemVer Range: ' + range) |     throw new TypeError('Invalid SemVer Range: ' + this.raw) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   this.format() |   this.format() | ||||||
| @@ -4214,20 +4262,19 @@ Range.prototype.toString = function () { | |||||||
| 
 | 
 | ||||||
| Range.prototype.parseRange = function (range) { | Range.prototype.parseRange = function (range) { | ||||||
|   var loose = this.options.loose |   var loose = this.options.loose | ||||||
|   range = range.trim() |  | ||||||
|   // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`
 |   // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`
 | ||||||
|   var hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE] |   var hr = loose ? safeRe[t.HYPHENRANGELOOSE] : safeRe[t.HYPHENRANGE] | ||||||
|   range = range.replace(hr, hyphenReplace) |   range = range.replace(hr, hyphenReplace) | ||||||
|   debug('hyphen replace', range) |   debug('hyphen replace', range) | ||||||
|   // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
 |   // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
 | ||||||
|   range = range.replace(re[t.COMPARATORTRIM], comparatorTrimReplace) |   range = range.replace(safeRe[t.COMPARATORTRIM], comparatorTrimReplace) | ||||||
|   debug('comparator trim', range, re[t.COMPARATORTRIM]) |   debug('comparator trim', range, safeRe[t.COMPARATORTRIM]) | ||||||
| 
 | 
 | ||||||
|   // `~ 1.2.3` => `~1.2.3`
 |   // `~ 1.2.3` => `~1.2.3`
 | ||||||
|   range = range.replace(re[t.TILDETRIM], tildeTrimReplace) |   range = range.replace(safeRe[t.TILDETRIM], tildeTrimReplace) | ||||||
| 
 | 
 | ||||||
|   // `^ 1.2.3` => `^1.2.3`
 |   // `^ 1.2.3` => `^1.2.3`
 | ||||||
|   range = range.replace(re[t.CARETTRIM], caretTrimReplace) |   range = range.replace(safeRe[t.CARETTRIM], caretTrimReplace) | ||||||
| 
 | 
 | ||||||
|   // normalize spaces
 |   // normalize spaces
 | ||||||
|   range = range.split(/\s+/).join(' ') |   range = range.split(/\s+/).join(' ') | ||||||
| @@ -4235,7 +4282,7 @@ Range.prototype.parseRange = function (range) { | |||||||
|   // At this point, the range is completely trimmed and
 |   // At this point, the range is completely trimmed and
 | ||||||
|   // ready to be split into comparators.
 |   // ready to be split into comparators.
 | ||||||
| 
 | 
 | ||||||
|   var compRe = loose ? re[t.COMPARATORLOOSE] : re[t.COMPARATOR] |   var compRe = loose ? safeRe[t.COMPARATORLOOSE] : safeRe[t.COMPARATOR] | ||||||
|   var set = range.split(' ').map(function (comp) { |   var set = range.split(' ').map(function (comp) { | ||||||
|     return parseComparator(comp, this.options) |     return parseComparator(comp, this.options) | ||||||
|   }, this).join(' ').split(/\s+/) |   }, this).join(' ').split(/\s+/) | ||||||
| @@ -4335,7 +4382,7 @@ function replaceTildes (comp, options) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function replaceTilde (comp, options) { | function replaceTilde (comp, options) { | ||||||
|   var r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE] |   var r = options.loose ? safeRe[t.TILDELOOSE] : safeRe[t.TILDE] | ||||||
|   return comp.replace(r, function (_, M, m, p, pr) { |   return comp.replace(r, function (_, M, m, p, pr) { | ||||||
|     debug('tilde', comp, _, M, m, p, pr) |     debug('tilde', comp, _, M, m, p, pr) | ||||||
|     var ret |     var ret | ||||||
| @@ -4376,7 +4423,7 @@ function replaceCarets (comp, options) { | |||||||
| 
 | 
 | ||||||
| function replaceCaret (comp, options) { | function replaceCaret (comp, options) { | ||||||
|   debug('caret', comp, options) |   debug('caret', comp, options) | ||||||
|   var r = options.loose ? re[t.CARETLOOSE] : re[t.CARET] |   var r = options.loose ? safeRe[t.CARETLOOSE] : safeRe[t.CARET] | ||||||
|   return comp.replace(r, function (_, M, m, p, pr) { |   return comp.replace(r, function (_, M, m, p, pr) { | ||||||
|     debug('caret', comp, _, M, m, p, pr) |     debug('caret', comp, _, M, m, p, pr) | ||||||
|     var ret |     var ret | ||||||
| @@ -4435,7 +4482,7 @@ function replaceXRanges (comp, options) { | |||||||
| 
 | 
 | ||||||
| function replaceXRange (comp, options) { | function replaceXRange (comp, options) { | ||||||
|   comp = comp.trim() |   comp = comp.trim() | ||||||
|   var r = options.loose ? re[t.XRANGELOOSE] : re[t.XRANGE] |   var r = options.loose ? safeRe[t.XRANGELOOSE] : safeRe[t.XRANGE] | ||||||
|   return comp.replace(r, function (ret, gtlt, M, m, p, pr) { |   return comp.replace(r, function (ret, gtlt, M, m, p, pr) { | ||||||
|     debug('xRange', comp, ret, gtlt, M, m, p, pr) |     debug('xRange', comp, ret, gtlt, M, m, p, pr) | ||||||
|     var xM = isX(M) |     var xM = isX(M) | ||||||
| @@ -4510,7 +4557,7 @@ function replaceXRange (comp, options) { | |||||||
| function replaceStars (comp, options) { | function replaceStars (comp, options) { | ||||||
|   debug('replaceStars', comp, options) |   debug('replaceStars', comp, options) | ||||||
|   // Looseness is ignored here.  star is always as loose as it gets!
 |   // Looseness is ignored here.  star is always as loose as it gets!
 | ||||||
|   return comp.trim().replace(re[t.STAR], '') |   return comp.trim().replace(safeRe[t.STAR], '') | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // This function is passed to string.replace(re[t.HYPHENRANGE])
 | // This function is passed to string.replace(re[t.HYPHENRANGE])
 | ||||||
| @@ -4836,7 +4883,7 @@ function coerce (version, options) { | |||||||
| 
 | 
 | ||||||
|   var match = null |   var match = null | ||||||
|   if (!options.rtl) { |   if (!options.rtl) { | ||||||
|     match = version.match(re[t.COERCE]) |     match = version.match(safeRe[t.COERCE]) | ||||||
|   } else { |   } else { | ||||||
|     // Find the right-most coercible string that does not share
 |     // Find the right-most coercible string that does not share
 | ||||||
|     // a terminus with a more left-ward coercible string.
 |     // a terminus with a more left-ward coercible string.
 | ||||||
| @@ -4847,17 +4894,17 @@ function coerce (version, options) { | |||||||
|     // Stop when we get a match that ends at the string end, since no
 |     // Stop when we get a match that ends at the string end, since no
 | ||||||
|     // coercible string can be more right-ward without the same terminus.
 |     // coercible string can be more right-ward without the same terminus.
 | ||||||
|     var next |     var next | ||||||
|     while ((next = re[t.COERCERTL].exec(version)) && |     while ((next = safeRe[t.COERCERTL].exec(version)) && | ||||||
|       (!match || match.index + match[0].length !== version.length) |       (!match || match.index + match[0].length !== version.length) | ||||||
|     ) { |     ) { | ||||||
|       if (!match || |       if (!match || | ||||||
|           next.index + next[0].length !== match.index + match[0].length) { |           next.index + next[0].length !== match.index + match[0].length) { | ||||||
|         match = next |         match = next | ||||||
|       } |       } | ||||||
|       re[t.COERCERTL].lastIndex = next.index + next[1].length + next[2].length |       safeRe[t.COERCERTL].lastIndex = next.index + next[1].length + next[2].length | ||||||
|     } |     } | ||||||
|     // leave it in a clean state
 |     // leave it in a clean state
 | ||||||
|     re[t.COERCERTL].lastIndex = -1 |     safeRe[t.COERCERTL].lastIndex = -1 | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   if (match === null) { |   if (match === null) { | ||||||
| @@ -59042,7 +59089,11 @@ module.exports = v4; | |||||||
| 
 | 
 | ||||||
| var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||||||
|     if (k2 === undefined) k2 = k; |     if (k2 === undefined) k2 = k; | ||||||
|     Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); |     var desc = Object.getOwnPropertyDescriptor(m, k); | ||||||
|  |     if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||||||
|  |       desc = { enumerable: true, get: function() { return m[k]; } }; | ||||||
|  |     } | ||||||
|  |     Object.defineProperty(o, k2, desc); | ||||||
| }) : (function(o, m, k, k2) { | }) : (function(o, m, k, k2) { | ||||||
|     if (k2 === undefined) k2 = k; |     if (k2 === undefined) k2 = k; | ||||||
|     o[k2] = m[k]; |     o[k2] = m[k]; | ||||||
| @@ -59151,7 +59202,11 @@ exports.CACHE_DEPENDENCY_BACKUP_PATH = '**/pyproject.toml'; | |||||||
| 
 | 
 | ||||||
| var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||||||
|     if (k2 === undefined) k2 = k; |     if (k2 === undefined) k2 = k; | ||||||
|     Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); |     var desc = Object.getOwnPropertyDescriptor(m, k); | ||||||
|  |     if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||||||
|  |       desc = { enumerable: true, get: function() { return m[k]; } }; | ||||||
|  |     } | ||||||
|  |     Object.defineProperty(o, k2, desc); | ||||||
| }) : (function(o, m, k, k2) { | }) : (function(o, m, k, k2) { | ||||||
|     if (k2 === undefined) k2 = k; |     if (k2 === undefined) k2 = k; | ||||||
|     o[k2] = m[k]; |     o[k2] = m[k]; | ||||||
|   | |||||||
							
								
								
									
										736
									
								
								dist/setup/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										736
									
								
								dist/setup/index.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -30,7 +30,7 @@ If there is a specific version of Python that you need and you don't want to wor | |||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
| steps: | steps: | ||||||
| - uses: actions/checkout@v3 | - uses: actions/checkout@v4 | ||||||
| - uses: actions/setup-python@v4 | - uses: actions/setup-python@v4 | ||||||
|   with: |   with: | ||||||
|     python-version: '3.7.5'  |     python-version: '3.7.5'  | ||||||
| @@ -44,7 +44,7 @@ You can specify **only a major and minor version** if you are okay with the most | |||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
| steps: | steps: | ||||||
| - uses: actions/checkout@v3 | - uses: actions/checkout@v4 | ||||||
| - uses: actions/setup-python@v4 | - uses: actions/setup-python@v4 | ||||||
|   with: |   with: | ||||||
|     python-version: '3.7'  |     python-version: '3.7'  | ||||||
| @@ -58,7 +58,7 @@ You can specify the version with **prerelease tag** to download and set up an ac | |||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
| steps: | steps: | ||||||
| - uses: actions/checkout@v3 | - uses: actions/checkout@v4 | ||||||
| - uses: actions/setup-python@v4 | - uses: actions/setup-python@v4 | ||||||
|   with: |   with: | ||||||
|     python-version: '3.12.0-alpha.1' |     python-version: '3.12.0-alpha.1' | ||||||
| @@ -69,7 +69,7 @@ It's also possible to use **x.y-dev syntax** to download and set up the latest p | |||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
| steps: | steps: | ||||||
| - uses: actions/checkout@v3 | - uses: actions/checkout@v4 | ||||||
| - uses: actions/setup-python@v4 | - uses: actions/setup-python@v4 | ||||||
|   with: |   with: | ||||||
|     python-version: '3.12-dev' |     python-version: '3.12-dev' | ||||||
| @@ -82,7 +82,7 @@ You can also use several types of ranges that are specified in [semver](https:// | |||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
| steps: | steps: | ||||||
| - uses: actions/checkout@v3 | - uses: actions/checkout@v4 | ||||||
| - uses: actions/setup-python@v4 | - uses: actions/setup-python@v4 | ||||||
|   with: |   with: | ||||||
|     python-version: '>=3.9 <3.10' |     python-version: '>=3.9 <3.10' | ||||||
| @@ -93,7 +93,7 @@ steps: | |||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
| steps: | steps: | ||||||
| - uses: actions/checkout@v3 | - uses: actions/checkout@v4 | ||||||
| - uses: actions/setup-python@v4 | - uses: actions/setup-python@v4 | ||||||
|   with: |   with: | ||||||
|     python-version: '3.12.0-alpha - 3.12.0' |     python-version: '3.12.0-alpha - 3.12.0' | ||||||
| @@ -104,7 +104,7 @@ steps: | |||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
| steps: | steps: | ||||||
| - uses: actions/checkout@v3 | - uses: actions/checkout@v4 | ||||||
| - uses: actions/setup-python@v4 | - uses: actions/setup-python@v4 | ||||||
|   with: |   with: | ||||||
|     python-version: '3.x' |     python-version: '3.x' | ||||||
| @@ -117,7 +117,7 @@ The version of PyPy should be specified in the format `pypy<python_version>[-v<p | |||||||
| The `-v<pypy_version>` parameter is optional and can be skipped. The latest PyPy version will be used in this case. | The `-v<pypy_version>` parameter is optional and can be skipped. The latest PyPy version will be used in this case. | ||||||
|  |  | ||||||
| ``` | ``` | ||||||
| pypy3.8 or pypy-3.8 # the latest available version of PyPy that supports Python 3.8 | pypy3.9 or pypy-3.9 # the latest available version of PyPy that supports Python 3.9 | ||||||
| pypy2.7 or pypy-2.7 # the latest available version of PyPy that supports Python 2.7 | pypy2.7 or pypy-2.7 # the latest available version of PyPy that supports Python 2.7 | ||||||
| pypy3.7-v7.3.3 or pypy-3.7-v7.3.3 # Python 3.7 and PyPy 7.3.3 | pypy3.7-v7.3.3 or pypy-3.7-v7.3.3 # Python 3.7 and PyPy 7.3.3 | ||||||
| pypy3.7-v7.x or pypy-3.7-v7.x # Python 3.7 and the latest available PyPy 7.x | pypy3.7-v7.x or pypy-3.7-v7.x # Python 3.7 and the latest available PyPy 7.x | ||||||
| @@ -137,7 +137,7 @@ jobs: | |||||||
|         - 'pypy3.7' # the latest available version of PyPy that supports Python 3.7 |         - 'pypy3.7' # the latest available version of PyPy that supports Python 3.7 | ||||||
|         - 'pypy3.7-v7.3.3' # Python 3.7 and PyPy 7.3.3 |         - 'pypy3.7-v7.3.3' # Python 3.7 and PyPy 7.3.3 | ||||||
|     steps: |     steps: | ||||||
|     - uses: actions/checkout@v3 |     - uses: actions/checkout@v4 | ||||||
|     - uses: actions/setup-python@v4 |     - uses: actions/setup-python@v4 | ||||||
|       with: |       with: | ||||||
|         python-version: ${{ matrix.python-version }} |         python-version: ${{ matrix.python-version }} | ||||||
| @@ -155,7 +155,7 @@ jobs: | |||||||
|   build: |   build: | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
|     steps: |     steps: | ||||||
|     - uses: actions/checkout@v3 |     - uses: actions/checkout@v4 | ||||||
|     - uses: actions/setup-python@v4 |     - uses: actions/setup-python@v4 | ||||||
|       with: |       with: | ||||||
|         python-version: | |         python-version: | | ||||||
| @@ -172,7 +172,7 @@ jobs: | |||||||
|   build: |   build: | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
|     steps: |     steps: | ||||||
|     - uses: actions/checkout@v3 |     - uses: actions/checkout@v4 | ||||||
|     - uses: actions/setup-python@v4 |     - uses: actions/setup-python@v4 | ||||||
|       with: |       with: | ||||||
|         python-version: | |         python-version: | | ||||||
| @@ -189,7 +189,7 @@ jobs: | |||||||
|   build: |   build: | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
|     steps: |     steps: | ||||||
|     - uses: actions/checkout@v3 |     - uses: actions/checkout@v4 | ||||||
|     - uses: actions/setup-python@v4 |     - uses: actions/setup-python@v4 | ||||||
|       with: |       with: | ||||||
|         python-version: | |         python-version: | | ||||||
| @@ -211,10 +211,10 @@ jobs: | |||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
|     strategy: |     strategy: | ||||||
|       matrix: |       matrix: | ||||||
|         python-version: [ '2.x', '3.x', 'pypy2.7', 'pypy3.7', 'pypy3.8' ] |         python-version: [ '2.x', '3.x', 'pypy2.7', 'pypy3.8', 'pypy3.9' ] | ||||||
|     name: Python ${{ matrix.python-version }} sample |     name: Python ${{ matrix.python-version }} sample | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v3 |       - uses: actions/checkout@v4 | ||||||
|       - name: Set up Python |       - name: Set up Python | ||||||
|         uses: actions/setup-python@v4 |         uses: actions/setup-python@v4 | ||||||
|         with: |         with: | ||||||
| @@ -232,14 +232,14 @@ jobs: | |||||||
|     strategy: |     strategy: | ||||||
|       matrix: |       matrix: | ||||||
|         os: [ubuntu-latest, macos-latest, windows-latest] |         os: [ubuntu-latest, macos-latest, windows-latest] | ||||||
|         python-version: ['2.7', '3.7', '3.8', '3.9', '3.10', 'pypy2.7', 'pypy3.8'] |         python-version: ['2.7', '3.7', '3.8', '3.9', '3.10', 'pypy2.7', 'pypy3.9'] | ||||||
|         exclude: |         exclude: | ||||||
|           - os: macos-latest |           - os: macos-latest | ||||||
|             python-version: '3.8' |             python-version: '3.8' | ||||||
|           - os: windows-latest |           - os: windows-latest | ||||||
|             python-version: '3.6' |             python-version: '3.6' | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v3 |       - uses: actions/checkout@v4 | ||||||
|       - name: Set up Python |       - name: Set up Python | ||||||
|         uses: actions/setup-python@v4 |         uses: actions/setup-python@v4 | ||||||
|         with: |         with: | ||||||
| @@ -256,7 +256,7 @@ jobs: | |||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
| steps: | steps: | ||||||
| - uses: actions/checkout@v3 | - uses: actions/checkout@v4 | ||||||
| - uses: actions/setup-python@v4 | - uses: actions/setup-python@v4 | ||||||
|   with: |   with: | ||||||
|     python-version-file: '.python-version' # Read python version from a file .python-version |     python-version-file: '.python-version' # Read python version from a file .python-version | ||||||
| @@ -265,7 +265,7 @@ steps: | |||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
| steps: | steps: | ||||||
| - uses: actions/checkout@v3 | - uses: actions/checkout@v4 | ||||||
| - uses: actions/setup-python@v4 | - uses: actions/setup-python@v4 | ||||||
|   with: |   with: | ||||||
|     python-version-file: 'pyproject.toml' # Read python version from a file pyproject.toml |     python-version-file: 'pyproject.toml' # Read python version from a file pyproject.toml | ||||||
| @@ -280,7 +280,7 @@ If `check-latest` is set to `true`, the action first checks if the cached versio | |||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
| steps: | steps: | ||||||
|   - uses: actions/checkout@v3 |   - uses: actions/checkout@v4 | ||||||
|   - uses: actions/setup-python@v4 |   - uses: actions/setup-python@v4 | ||||||
|     with: |     with: | ||||||
|       python-version: '3.7' |       python-version: '3.7' | ||||||
| @@ -295,7 +295,7 @@ steps: | |||||||
| **Caching pipenv dependencies:** | **Caching pipenv dependencies:** | ||||||
| ```yaml | ```yaml | ||||||
| steps: | steps: | ||||||
| - uses: actions/checkout@v3 | - uses: actions/checkout@v4 | ||||||
| - uses: actions/setup-python@v4 | - uses: actions/setup-python@v4 | ||||||
|   with: |   with: | ||||||
|     python-version: '3.9' |     python-version: '3.9' | ||||||
| @@ -308,7 +308,7 @@ steps: | |||||||
| **Caching poetry dependencies:** | **Caching poetry dependencies:** | ||||||
| ```yaml | ```yaml | ||||||
| steps: | steps: | ||||||
| - uses: actions/checkout@v3 | - uses: actions/checkout@v4 | ||||||
| - name: Install poetry | - name: Install poetry | ||||||
|   run: pipx install poetry |   run: pipx install poetry | ||||||
| - uses: actions/setup-python@v4 | - uses: actions/setup-python@v4 | ||||||
| @@ -322,7 +322,7 @@ steps: | |||||||
| **Using a list of file paths to cache dependencies** | **Using a list of file paths to cache dependencies** | ||||||
| ```yaml | ```yaml | ||||||
| steps: | steps: | ||||||
| - uses: actions/checkout@v3 | - uses: actions/checkout@v4 | ||||||
| - uses: actions/setup-python@v4 | - uses: actions/setup-python@v4 | ||||||
|   with: |   with: | ||||||
|     python-version: '3.9' |     python-version: '3.9' | ||||||
| @@ -337,7 +337,7 @@ steps: | |||||||
| **Using wildcard patterns to cache dependencies** | **Using wildcard patterns to cache dependencies** | ||||||
| ```yaml | ```yaml | ||||||
| steps: | steps: | ||||||
| - uses: actions/checkout@v3 | - uses: actions/checkout@v4 | ||||||
| - uses: actions/setup-python@v4 | - uses: actions/setup-python@v4 | ||||||
|   with: |   with: | ||||||
|     python-version: '3.9' |     python-version: '3.9' | ||||||
| @@ -349,7 +349,7 @@ steps: | |||||||
| **Using a list of wildcard patterns to cache dependencies** | **Using a list of wildcard patterns to cache dependencies** | ||||||
| ```yaml | ```yaml | ||||||
| steps: | steps: | ||||||
| - uses: actions/checkout@v3 | - uses: actions/checkout@v4 | ||||||
| - uses: actions/setup-python@v4 | - uses: actions/setup-python@v4 | ||||||
|   with: |   with: | ||||||
|     python-version: '3.10' |     python-version: '3.10' | ||||||
| @@ -364,7 +364,7 @@ steps: | |||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
| steps: | steps: | ||||||
| - uses: actions/checkout@v3 | - uses: actions/checkout@v4 | ||||||
| - uses: actions/setup-python@v4 | - uses: actions/setup-python@v4 | ||||||
|   with: |   with: | ||||||
|     python-version: '3.11' |     python-version: '3.11' | ||||||
| @@ -387,7 +387,7 @@ jobs: | |||||||
|   build: |   build: | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
|     steps: |     steps: | ||||||
|     - uses: actions/checkout@v3 |     - uses: actions/checkout@v4 | ||||||
|     - uses: actions/setup-python@v4 |     - uses: actions/setup-python@v4 | ||||||
|       id: cp310 |       id: cp310 | ||||||
|       with: |       with: | ||||||
| @@ -404,7 +404,7 @@ jobs: | |||||||
|   build: |   build: | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
|     steps: |     steps: | ||||||
|     - uses: actions/checkout@v3 |     - uses: actions/checkout@v4 | ||||||
|     - uses: actions/setup-python@v4 |     - uses: actions/setup-python@v4 | ||||||
|       id: cp310 |       id: cp310 | ||||||
|       with: |       with: | ||||||
| @@ -420,7 +420,7 @@ jobs: | |||||||
|   build: |   build: | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
|     steps: |     steps: | ||||||
|     - uses: actions/checkout@v3 |     - uses: actions/checkout@v4 | ||||||
|     - uses: actions/setup-python@v4 |     - uses: actions/setup-python@v4 | ||||||
|       id: cp310 |       id: cp310 | ||||||
|       with: |       with: | ||||||
| @@ -451,7 +451,7 @@ Such a requirement on side-effect could be because you don't want your composite | |||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
|  steps: |  steps: | ||||||
|    - uses: actions/checkout@v3 |    - uses: actions/checkout@v4 | ||||||
|    - uses: actions/setup-python@v4 |    - uses: actions/setup-python@v4 | ||||||
|      id: cp310 |      id: cp310 | ||||||
|      with: |      with: | ||||||
| @@ -611,7 +611,7 @@ jobs: | |||||||
|         python_version: ["3.11", "3.12"] |         python_version: ["3.11", "3.12"] | ||||||
|  |  | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v3 |       - uses: actions/checkout@v4 | ||||||
|       - uses: actions/setup-python@v4 |       - uses: actions/setup-python@v4 | ||||||
|         with: |         with: | ||||||
|           python-version: "${{ matrix.python_version }}" |           python-version: "${{ matrix.python_version }}" | ||||||
|   | |||||||
							
								
								
									
										7122
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										7122
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										10
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								package.json
									
									
									
									
									
								
							| @@ -36,21 +36,21 @@ | |||||||
|     "semver": "^7.5.2" |     "semver": "^7.5.2" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@types/jest": "^27.0.2", |     "@types/jest": "^29.5.6", | ||||||
|     "@types/node": "^16.11.25", |     "@types/node": "^16.11.25", | ||||||
|     "@types/semver": "^7.1.0", |     "@types/semver": "^7.1.0", | ||||||
|     "@typescript-eslint/eslint-plugin": "^5.54.0", |     "@typescript-eslint/eslint-plugin": "^5.54.0", | ||||||
|     "@typescript-eslint/parser": "^5.54.0", |     "@typescript-eslint/parser": "^5.54.0", | ||||||
|     "@vercel/ncc": "^0.33.4", |     "@vercel/ncc": "^0.38.0", | ||||||
|     "eslint": "^8.35.0", |     "eslint": "^8.35.0", | ||||||
|     "eslint-config-prettier": "^8.6.0", |     "eslint-config-prettier": "^8.6.0", | ||||||
|     "eslint-plugin-jest": "^27.2.1", |     "eslint-plugin-jest": "^27.2.1", | ||||||
|     "eslint-plugin-node": "^11.1.0", |     "eslint-plugin-node": "^11.1.0", | ||||||
|     "husky": "^7.0.2", |     "husky": "^7.0.2", | ||||||
|     "jest": "^27.2.5", |     "jest": "^29.7.0", | ||||||
|     "jest-circus": "^27.2.5", |     "jest-circus": "^29.7.0", | ||||||
|     "prettier": "^2.8.4", |     "prettier": "^2.8.4", | ||||||
|     "ts-jest": "^27.0.5", |     "ts-jest": "^29.1.1", | ||||||
|     "typescript": "^4.2.3" |     "typescript": "^4.2.3" | ||||||
|   }, |   }, | ||||||
|   "husky": { |   "husky": { | ||||||
|   | |||||||
							
								
								
									
										146
									
								
								src/find-graalpy.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								src/find-graalpy.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,146 @@ | |||||||
|  | import * as path from 'path'; | ||||||
|  | import * as graalpyInstall from './install-graalpy'; | ||||||
|  | import { | ||||||
|  |   IS_WINDOWS, | ||||||
|  |   validateVersion, | ||||||
|  |   IGraalPyManifestRelease, | ||||||
|  |   getBinaryDirectory | ||||||
|  | } from './utils'; | ||||||
|  |  | ||||||
|  | import * as semver from 'semver'; | ||||||
|  | import * as core from '@actions/core'; | ||||||
|  | import * as tc from '@actions/tool-cache'; | ||||||
|  |  | ||||||
|  | export async function findGraalPyVersion( | ||||||
|  |   versionSpec: string, | ||||||
|  |   architecture: string, | ||||||
|  |   updateEnvironment: boolean, | ||||||
|  |   checkLatest: boolean, | ||||||
|  |   allowPreReleases: boolean | ||||||
|  | ): Promise<string> { | ||||||
|  |   let resolvedGraalPyVersion = ''; | ||||||
|  |   let installDir: string | null; | ||||||
|  |   let releases: IGraalPyManifestRelease[] | undefined; | ||||||
|  |  | ||||||
|  |   let graalpyVersionSpec = parseGraalPyVersion(versionSpec); | ||||||
|  |  | ||||||
|  |   if (checkLatest) { | ||||||
|  |     releases = await graalpyInstall.getAvailableGraalPyVersions(); | ||||||
|  |     if (releases && releases.length > 0) { | ||||||
|  |       const releaseData = graalpyInstall.findRelease( | ||||||
|  |         releases, | ||||||
|  |         graalpyVersionSpec, | ||||||
|  |         architecture, | ||||||
|  |         false | ||||||
|  |       ); | ||||||
|  |  | ||||||
|  |       if (releaseData) { | ||||||
|  |         core.info(`Resolved as GraalPy ${releaseData.resolvedGraalPyVersion}`); | ||||||
|  |         graalpyVersionSpec = releaseData.resolvedGraalPyVersion; | ||||||
|  |       } else { | ||||||
|  |         core.info( | ||||||
|  |           `Failed to resolve GraalPy ${graalpyVersionSpec} from manifest` | ||||||
|  |         ); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ({installDir, resolvedGraalPyVersion} = findGraalPyToolCache( | ||||||
|  |     graalpyVersionSpec, | ||||||
|  |     architecture | ||||||
|  |   )); | ||||||
|  |  | ||||||
|  |   if (!installDir) { | ||||||
|  |     ({installDir, resolvedGraalPyVersion} = await graalpyInstall.installGraalPy( | ||||||
|  |       graalpyVersionSpec, | ||||||
|  |       architecture, | ||||||
|  |       allowPreReleases, | ||||||
|  |       releases | ||||||
|  |     )); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   const pipDir = IS_WINDOWS ? 'Scripts' : 'bin'; | ||||||
|  |   const _binDir = path.join(installDir, pipDir); | ||||||
|  |   const binaryExtension = IS_WINDOWS ? '.exe' : ''; | ||||||
|  |   const pythonPath = path.join( | ||||||
|  |     IS_WINDOWS ? installDir : _binDir, | ||||||
|  |     `python${binaryExtension}` | ||||||
|  |   ); | ||||||
|  |   const pythonLocation = getBinaryDirectory(installDir); | ||||||
|  |   if (updateEnvironment) { | ||||||
|  |     core.exportVariable('pythonLocation', installDir); | ||||||
|  |     // https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython | ||||||
|  |     core.exportVariable('Python_ROOT_DIR', installDir); | ||||||
|  |     // https://cmake.org/cmake/help/latest/module/FindPython2.html#module:FindPython2 | ||||||
|  |     core.exportVariable('Python2_ROOT_DIR', installDir); | ||||||
|  |     // https://cmake.org/cmake/help/latest/module/FindPython3.html#module:FindPython3 | ||||||
|  |     core.exportVariable('Python3_ROOT_DIR', installDir); | ||||||
|  |     core.exportVariable('PKG_CONFIG_PATH', pythonLocation + '/lib/pkgconfig'); | ||||||
|  |     core.addPath(pythonLocation); | ||||||
|  |     core.addPath(_binDir); | ||||||
|  |   } | ||||||
|  |   core.setOutput('python-version', 'graalpy' + resolvedGraalPyVersion); | ||||||
|  |   core.setOutput('python-path', pythonPath); | ||||||
|  |  | ||||||
|  |   return resolvedGraalPyVersion; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function findGraalPyToolCache( | ||||||
|  |   graalpyVersion: string, | ||||||
|  |   architecture: string | ||||||
|  | ) { | ||||||
|  |   let resolvedGraalPyVersion = ''; | ||||||
|  |   let installDir: string | null = tc.find( | ||||||
|  |     'GraalPy', | ||||||
|  |     graalpyVersion, | ||||||
|  |     architecture | ||||||
|  |   ); | ||||||
|  |  | ||||||
|  |   if (installDir) { | ||||||
|  |     // 'tc.find' finds tool based on Python version but we also need to check | ||||||
|  |     // whether GraalPy version satisfies requested version. | ||||||
|  |     resolvedGraalPyVersion = path.basename(path.dirname(installDir)); | ||||||
|  |  | ||||||
|  |     const isGraalPyVersionSatisfies = semver.satisfies( | ||||||
|  |       resolvedGraalPyVersion, | ||||||
|  |       graalpyVersion | ||||||
|  |     ); | ||||||
|  |     if (!isGraalPyVersionSatisfies) { | ||||||
|  |       installDir = null; | ||||||
|  |       resolvedGraalPyVersion = ''; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (!installDir) { | ||||||
|  |     core.info( | ||||||
|  |       `GraalPy version ${graalpyVersion} was not found in the local cache` | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return {installDir, resolvedGraalPyVersion}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function parseGraalPyVersion(versionSpec: string): string { | ||||||
|  |   const versions = versionSpec.split('-').filter(item => !!item); | ||||||
|  |  | ||||||
|  |   if (/^(graalpy)(.+)/.test(versions[0])) { | ||||||
|  |     const version = versions[0].replace('graalpy', ''); | ||||||
|  |     versions.splice(0, 1, 'graalpy', version); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (versions.length < 2 || versions[0] != 'graalpy') { | ||||||
|  |     throw new Error( | ||||||
|  |       "Invalid 'version' property for GraalPy. GraalPy version should be specified as 'graalpy<python-version>' or 'graalpy-<python-version>'. See README for examples and documentation." | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   const pythonVersion = versions[1]; | ||||||
|  |  | ||||||
|  |   if (!validateVersion(pythonVersion)) { | ||||||
|  |     throw new Error( | ||||||
|  |       "Invalid 'version' property for GraalPy. GraalPy versions should satisfy SemVer notation. See README for examples and documentation." | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return pythonVersion; | ||||||
|  | } | ||||||
| @@ -7,7 +7,8 @@ import { | |||||||
|   getPyPyVersionFromPath, |   getPyPyVersionFromPath, | ||||||
|   readExactPyPyVersionFile, |   readExactPyPyVersionFile, | ||||||
|   validatePythonVersionFormatForPyPy, |   validatePythonVersionFormatForPyPy, | ||||||
|   IPyPyManifestRelease |   IPyPyManifestRelease, | ||||||
|  |   getBinaryDirectory | ||||||
| } from './utils'; | } from './utils'; | ||||||
|  |  | ||||||
| import * as semver from 'semver'; | import * as semver from 'semver'; | ||||||
| @@ -82,7 +83,7 @@ export async function findPyPyVersion( | |||||||
|     IS_WINDOWS ? installDir : _binDir, |     IS_WINDOWS ? installDir : _binDir, | ||||||
|     `python${binaryExtension}` |     `python${binaryExtension}` | ||||||
|   ); |   ); | ||||||
|   const pythonLocation = pypyInstall.getPyPyBinaryPath(installDir); |   const pythonLocation = getBinaryDirectory(installDir); | ||||||
|   if (updateEnvironment) { |   if (updateEnvironment) { | ||||||
|     core.exportVariable('pythonLocation', installDir); |     core.exportVariable('pythonLocation', installDir); | ||||||
|     // https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython |     // https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython | ||||||
|   | |||||||
							
								
								
									
										262
									
								
								src/install-graalpy.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										262
									
								
								src/install-graalpy.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,262 @@ | |||||||
|  | import * as os from 'os'; | ||||||
|  | import * as path from 'path'; | ||||||
|  | import * as core from '@actions/core'; | ||||||
|  | import * as tc from '@actions/tool-cache'; | ||||||
|  | import * as semver from 'semver'; | ||||||
|  | import * as httpm from '@actions/http-client'; | ||||||
|  | import * as ifm from '@actions/http-client/interfaces'; | ||||||
|  | import * as exec from '@actions/exec'; | ||||||
|  | import fs from 'fs'; | ||||||
|  |  | ||||||
|  | import { | ||||||
|  |   IS_WINDOWS, | ||||||
|  |   IGraalPyManifestRelease, | ||||||
|  |   createSymlinkInFolder, | ||||||
|  |   isNightlyKeyword, | ||||||
|  |   getBinaryDirectory, | ||||||
|  |   getNextPageUrl | ||||||
|  | } from './utils'; | ||||||
|  |  | ||||||
|  | const TOKEN = core.getInput('token'); | ||||||
|  | const AUTH = !TOKEN ? undefined : `token ${TOKEN}`; | ||||||
|  |  | ||||||
|  | export async function installGraalPy( | ||||||
|  |   graalpyVersion: string, | ||||||
|  |   architecture: string, | ||||||
|  |   allowPreReleases: boolean, | ||||||
|  |   releases: IGraalPyManifestRelease[] | undefined | ||||||
|  | ) { | ||||||
|  |   let downloadDir; | ||||||
|  |  | ||||||
|  |   releases = releases ?? (await getAvailableGraalPyVersions()); | ||||||
|  |  | ||||||
|  |   if (!releases || !releases.length) { | ||||||
|  |     throw new Error('No release was found in GraalPy version.json'); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   let releaseData = findRelease(releases, graalpyVersion, architecture, false); | ||||||
|  |  | ||||||
|  |   if (allowPreReleases && (!releaseData || !releaseData.foundAsset)) { | ||||||
|  |     // check for pre-release | ||||||
|  |     core.info( | ||||||
|  |       [ | ||||||
|  |         `Stable GraalPy version ${graalpyVersion} with arch ${architecture} not found`, | ||||||
|  |         `Trying pre-release versions` | ||||||
|  |       ].join(os.EOL) | ||||||
|  |     ); | ||||||
|  |     releaseData = findRelease(releases, graalpyVersion, architecture, true); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (!releaseData || !releaseData.foundAsset) { | ||||||
|  |     throw new Error( | ||||||
|  |       `GraalPy version ${graalpyVersion} with arch ${architecture} not found` | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   const {foundAsset, resolvedGraalPyVersion} = releaseData; | ||||||
|  |   const downloadUrl = `${foundAsset.browser_download_url}`; | ||||||
|  |  | ||||||
|  |   core.info(`Downloading GraalPy from "${downloadUrl}" ...`); | ||||||
|  |  | ||||||
|  |   try { | ||||||
|  |     const graalpyPath = await tc.downloadTool(downloadUrl, undefined, AUTH); | ||||||
|  |  | ||||||
|  |     core.info('Extracting downloaded archive...'); | ||||||
|  |     downloadDir = await tc.extractTar(graalpyPath); | ||||||
|  |  | ||||||
|  |     // root folder in archive can have unpredictable name so just take the first folder | ||||||
|  |     // downloadDir is unique folder under TEMP and can't contain any other folders | ||||||
|  |     const archiveName = fs.readdirSync(downloadDir)[0]; | ||||||
|  |  | ||||||
|  |     const toolDir = path.join(downloadDir, archiveName); | ||||||
|  |     let installDir = toolDir; | ||||||
|  |     if (!isNightlyKeyword(resolvedGraalPyVersion)) { | ||||||
|  |       installDir = await tc.cacheDir( | ||||||
|  |         toolDir, | ||||||
|  |         'GraalPy', | ||||||
|  |         resolvedGraalPyVersion, | ||||||
|  |         architecture | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const binaryPath = getBinaryDirectory(installDir); | ||||||
|  |     await createGraalPySymlink(binaryPath, resolvedGraalPyVersion); | ||||||
|  |     await installPip(binaryPath); | ||||||
|  |  | ||||||
|  |     return {installDir, resolvedGraalPyVersion}; | ||||||
|  |   } catch (err) { | ||||||
|  |     if (err instanceof Error) { | ||||||
|  |       // Rate limit? | ||||||
|  |       if ( | ||||||
|  |         err instanceof tc.HTTPError && | ||||||
|  |         (err.httpStatusCode === 403 || err.httpStatusCode === 429) | ||||||
|  |       ) { | ||||||
|  |         core.info( | ||||||
|  |           `Received HTTP status code ${err.httpStatusCode}.  This usually indicates the rate limit has been exceeded` | ||||||
|  |         ); | ||||||
|  |       } else { | ||||||
|  |         core.info(err.message); | ||||||
|  |       } | ||||||
|  |       if (err.stack !== undefined) { | ||||||
|  |         core.debug(err.stack); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     throw err; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export async function getAvailableGraalPyVersions() { | ||||||
|  |   const http: httpm.HttpClient = new httpm.HttpClient('tool-cache'); | ||||||
|  |  | ||||||
|  |   const headers: ifm.IHeaders = {}; | ||||||
|  |   if (AUTH) { | ||||||
|  |     headers.authorization = AUTH; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   let url: string | null = | ||||||
|  |     'https://api.github.com/repos/oracle/graalpython/releases'; | ||||||
|  |   const result: IGraalPyManifestRelease[] = []; | ||||||
|  |   do { | ||||||
|  |     const response: ifm.ITypedResponse<IGraalPyManifestRelease[]> = | ||||||
|  |       await http.getJson(url, headers); | ||||||
|  |     if (!response.result) { | ||||||
|  |       throw new Error( | ||||||
|  |         `Unable to retrieve the list of available GraalPy versions from '${url}'` | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |     result.push(...response.result); | ||||||
|  |     url = getNextPageUrl(response); | ||||||
|  |   } while (url); | ||||||
|  |  | ||||||
|  |   return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | async function createGraalPySymlink( | ||||||
|  |   graalpyBinaryPath: string, | ||||||
|  |   graalpyVersion: string | ||||||
|  | ) { | ||||||
|  |   const version = semver.coerce(graalpyVersion)!; | ||||||
|  |   const pythonBinaryPostfix = semver.major(version); | ||||||
|  |   const pythonMinor = semver.minor(version); | ||||||
|  |   const graalpyMajorMinorBinaryPostfix = `${pythonBinaryPostfix}.${pythonMinor}`; | ||||||
|  |   const binaryExtension = IS_WINDOWS ? '.exe' : ''; | ||||||
|  |  | ||||||
|  |   core.info('Creating symlinks...'); | ||||||
|  |   createSymlinkInFolder( | ||||||
|  |     graalpyBinaryPath, | ||||||
|  |     `graalpy${binaryExtension}`, | ||||||
|  |     `python${pythonBinaryPostfix}${binaryExtension}`, | ||||||
|  |     true | ||||||
|  |   ); | ||||||
|  |  | ||||||
|  |   createSymlinkInFolder( | ||||||
|  |     graalpyBinaryPath, | ||||||
|  |     `graalpy${binaryExtension}`, | ||||||
|  |     `python${binaryExtension}`, | ||||||
|  |     true | ||||||
|  |   ); | ||||||
|  |  | ||||||
|  |   createSymlinkInFolder( | ||||||
|  |     graalpyBinaryPath, | ||||||
|  |     `graalpy${binaryExtension}`, | ||||||
|  |     `graalpy${graalpyMajorMinorBinaryPostfix}${binaryExtension}`, | ||||||
|  |     true | ||||||
|  |   ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | async function installPip(pythonLocation: string) { | ||||||
|  |   core.info( | ||||||
|  |     "Installing pip (GraalPy doesn't update pip because it uses a patched version of pip)" | ||||||
|  |   ); | ||||||
|  |   const pythonBinary = path.join(pythonLocation, 'python'); | ||||||
|  |   await exec.exec(`${pythonBinary} -m ensurepip --default-pip`); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function graalPyTagToVersion(tag: string) { | ||||||
|  |   const versionPattern = /.*-(\d+\.\d+\.\d+(?:\.\d+)?)((?:a|b|rc))?(\d*)?/; | ||||||
|  |   const match = tag.match(versionPattern); | ||||||
|  |   if (match && match[2]) { | ||||||
|  |     return `${match[1]}-${match[2]}.${match[3]}`; | ||||||
|  |   } else if (match) { | ||||||
|  |     return match[1]; | ||||||
|  |   } else { | ||||||
|  |     return tag.replace(/.*-/, ''); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function findRelease( | ||||||
|  |   releases: IGraalPyManifestRelease[], | ||||||
|  |   graalpyVersion: string, | ||||||
|  |   architecture: string, | ||||||
|  |   includePrerelease: boolean | ||||||
|  | ) { | ||||||
|  |   const options = {includePrerelease: includePrerelease}; | ||||||
|  |   const filterReleases = releases.filter(item => { | ||||||
|  |     const isVersionSatisfied = semver.satisfies( | ||||||
|  |       graalPyTagToVersion(item.tag_name), | ||||||
|  |       graalpyVersion, | ||||||
|  |       options | ||||||
|  |     ); | ||||||
|  |     return ( | ||||||
|  |       isVersionSatisfied && !!findAsset(item, architecture, process.platform) | ||||||
|  |     ); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   if (!filterReleases.length) { | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   const sortedReleases = filterReleases.sort((previous, current) => | ||||||
|  |     semver.compare( | ||||||
|  |       semver.coerce(graalPyTagToVersion(current.tag_name))!, | ||||||
|  |       semver.coerce(graalPyTagToVersion(previous.tag_name))! | ||||||
|  |     ) | ||||||
|  |   ); | ||||||
|  |  | ||||||
|  |   const foundRelease = sortedReleases[0]; | ||||||
|  |   const foundAsset = findAsset(foundRelease, architecture, process.platform); | ||||||
|  |  | ||||||
|  |   return { | ||||||
|  |     foundAsset, | ||||||
|  |     resolvedGraalPyVersion: graalPyTagToVersion(foundRelease.tag_name) | ||||||
|  |   }; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function toGraalPyPlatform(platform: string) { | ||||||
|  |   switch (platform) { | ||||||
|  |     case 'win32': | ||||||
|  |       return 'windows'; | ||||||
|  |     case 'darwin': | ||||||
|  |       return 'macos'; | ||||||
|  |   } | ||||||
|  |   return platform; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function toGraalPyArchitecture(architecture: string) { | ||||||
|  |   switch (architecture) { | ||||||
|  |     case 'x64': | ||||||
|  |       return 'amd64'; | ||||||
|  |     case 'arm64': | ||||||
|  |       return 'aarch64'; | ||||||
|  |   } | ||||||
|  |   return architecture; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function findAsset( | ||||||
|  |   item: IGraalPyManifestRelease, | ||||||
|  |   architecture: string, | ||||||
|  |   platform: string | ||||||
|  | ) { | ||||||
|  |   const graalpyArch = toGraalPyArchitecture(architecture); | ||||||
|  |   const graalpyPlatform = toGraalPyPlatform(platform); | ||||||
|  |   const found = item.assets.filter( | ||||||
|  |     file => | ||||||
|  |       file.name.startsWith('graalpy') && | ||||||
|  |       file.name.endsWith(`-${graalpyPlatform}-${graalpyArch}.tar.gz`) | ||||||
|  |   ); | ||||||
|  |   /* | ||||||
|  |   In the future there could be more variants of GraalPy for a single release. Pick the shortest name, that one is the most likely to be the primary variant. | ||||||
|  |   */ | ||||||
|  |   found.sort((f1, f2) => f1.name.length - f2.name.length); | ||||||
|  |   return found[0]; | ||||||
|  | } | ||||||
| @@ -13,7 +13,8 @@ import { | |||||||
|   IPyPyManifestRelease, |   IPyPyManifestRelease, | ||||||
|   createSymlinkInFolder, |   createSymlinkInFolder, | ||||||
|   isNightlyKeyword, |   isNightlyKeyword, | ||||||
|   writeExactPyPyVersionFile |   writeExactPyPyVersionFile, | ||||||
|  |   getBinaryDirectory | ||||||
| } from './utils'; | } from './utils'; | ||||||
|  |  | ||||||
| export async function installPyPy( | export async function installPyPy( | ||||||
| @@ -94,7 +95,7 @@ export async function installPyPy( | |||||||
|  |  | ||||||
|     writeExactPyPyVersionFile(installDir, resolvedPyPyVersion); |     writeExactPyPyVersionFile(installDir, resolvedPyPyVersion); | ||||||
|  |  | ||||||
|     const binaryPath = getPyPyBinaryPath(installDir); |     const binaryPath = getBinaryDirectory(installDir); | ||||||
|     await createPyPySymlink(binaryPath, resolvedPythonVersion); |     await createPyPySymlink(binaryPath, resolvedPythonVersion); | ||||||
|     await installPip(binaryPath); |     await installPip(binaryPath); | ||||||
|  |  | ||||||
| @@ -237,15 +238,6 @@ export function findRelease( | |||||||
|   }; |   }; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** Get PyPy binary location from the tool of installation directory |  | ||||||
|  *  - On Linux and macOS, the Python interpreter is in 'bin'. |  | ||||||
|  *  - On Windows, it is in the installation root. |  | ||||||
|  */ |  | ||||||
| export function getPyPyBinaryPath(installDir: string) { |  | ||||||
|   const _binDir = path.join(installDir, 'bin'); |  | ||||||
|   return IS_WINDOWS ? installDir : _binDir; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function pypyVersionToSemantic(versionSpec: string) { | export function pypyVersionToSemantic(versionSpec: string) { | ||||||
|   const prereleaseVersion = /(\d+\.\d+\.\d+)((?:a|b|rc))(\d*)/g; |   const prereleaseVersion = /(\d+\.\d+\.\d+)((?:a|b|rc))(\d*)/g; | ||||||
|   return versionSpec.replace(prereleaseVersion, '$1-$2.$3'); |   return versionSpec.replace(prereleaseVersion, '$1-$2.$3'); | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| import * as core from '@actions/core'; | import * as core from '@actions/core'; | ||||||
| import * as finder from './find-python'; | import * as finder from './find-python'; | ||||||
| import * as finderPyPy from './find-pypy'; | import * as finderPyPy from './find-pypy'; | ||||||
|  | import * as finderGraalPy from './find-graalpy'; | ||||||
| import * as path from 'path'; | import * as path from 'path'; | ||||||
| import * as os from 'os'; | import * as os from 'os'; | ||||||
| import fs from 'fs'; | import fs from 'fs'; | ||||||
| @@ -17,6 +18,10 @@ function isPyPyVersion(versionSpec: string) { | |||||||
|   return versionSpec.startsWith('pypy'); |   return versionSpec.startsWith('pypy'); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function isGraalPyVersion(versionSpec: string) { | ||||||
|  |   return versionSpec.startsWith('graalpy'); | ||||||
|  | } | ||||||
|  |  | ||||||
| async function cacheDependencies(cache: string, pythonVersion: string) { | async function cacheDependencies(cache: string, pythonVersion: string) { | ||||||
|   const cacheDependencyPath = |   const cacheDependencyPath = | ||||||
|     core.getInput('cache-dependency-path') || undefined; |     core.getInput('cache-dependency-path') || undefined; | ||||||
| @@ -106,10 +111,20 @@ async function run() { | |||||||
|           core.info( |           core.info( | ||||||
|             `Successfully set up PyPy ${installed.resolvedPyPyVersion} with Python (${installed.resolvedPythonVersion})` |             `Successfully set up PyPy ${installed.resolvedPyPyVersion} with Python (${installed.resolvedPythonVersion})` | ||||||
|           ); |           ); | ||||||
|  |         } else if (isGraalPyVersion(version)) { | ||||||
|  |           const installed = await finderGraalPy.findGraalPyVersion( | ||||||
|  |             version, | ||||||
|  |             arch, | ||||||
|  |             updateEnvironment, | ||||||
|  |             checkLatest, | ||||||
|  |             allowPreReleases | ||||||
|  |           ); | ||||||
|  |           pythonVersion = `${installed}`; | ||||||
|  |           core.info(`Successfully set up GraalPy ${installed}`); | ||||||
|         } else { |         } else { | ||||||
|           if (version.startsWith('2')) { |           if (version.startsWith('2')) { | ||||||
|             core.warning( |             core.warning( | ||||||
|               'The support for python 2.7 will be removed on June 19. Related issue: https://github.com/actions/setup-python/issues/672' |               'The support for python 2.7 was removed on June 19, 2023. Related issue: https://github.com/actions/setup-python/issues/672' | ||||||
|             ); |             ); | ||||||
|           } |           } | ||||||
|           const installed = await finder.useCpythonVersion( |           const installed = await finder.useCpythonVersion( | ||||||
|   | |||||||
							
								
								
									
										46
									
								
								src/utils.ts
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								src/utils.ts
									
									
									
									
									
								
							| @@ -6,6 +6,7 @@ import * as path from 'path'; | |||||||
| import * as semver from 'semver'; | import * as semver from 'semver'; | ||||||
| import * as toml from '@iarna/toml'; | import * as toml from '@iarna/toml'; | ||||||
| import * as exec from '@actions/exec'; | import * as exec from '@actions/exec'; | ||||||
|  | import * as ifm from '@actions/http-client/interfaces'; | ||||||
|  |  | ||||||
| export const IS_WINDOWS = process.platform === 'win32'; | export const IS_WINDOWS = process.platform === 'win32'; | ||||||
| export const IS_LINUX = process.platform === 'linux'; | export const IS_LINUX = process.platform === 'linux'; | ||||||
| @@ -29,6 +30,16 @@ export interface IPyPyManifestRelease { | |||||||
|   files: IPyPyManifestAsset[]; |   files: IPyPyManifestAsset[]; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | export interface IGraalPyManifestAsset { | ||||||
|  |   name: string; | ||||||
|  |   browser_download_url: string; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export interface IGraalPyManifestRelease { | ||||||
|  |   tag_name: string; | ||||||
|  |   assets: IGraalPyManifestAsset[]; | ||||||
|  | } | ||||||
|  |  | ||||||
| /** create Symlinks for downloaded PyPy | /** create Symlinks for downloaded PyPy | ||||||
|  *  It should be executed only for downloaded versions in runtime, because |  *  It should be executed only for downloaded versions in runtime, because | ||||||
|  *  toolcache versions have this setup. |  *  toolcache versions have this setup. | ||||||
| @@ -90,7 +101,7 @@ export function writeExactPyPyVersionFile( | |||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Python version should be specified explicitly like "x.y" (2.7, 3.6, 3.7) |  * Python version should be specified explicitly like "x.y" (3.10, 3.11, etc) | ||||||
|  * "3.x" or "3" are not supported |  * "3.x" or "3" are not supported | ||||||
|  * because it could cause ambiguity when both PyPy version and Python version are not precise |  * because it could cause ambiguity when both PyPy version and Python version are not precise | ||||||
|  */ |  */ | ||||||
| @@ -251,7 +262,7 @@ export function getVersionInputFromTomlFile(versionFile: string): string[] { | |||||||
|  */ |  */ | ||||||
| export function getVersionInputFromPlainFile(versionFile: string): string[] { | export function getVersionInputFromPlainFile(versionFile: string): string[] { | ||||||
|   core.debug(`Trying to resolve version form ${versionFile}`); |   core.debug(`Trying to resolve version form ${versionFile}`); | ||||||
|   const version = fs.readFileSync(versionFile, 'utf8'); |   const version = fs.readFileSync(versionFile, 'utf8').trim(); | ||||||
|   core.info(`Resolved ${versionFile} as ${version}`); |   core.info(`Resolved ${versionFile} as ${version}`); | ||||||
|   return [version]; |   return [version]; | ||||||
| } | } | ||||||
| @@ -266,3 +277,34 @@ export function getVersionInputFromFile(versionFile: string): string[] { | |||||||
|     return getVersionInputFromPlainFile(versionFile); |     return getVersionInputFromPlainFile(versionFile); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Get the directory containing interpreter binary from installation directory of PyPy or GraalPy | ||||||
|  |  *  - On Linux and macOS, the Python interpreter is in 'bin'. | ||||||
|  |  *  - On Windows, it is in the installation root. | ||||||
|  |  */ | ||||||
|  | export function getBinaryDirectory(installDir: string) { | ||||||
|  |   return IS_WINDOWS ? installDir : path.join(installDir, 'bin'); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Extract next page URL from a HTTP response "link" header. Such headers are used in GitHub APIs. | ||||||
|  |  */ | ||||||
|  | export function getNextPageUrl<T>(response: ifm.ITypedResponse<T>) { | ||||||
|  |   const responseHeaders = <ifm.IHeaders>response.headers; | ||||||
|  |   const linkHeader = responseHeaders.link; | ||||||
|  |   if (typeof linkHeader === 'string') { | ||||||
|  |     for (const link of linkHeader.split(/\s*,\s*/)) { | ||||||
|  |       const match = link.match(/<([^>]+)>(.*)/); | ||||||
|  |       if (match) { | ||||||
|  |         const url = match[1]; | ||||||
|  |         for (const param of match[2].split(/\s*;\s*/)) { | ||||||
|  |           if (param.match(/rel="?next"?/)) { | ||||||
|  |             return url; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   return null; | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user