Compare commits

..

130 Commits

Author SHA1 Message Date
c4e89fac7e Improve readme for 3.x and 3.11-dev style python-version (#441) 2022-07-07 23:34:44 +02:00
0ad0f6a0a5 Merge pull request #452 from mayeut/fix-env
Remove duplicate code introduced in #440
2022-07-06 16:11:51 +02:00
f0bcf8be03 Merge pull request #456 from akx/patch-1
doc: Add multiple wildcards example to readme
2022-07-05 08:23:25 +02:00
af97157ae6 doc: Add multiple wildcards example to readme
Based on https://www.npmjs.com/package/@actions/glob (the library used for cache file globbing), newline-separating multiple patterns is accepted.
2022-07-04 12:24:58 +03:00
364e819741 Merge pull request #394 from akv-platform/v-sedoli/set-env-by-default
Assign default value of AGENT_TOOLSDIRECTORY if not set
2022-07-04 10:35:46 +02:00
782f81b91d Merge pull request #450 from IvanZosimov/ResolveVersionFix
Rearranged logic of the ResolveVersionInput()
2022-07-04 08:20:42 +02:00
2c9de4ed41 Remove duplicate code introduced in #440
#440 duplicated a block of code outside of `if (updateEnvironment) {` condition. This was probably an oversight when merging `main` back on the PR branch. The tests should have seen that `core.exportVariable` was being called and should have failed.
2022-07-02 11:50:48 +02:00
412091c1e0 Fix tests for update-environment==false 2022-07-02 11:50:48 +02:00
78a2330b92 Merge pull request #451 from dmitry-shibanov/fx-pipenv-python-version
Fx pipenv python version
2022-07-01 16:57:38 +02:00
96f494e18c trigger checks 2022-07-01 10:28:46 +02:00
099ed898be Optimize code 2022-06-30 18:42:04 +02:00
ccb7da8ae9 Change warning handler to default 2022-06-30 18:28:17 +02:00
5fbb819407 Optimize logic, rebuild action 2022-06-30 17:32:12 +02:00
82eddc4023 Add warning in case the versionFile isn't found 2022-06-30 16:34:29 +02:00
d97b6edda3 Fix typos 2022-06-30 16:25:46 +02:00
a6b01c4e40 Rebuild action with new changes 2022-06-30 16:22:51 +02:00
84087f5301 Rearrange logic 2022-06-30 16:21:14 +02:00
56f6060254 Fix naming 2022-06-30 14:41:09 +02:00
e29a7c89f6 Merge branch 'main' into ResolveVersionFix 2022-06-30 14:40:24 +02:00
5407bf6e69 Merge pull request #448 from IvanZosimov/CacheLibVersionUpdate
Add support for the @actions/cache library 3.0.0
2022-06-30 14:38:10 +02:00
41b91104ea Rebuild action 2022-06-30 14:26:40 +02:00
08116500d0 Rebuild action 2022-06-30 14:19:36 +02:00
161c3a68f0 Merge branch 'main' into CacheLibVersionUpdate 2022-06-30 14:18:06 +02:00
6733fc44ec Fix typo 2022-06-30 13:44:10 +02:00
afd3e72a25 Fix bug in resolveVersionInput() 2022-06-30 13:38:43 +02:00
ab6deb310f Merge pull request #440 from akv-platform/v-sdolin/issue-231
Add CMake hints
2022-06-30 08:56:04 +02:00
e629242ad4 Fix failed check 2022-06-30 07:56:08 +02:00
63086c6ded rebase main 2022-06-30 07:46:53 +02:00
69b94463f5 Add CMake hints 2022-06-30 07:43:57 +02:00
d7db8259d9 update pypy versions 2022-06-29 23:41:39 +02:00
27091d50ca minor fix 2022-06-29 20:38:02 +02:00
d358f9e3d7 fix check 2022-06-29 20:28:20 +02:00
1e52de40a4 fixing pipenv 2022-06-29 20:16:07 +02:00
2a20d9b5e0 add --python 3 2022-06-29 19:36:35 +02:00
766e8c6088 Fixing pipenv CI (#444)
* work on fixing pipenv

* change installation of pipenv to curl

* add different logs

* regenerate pipefile.lock

* change pipenv ci
2022-06-29 13:09:14 -04:00
00a5248c77 feature: add update-environment input (#411)
This option allows to specify if the action shall update environment variables (default) or not.
This allows to use the setup-python action in a composite action without side effect (except downloading/installing python if version is missing).
2022-06-29 11:00:51 -04:00
9c76df2a90 Build after rebase 2022-06-29 11:24:02 +02:00
958897304a Exclude windows from the fix 2022-06-29 11:22:07 +02:00
5d9fdcab75 Handle each OS in its own way 2022-06-29 11:22:07 +02:00
7199395312 Fix dist folder 2022-06-29 11:22:06 +02:00
5ad79022bc Change README 2022-06-29 11:21:25 +02:00
a8da2a66aa Use /opt/hostedtoolcache as default value AGENT_TOOLSDIRECTORY 2022-06-29 11:21:21 +02:00
c61bc3d08e Update licenses 2022-06-28 15:40:29 +02:00
01408cef88 Update cache-save.ts to support @actions/cache v3.0.0 lib
Made package.json and package-lock.json to use @actions/cache v3.0.0,
updated logic of the cache-save operation and added unit-tests
2022-06-28 15:17:50 +02:00
ffcd00020c Allow python-version-file to be a relative path (#431) 2022-06-20 16:04:59 +02:00
cf86e08a31 Revert "Pass the token input through on GHES (#427)" (#437)
This reverts commit 7e4abae443.
2022-06-16 11:08:06 -04:00
8fb4cbf7c8 README: Document pypy2 and pypy3 are deprecated (#265) 2022-06-15 14:03:21 +02:00
7e4abae443 Pass the token input through on GHES (#427)
* Pass the`token` input through on GHES

* Update the description for `token`

* Fix dist files

* Update package-lock.json

* Update README

* Fix indent level in YAML snippet

* secret names can't start with GITHUB_
2022-06-13 14:55:47 -04:00
813f9b1556 Merge pull request #423 from vsafonkin/v-vsafonkin/update-docs-v4
Update docs to v4 version
2022-06-09 10:56:24 +02:00
775367df99 Update docs to v4 version 2022-06-09 09:54:52 +02:00
d09bd5e600 fix: 3.x-dev can install a 3.y version (#417)
* fix: 3.x-dev can install a 3.y version

* Update README section for `-dev`
2022-06-08 14:58:05 +02:00
f72db171ab Made env.var pythonLocation consistent for Python and PyPy (#418)
* Change find-pypy.ts to redefine pythonLocaction environment variable

* Change README.md in order to add sentence about pythonLocation envvar

* Change sentence about pythonLocation envvar in README.md

* Rephrase the definition of pythonLocation env.var
2022-06-08 14:57:23 +02:00
53e15292cd add support for python-version-file (#336)
* add support for python-version-file

* Update action.yml

* update to v4, remove python-version default

* python-version overrides python-version-file, like setup-node
* checks '.python-version' by default if nothing else specified

* update tests, update to checkout@v3

* update build

* appease the linter

* remove old test for default python version

* revert readme changes

* update build
2022-06-02 16:37:57 +02:00
3f82819745 Fix output for prerelease version of poetry (#409) 2022-05-31 15:48:54 +02:00
397252c582 Update zeit/ncc to vercel/ncc (#393) 2022-05-31 12:56:29 +02:00
de977ad132 Merge pull request #412 from vsafonkin/v-vsafonkin/fix-poetry-cache-test
Fix e2e test for poetry cache and PyPy-3.7
2022-05-31 09:41:08 +02:00
22c6af91ce Change PyPy version to rebuild cache 2022-05-30 15:02:04 +02:00
081a3cf1a5 Merge pull request #405 from mayeut/interpreter-path
feature: add a `python-path` output
2022-05-25 11:02:46 +02:00
ff706563d7 feature: add a python-path output
Expose a `python-path` output containing the chosen Python executable path.
2022-05-24 21:02:03 +02:00
fff15a21cc Use pypyX.Y for PyPy python-version input (#349)
This versioning scheme is consistent with other
tools in the python ecosystem so it feels more natural
and allows better interaction with other tools.

fixes #346
2022-05-18 15:20:53 +02:00
c57f79353b Merge pull request #318 from neutrinoceros/document_dev_sugar
DOC: document -dev syntactic sugar
2022-05-06 13:03:34 +02:00
fd8f0a9fb8 Merge pull request #396 from akv-platform/v-sedoli/issue-241
Add warning if python version set to empty value
2022-05-04 15:21:43 +02:00
ae11205ec6 Merge pull request #400 from akv-platform/v-sedoli/pkg-config
set PKG_CONFIG_PATH environment var
2022-05-04 09:56:28 +02:00
8f73c1495f Formatting 2022-05-04 12:55:36 +05:00
e31727ce0a Improve warning message
Co-authored-by: Brian Cristante <33549821+brcrista@users.noreply.github.com>
2022-05-04 12:43:58 +05:00
a69041ca9f Successfully set up (#399) 2022-05-03 08:43:53 -04:00
5e1e05c694 set PKG_CONFIG_PATH environment var 2022-05-03 16:04:39 +05:00
0b56b76337 Improve wording 2022-04-29 12:49:49 +05:00
22daa094b8 Add generated files 2022-04-29 09:29:36 +05:00
ac4e858835 Add warning if python version set to empty value 2022-04-29 09:14:59 +05:00
1ce308808a Create missing pypyX.Y symlinks (#347)
`pypyX.Y.exe` executables are missing from PyPy archives on Windows before v7.3.9 (X.Y < 3.9)
`pypy2.7` symlinks are also missing from macOS/Linux PyPy archives before v7.3.9

relates to #346
2022-04-28 09:26:17 -04:00
c36dc43e7b Fix conflicts (#389) 2022-04-26 16:50:29 +02:00
4e6b5f40fc Merge pull request #384 from akv-platform/main
Add CODE_OF_CONDUCT
2022-04-21 08:59:12 +02:00
bcc31375e1 Throw exe on empty python-version 2022-04-21 08:19:23 +05:00
85a7430316 Merge branch 'actions:main' into main 2022-04-21 08:16:01 +05:00
6a4c6c1309 adjust documentation for python versions (#388) 2022-04-20 14:48:22 +02:00
3a63f5d525 Merge branch 'actions:main' into main 2022-04-20 12:09:38 +05:00
4a33d3c467 Merge pull request #387 from vsafonkin/v-vsafonkin/fix-readme-outdated-links
Fix virtual-env toolcache outdated links
2022-04-19 17:06:22 +03:00
abfd16b121 Fix virtual-env toolcache links 2022-04-19 15:21:09 +02:00
4176166af9 Add CODE_OF_CONDUCT 2022-04-18 16:04:39 +05:00
91712e11bb Merge pull request #338 from akv-demo/main
Force TOOLCACHE_ROOT to be equal AGENT_TOOLSDIRECTORY
2022-04-15 09:54:33 +02:00
98f2ad02fd Updated @actions/cache (#382) 2022-04-11 19:06:33 +05:30
5d6f0c8a87 ci(workflow): add 'npm' cache for actions/setup-node in .github/workflows (#379) 2022-04-07 12:16:24 +02:00
f4b66dec00 Merge branch 'actions:main' into main 2022-04-06 12:51:31 +05:00
21c0493ecf Cache hit output (#373)
* Remove useless await in getCacheDistributor calls

* Added cache-hit output

* Build action with cache-hit output

* Remove PromiseReturnType, add matchedKey == primaryKey check

* Update cache-distributor.ts

* Fix tests and rebuild
2022-04-05 09:57:13 -04:00
7933d5a3dd Add pyton-version to setup PyPy output (#365)
* Add pyton-version to setup PyPy output

* remove new line from pypy version

* Move setOutput to findPyPyVersion

* Resolve conflict: 2
2022-04-04 13:12:56 -04:00
7885ec3539 Rework pipenv caching test (#375)
* Rework python-pipenv-dependencies-caching test

* Update Pipfile.lock hash in the tests

* Rework python-pipenv-dependencies-caching-path test

* Set location for pipenv test

* Remove requests package from tests

* Test pipenv without caching

* Enable pipenv cache
2022-04-04 09:12:24 -04:00
9c644ca2ab Update README.md to fix setup-python version in example (#368) 2022-04-01 13:20:54 +02:00
3e8e90edf0 dist fix (#367) 2022-04-01 12:54:05 +02:00
05fb98de9a Cache on ghes (#363)
* initial changes

* updated version

* format check

* refactored code

* updated test cases

* Update src/utils.ts

Co-authored-by: Brian Cristante <33549821+brcrista@users.noreply.github.com>

* Update utils.ts

* Update utils.test.ts

* review comments

* dist update

* Review comment

* update version

* updated version

Co-authored-by: Brian Cristante <33549821+brcrista@users.noreply.github.com>
2022-03-31 15:11:27 -04:00
6c566026c0 Merge pull request #281 from patrick91/feature/poetry-caching
Add poetry caching support
2022-03-31 13:27:09 -04:00
9516be869f Merge pull request #358 from actions/brcrista/codeql-main
Run CodeQL only on pushes to main
2022-03-31 10:54:02 -04:00
7aa3e95001 Update dist 2022-03-30 16:47:06 -05:00
6c31eb3fc7 Use \n instead of os.EOL
Co-authored-by: Brian Cristante <33549821+brcrista@users.noreply.github.com>
2022-03-30 22:41:41 +01:00
7a37d78806 Update dist 2022-03-30 10:07:42 -05:00
e4be7a40b0 Initialise pyproject.toml 2022-03-28 13:42:47 -05:00
aac0ef93ba Build and format 2022-03-25 22:54:10 -05:00
b0c8e3dab7 Remove console.log 2022-03-25 22:53:31 -05:00
0ebf7997c4 Remove unused file 2022-03-25 22:53:31 -05:00
415c3568c9 Reduce test matrix 2022-03-25 22:53:31 -05:00
42ed863652 Parse values from poetry 2022-03-25 22:53:31 -05:00
c275cf49c7 Release 2022-03-25 22:53:30 -05:00
7c950ebdca Add more tests 2022-03-25 22:53:30 -05:00
1259541ec8 Add tests 2022-03-25 22:53:30 -05:00
95824fd246 Get poetry cache implementation when requested 2022-03-25 22:53:30 -05:00
59cb3f4919 Add untest poetry cache implementation 2022-03-25 22:53:30 -05:00
18c67b44e4 Initial preparation to add support for poetry 2022-03-25 22:53:30 -05:00
bbebfafece Run CodeQL only on pushes to main 2022-03-24 09:48:15 -04:00
6c048c7558 Merge pull request #357 from actions/dependabot/npm_and_yarn/minimist-1.2.6
Bump minimist from 1.2.5 to 1.2.6
2022-03-24 09:34:43 -04:00
0ff64a7f0e Bump minimist from 1.2.5 to 1.2.6
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-24 11:25:49 +00:00
792c23f43e Merge pull request #356 from cclauss/patch-2
README.md: Upgrade to v3
2022-03-17 09:45:50 -04:00
8c1441c007 README.md: Upgrade to v3
* https://github.com/actions/checkout/releases
* https://github.com/actions/setup-python/releases
2022-03-17 07:40:10 +01:00
0ebf233433 Remove legacy PyPy input (#342) 2022-02-28 10:19:48 +03:00
665cd78205 Update lockfileversion (#341) 2022-02-25 14:12:36 +03:00
93cb78f17b Update to node16 (#340) 2022-02-25 12:31:18 +03:00
65fe6a82c7 Use template literals instead of string concatenation 2022-02-21 05:26:51 +00:00
011c443f81 prettier 2022-02-17 19:21:13 +00:00
3250b5373c Force RUNNER_TOOL_CACHE to be equal AGENT_TOOLSDIRECTORY 2022-02-17 18:35:19 +00:00
7f80679172 Add fix for Windows caching of pip (#332) 2022-02-04 14:00:41 +03:00
dc9de69ff3 Update node-fetch from 2.6.6 to 2.6.7 (#327) 2022-02-01 14:17:23 +03:00
ba33a692f1 Include Python version in pip cache key (#303) 2022-01-31 13:42:08 +03:00
156361d073 Fix ci for pipenv and reduce test matrix (#323) 2022-01-26 18:54:54 +03:00
0bcf8ef2ba DOC: document -dev syntactic sugar 2022-01-12 10:35:17 +01:00
9a115684c9 README.md: Bring Python versions up to date (#256) 2021-12-30 11:55:42 +03:00
3a40ba0199 Fix small typo in README (comma missing) (#277) 2021-12-29 16:01:07 +03:00
fa17801fa7 Fix typo in README.md (#224) 2021-12-29 15:30:46 +03:00
6277dd1255 Fix build command (#306) 2021-12-21 15:44:58 +03:00
2b732b899c Removing a non-existent command from the documentation (#293) 2021-12-13 18:51:02 +03:00
f382193329 Update @actions/cache version to 1.0.8 (#283) 2021-11-29 12:19:53 +03:00
3ef38b826b Create ADR for integrating cache functionality to setup-python action (#247) 2021-11-18 13:29:22 +03:00
42 changed files with 73011 additions and 59010 deletions

View File

@ -23,10 +23,11 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Set Node.js 12.x
uses: actions/setup-node@v1
- name: Set Node.js 16.x
uses: actions/setup-node@v3
with:
node-version: 12.x
node-version: 16.x
cache: npm
- name: Install dependencies
run: npm ci

View File

@ -2,6 +2,7 @@ name: "Code scanning - action"
on:
push:
branches: [ 'main' ]
pull_request:
schedule:
- cron: '25 3 * * 5'

View File

@ -21,9 +21,9 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ['3.7', '3.8', '3.9', 'pypy-3.7-v7.3.5', 'pypy-3.7-v7.x']
python-version: ['3.9', 'pypy-3.7-v7.x']
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Setup Python
uses: ./
with:
@ -39,18 +39,48 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ['3.7', '3.8', '3.9', 'pypy-3.7-v7.3.5', 'pypy-3.7-v7.x']
python-version: ['3.9', 'pypy-3.9-v7.x']
steps:
- uses: actions/checkout@v2
- name: Install pipenv
run: pipx install pipenv
- uses: actions/checkout@v3
- name: Setup Python
uses: ./
with:
python-version: ${{ matrix.python-version }}
cache: 'pipenv'
- name: Install pipenv
run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python
- name: Install dependencies
run: pipenv install flake8
shell: pwsh
run: |
mv ./__tests__/data/Pipfile.lock .
mv ./__tests__/data/Pipfile .
if ("${{ matrix.python-version }}" -Match "pypy") {
pipenv install --keep-outdated --python pypy
} else {
pipenv install --keep-outdated --python ${{ matrix.python-version }}
}
python-poetry-dependencies-caching:
name: Test poetry (Python ${{ matrix.python-version}}, ${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ['3.9', 'pypy-3.8']
steps:
- uses: actions/checkout@v3
- name: Install poetry
run: pipx install poetry
- name: Setup Python
uses: ./
with:
python-version: ${{ matrix.python-version }}
cache: 'poetry'
- name: Init pyproject.toml
run: poetry init -n
- name: Install dependencies
run: poetry add flake8
python-pip-dependencies-caching-path:
name: Test pip (Python ${{ matrix.python-version}}, ${{ matrix.os }})
@ -59,9 +89,9 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ['3.7', '3.8', '3.9', 'pypy-3.7-v7.3.5', 'pypy-3.7-v7.x']
python-version: ['3.9', 'pypy-3.7-v7.x']
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Setup Python
uses: ./
with:
@ -78,16 +108,24 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ['3.7', '3.8', '3.9', 'pypy-3.7-v7.3.5', 'pypy-3.7-v7.x']
python-version: ['3.9', 'pypy-3.9-v7.x']
steps:
- uses: actions/checkout@v2
- name: Install pipenv
run: pipx install pipenv
- uses: actions/checkout@v3
- name: Setup Python
uses: ./
with:
python-version: ${{ matrix.python-version }}
cache: 'pipenv'
cache-dependency-path: '**/requirements-linux.txt'
cache-dependency-path: '**/pipenv-requirements.txt'
- name: Install pipenv
run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python
- name: Install dependencies
run: pipenv install flake8
shell: pwsh
run: |
mv ./__tests__/data/Pipfile.lock .
mv ./__tests__/data/Pipfile .
if ("${{ matrix.python-version }}" -Match "pypy") {
pipenv install --keep-outdated --python pypy
} else {
pipenv install --keep-outdated --python ${{ matrix.python-version }}
}

View File

@ -14,11 +14,16 @@ jobs:
name: Check licenses
steps:
- uses: actions/checkout@v2
- name: Set Node.js 16.x
uses: actions/setup-node@v3
with:
node-version: 16.x
cache: npm
- run: npm ci
- name: Install licensed
run: |
cd $RUNNER_TEMP
curl -Lfs -o licensed.tar.gz https://github.com/github/licensed/releases/download/2.12.2/licensed-2.12.2-linux-x64.tar.gz
curl -Lfs -o licensed.tar.gz https://github.com/github/licensed/releases/download/3.4.4/licensed-3.4.4-linux-x64.tar.gz
sudo tar -xzf licensed.tar.gz
sudo mv licensed /usr/local/bin/licensed
- run: licensed status

View File

@ -22,6 +22,7 @@ jobs:
pypy:
- 'pypy-2.7'
- 'pypy-3.7'
- 'pypy3.9'
- 'pypy-2.7-v7.3.4'
- 'pypy-3.7-v7.3.5'
- 'pypy-3.7-v7.3.4'
@ -29,18 +30,64 @@ jobs:
- 'pypy-3.7-v7.x'
- 'pypy-2.7-v7.3.4rc1'
- 'pypy-3.7-nightly'
- 'pypy3.8-v7.3.7'
steps:
- name: Checkout
uses: actions/checkout@v2
- name: setup-python ${{ matrix.pypy }}
id: setup-python
uses: ./
with:
python-version: ${{ matrix.pypy }}
- name: Check python-path
run: ./__tests__/check-python-path.sh '${{ steps.setup-python.outputs.python-path }}'
shell: bash
- name: PyPy and Python version
run: python --version
- name: Run simple code
run: python -c 'import math; print(math.factorial(5))'
- name: Assert PyPy is running
run: |
import platform
assert platform.python_implementation().lower() == "pypy"
shell: python
- name: Assert expected binaries (or symlinks) are present
run: |
EXECUTABLE=${{ matrix.pypy }}
EXECUTABLE=${EXECUTABLE/pypy-/pypy} # remove the first '-' in "pypy-X.Y" -> "pypyX.Y" to match executable name
EXECUTABLE=${EXECUTABLE%%-*} # remove any -* suffixe
${EXECUTABLE} --version
shell: bash
setup-pypy-noenv:
name: Setup PyPy ${{ matrix.pypy }} ${{ matrix.os }} (noenv)
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-latest]
pypy: ['pypy2.7', 'pypy3.7', 'pypy3.8', 'pypy3.9-nightly']
steps:
- name: Checkout
uses: actions/checkout@v3
- name: setup-python ${{ matrix.pypy }}
id: setup-python
uses: ./
with:
python-version: ${{ matrix.pypy }}
update-environment: false
- name: PyPy 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))'

View File

@ -10,28 +10,9 @@ on:
- '**.md'
schedule:
- cron: 30 3 * * *
workflow_dispatch:
jobs:
default-version:
name: Setup default version
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-20.04]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: setup default python
uses: ./
- name: Validate version
run: python --version
- name: Run simple python code
run: python -c 'import math; print(math.factorial(5))'
setup-versions-from-manifest:
name: Setup ${{ matrix.python }} ${{ matrix.os }}
runs-on: ${{ matrix.os }}
@ -42,13 +23,56 @@ jobs:
python: [3.5.4, 3.6.7, 3.7.5, 3.8.1]
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: setup-python ${{ matrix.python }}
id: setup-python
uses: ./
with:
python-version: ${{ matrix.python }}
- name: Check python-path
run: ./__tests__/check-python-path.sh '${{ steps.setup-python.outputs.python-path }}'
shell: bash
- name: Validate version
run: |
$pythonVersion = (python --version)
if ("Python ${{ matrix.python }}" -ne "$pythonVersion"){
Write-Host "The current version is $pythonVersion; expected version is ${{ matrix.python }}"
exit 1
}
$pythonVersion
shell: pwsh
- name: Run simple code
run: python -c 'import math; print(math.factorial(5))'
setup-versions-from-file:
name: Setup ${{ matrix.python }} ${{ matrix.os }} version file
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-20.04]
python: [3.5.4, 3.6.7, 3.7.5, 3.8.1]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: build-version-file ${{ matrix.python }}
run: echo ${{ matrix.python }} > .python-version
- name: setup-python ${{ matrix.python }}
id: setup-python
uses: ./
with:
python-version-file: '.python-version'
- name: Check python-path
run: ./__tests__/check-python-path.sh '${{ steps.setup-python.outputs.python-path }}'
shell: bash
- name: Validate version
run: |
$pythonVersion = (python --version)
@ -71,13 +95,18 @@ jobs:
os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-20.04]
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: setup-python 3.9.0-beta.4
id: setup-python
uses: ./
with:
python-version: '3.9.0-beta.4'
- name: Check python-path
run: ./__tests__/check-python-path.sh '${{ steps.setup-python.outputs.python-path }}'
shell: bash
- name: Validate version
run: |
$pythonVersion = (python --version)
@ -91,23 +120,55 @@ jobs:
- name: Run simple code
run: python -c 'import math; print(math.factorial(5))'
setup-pypy-legacy:
name: Setup PyPy ${{ matrix.os }}
setup-dev-version:
name: Setup 3.9-dev ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-10.15, windows-latest, ubuntu-18.04, ubuntu-20.04]
os: [macos-latest, windows-latest, ubuntu-latest]
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: setup-python pypy3
- name: setup-python 3.9-dev
id: setup-python
uses: ./
with:
python-version: 'pypy3'
python-version: '3.9-dev'
- name: setup-python pypy2
- name: Check python-path
run: ./__tests__/check-python-path.sh '${{ steps.setup-python.outputs.python-path }}'
shell: bash
- name: Validate version
run: ${{ startsWith(steps.setup-python.outputs.python-version, '3.9.') }}
shell: bash
- name: Run simple code
run: python -c 'import math; print(math.factorial(5))'
setup-versions-noenv:
name: Setup ${{ matrix.python }} ${{ matrix.os }} (noenv)
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-20.04]
python: ["3.7", "3.8", "3.9", "3.10"]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: setup-python ${{ matrix.python }}
id: setup-python
uses: ./
with:
python-version: 'pypy2'
python-version: ${{ matrix.python }}
update-environment: false
- name: 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))'

View File

@ -19,13 +19,14 @@ jobs:
- name: Checkout
uses: actions/checkout@v2
- name: Set Node.js 12.x
uses: actions/setup-node@v1
- name: Set Node.js 16.x
uses: actions/setup-node@v3
with:
node-version: 12.x
node-version: 16.x
cache: npm
- name: npm install
run: npm install
- name: npm ci
run: npm ci
- name: Lint
run: npm run format-check
@ -88,3 +89,13 @@ jobs:
python-version: 3.8.1
- name: Verify 3.8.1
run: python __tests__/verify-python.py 3.8.1
- name: Run with setup-python 3.10
id: cp310
uses: ./
with:
python-version: "3.10"
- name: Verify 3.10
run: python __tests__/verify-python.py 3.10
- name: Run python-path sample 3.10
run: pipx run --python '${{ steps.cp310.outputs.python-path }}' nox --version

View File

@ -1,6 +1,6 @@
---
name: "@actions/cache"
version: 1.0.7
version: 3.0.0
type: npm
summary: Actions cache lib
homepage: https://github.com/actions/toolkit/tree/main/packages/cache

View File

@ -1,6 +1,6 @@
---
name: "@actions/core"
version: 1.2.6
version: 1.7.0
type: npm
summary: Actions core lib
homepage: https://github.com/actions/toolkit/tree/main/packages/core

View File

@ -1,6 +1,6 @@
---
name: "@actions/http-client"
version: 1.0.8
version: 2.0.1
type: npm
summary: Actions Http Client
homepage: https://github.com/actions/http-client#readme

View File

@ -0,0 +1,32 @@
---
name: "@actions/http-client"
version: 1.0.11
type: npm
summary: Actions Http Client
homepage: https://github.com/actions/http-client#readme
license: mit
licenses:
- sources: LICENSE
text: |
Actions Http Client for Node.js
Copyright (c) GitHub, Inc.
All rights reserved.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
notices: []

View File

@ -1,6 +1,6 @@
---
name: "@azure/core-http"
version: 2.2.1
version: 2.2.2
type: npm
summary: Isomorphic client Runtime for Typescript/node.js/browser javascript client
libraries generated using AutoRest

View File

@ -1,6 +1,6 @@
---
name: "@types/node"
version: 12.20.36
version: 16.11.25
type: npm
summary: TypeScript definitions for Node.js
homepage: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node

View File

@ -1,6 +1,6 @@
---
name: node-fetch
version: 2.6.5
version: 2.6.7
type: npm
summary: A light-weight module that brings window.fetch to node.js
homepage: https://github.com/bitinn/node-fetch

76
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,76 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to make participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies within all project spaces, and it also applies when
an individual is representing the project or its community in public spaces.
Examples of representing a project or community include using an official
project e-mail address, posting via an official social media account, or acting
as an appointed representative at an online or offline event. Representation of
a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at opensource+actions/setup-python@github.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

216
README.md
View File

@ -1,4 +1,4 @@
# setup-python V2
# setup-python V4
<p align="left">
<a href="https://github.com/actions/setup-python"><img alt="GitHub Actions status" src="https://github.com/actions/setup-python/workflows/Main%20workflow/badge.svg"></a>
@ -9,7 +9,7 @@ This action sets up a Python environment for use in actions by:
- optionally installing and adding to PATH a version of Python that is already installed in the tools cache.
- downloading, installing and adding to PATH an available version of Python from GitHub Releases ([actions/python-versions](https://github.com/actions/python-versions/releases)) if a specific version is not available in the tools cache.
- failing if a specific version of Python is not preinstalled or available for download.
- optionally caching dependencies for pip and pipenv.
- optionally caching dependencies for pip, pipenv and poetry.
- registering problem matchers for error output.
# What's new
@ -19,7 +19,8 @@ This action sets up a Python environment for use in actions by:
- Automatic setup and download of Python packages if using a self-hosted runner.
- Support for pre-release versions of Python.
- Support for installing any version of PyPy on-flight
- Support for built-in caching of pip and pipenv dependencies
- Support for built-in caching of pip, pipenv and poetry dependencies
- Support for `.python-version` file
# Usage
@ -28,14 +29,24 @@ See [action.yml](action.yml)
Basic:
```yaml
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.x' # Version range or exact version of a Python version to use, using SemVer's version range syntax
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
- run: python my_script.py
```
Read Python version from file:
```yaml
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version-file: '.python-version' # Read python version from a file
- run: python my_script.py
```
Matrix Testing:
```yaml
jobs:
@ -43,12 +54,12 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ '2.x', '3.x', 'pypy-2.7', 'pypy-3.6', 'pypy-3.7' ]
python-version: [ '2.x', '3.x', 'pypy2.7', 'pypy3.7', 'pypy3.8' ]
name: Python ${{ matrix.python-version }} sample
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
architecture: x64
@ -63,20 +74,20 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ['2.7', '3.6', '3.7', '3.8', 'pypy-2.7', 'pypy-3.6']
python-version: ['2.7', '3.7', '3.8', '3.9', '3.10', 'pypy2.7', 'pypy3.8']
exclude:
- os: macos-latest
python-version: '3.8'
- os: windows-latest
python-version: '3.6'
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Display Python version
run: python -c "import sys; print(sys.version)"
run: python --version
```
Download and set up a version of Python that does not come preinstalled on an image:
@ -87,10 +98,10 @@ jobs:
strategy:
matrix:
# in this example, there is a newer version already installed, 3.7.7, so the older version will be downloaded
python-version: ['3.5', '3.6', '3.7.4', '3.8']
python-version: ['3.7.4', '3.8', '3.9', '3.10']
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- run: python my_script.py
@ -99,20 +110,40 @@ jobs:
Download and set up an accurate pre-release version of Python:
```yaml
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.9.0-beta.4'
python-version: '3.11.0-alpha.1'
- run: python my_script.py
```
Download and set up the latest available version of Python (includes both pre-release and stable versions):
```yaml
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.9.0-alpha - 3.9.0' # SemVer's version range syntax
python-version: '3.11.0-alpha - 3.11.0' # SemVer's version range syntax
- run: python my_script.py
```
Download and set up the latest patch version of Python (for specified major & minor versions):
```yaml
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.11-dev'
- run: python my_script.py
```
Download and set up the latest stable version of Python (for specified major version):
```yaml
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.x'
- run: python my_script.py
```
@ -125,18 +156,34 @@ jobs:
strategy:
matrix:
python-version:
- 'pypy-3.6' # the latest available version of PyPy that supports Python 3.6
- 'pypy-3.7' # the latest available version of PyPy that supports Python 3.7
- 'pypy-3.7-v7.3.3' # Python 3.7 and PyPy 7.3.3
- '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.8' # the latest available version of PyPy that supports Python 3.8
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- run: python my_script.py
```
More details on PyPy syntax and examples of using preview / nightly versions of PyPy can be found in the [Available versions of PyPy](#available-versions-of-pypy) section.
An output is available with the absolute path of the python interpreter executable if you need it:
```yaml
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
id: cp310
with:
python-version: "3.10"
- run: pipx run --python '${{ steps.cp310.outputs.python-path }}' nox --version
```
>The environment variable `pythonLocation` also becomes available after Python or PyPy installation. It contains the absolute path to the folder where the desired version of Python or PyPy is installed.
# Getting started with Python + Actions
Check out our detailed guide on using [Python with GitHub Actions](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/using-python-with-github-actions).
@ -146,22 +193,25 @@ Check out our detailed guide on using [Python with GitHub Actions](https://help.
`setup-python` is able to configure Python from two sources:
- Preinstalled versions of Python in the tools cache on GitHub-hosted runners.
- For detailed information regarding the available versions of Python that are installed see [Supported software](https://docs.github.com/en/actions/reference/specifications-for-github-hosted-runners#supported-software).
- For detailed information regarding the available versions of Python that are installed, see [Supported software](https://docs.github.com/en/actions/reference/specifications-for-github-hosted-runners#supported-software).
- For every minor version of Python, expect only the latest patch to be preinstalled.
- If `3.8.1` is installed for example, and `3.8.2` is released, expect `3.8.1` to be removed and replaced by `3.8.2` in the tools cache.
- If the exact patch version doesn't matter to you, specifying just the major and minor version will get you the latest preinstalled patch version. In the previous example, the version spec `3.8` will use the `3.8.2` Python version found in the cache.
- Use `-dev` instead of a patch number (e.g., `3.11-dev`) to install the latest patch version release for a given minor version, *alpha and beta releases included*.
- Downloadable Python versions from GitHub Releases ([actions/python-versions](https://github.com/actions/python-versions/releases)).
- All available versions are listed in the [version-manifest.json](https://github.com/actions/python-versions/blob/main/versions-manifest.json) file.
- If there is a specific version of Python that is not available, you can open an issue here
**Note:** Python versions used in this action are generated in the [python-versions](https://github.com/actions/python-versions) repository. For macOS and Ubuntu images python versions are built from the source code. For Windows the python-versions repository uses installation executable. For more information please refer to the [python-versions](https://github.com/actions/python-versions) repository.
# Available versions of PyPy
`setup-python` is able to configure PyPy from two sources:
- Preinstalled versions of PyPy in the tools cache on GitHub-hosted runners
- For detailed information regarding the available versions of PyPy that are installed see [Supported software](https://docs.github.com/en/actions/reference/specifications-for-github-hosted-runners#supported-software).
- For detailed information regarding the available versions of PyPy that are installed, see [Supported software](https://docs.github.com/en/actions/reference/specifications-for-github-hosted-runners#supported-software).
- For the latest PyPy release, all versions of Python are cached.
- Cache is updated with a 1-2 week delay. If you specify the PyPy version as `pypy-3.6`, the cached version will be used although a newer version is available. If you need to start using the recently released version right after release, you should specify the exact PyPy version using `pypy-3.6-v7.3.3`.
- Cache is updated with a 1-2 week delay. If you specify the PyPy version as `pypy3.7` or `pypy-3.7`, the cached version will be used although a newer version is available. If you need to start using the recently released version right after release, you should specify the exact PyPy version using `pypy3.7-v7.3.3` or `pypy-3.7-v7.3.3`.
- Downloadable PyPy versions from the [official PyPy site](https://downloads.python.org/pypy/).
- All available versions that we can download are listed in [versions.json](https://downloads.python.org/pypy/versions.json) file.
@ -179,8 +229,8 @@ GitHub hosted runners have a tools cache that comes with a few versions of Pytho
|**PyPy Tool Cache**|`RUNNER_TOOL_CACHE/PyPy/*`|
GitHub virtual environments are setup in [actions/virtual-environments](https://github.com/actions/virtual-environments). During the setup, the available versions of Python and PyPy are automatically downloaded, setup and documented.
- [Tools cache setup for Ubuntu](https://github.com/actions/virtual-environments/blob/main/images/linux/scripts/installers/hosted-tool-cache.sh)
- [Tools cache setup for Windows](https://github.com/actions/virtual-environments/blob/main/images/win/scripts/Installers/Download-ToolCache.ps1)
- Tools cache setup for Ubuntu: [Install-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/linux/scripts/installers/Install-Toolset.ps1) [Configure-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/linux/scripts/installers/Configure-Toolset.ps1)
- Tools cache setup for Windows: [Install-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/win/scripts/Installers/Install-Toolset.ps1) [Configure-Toolset.ps1](https://github.com/actions/virtual-environments/blob/main/images/win/scripts/Installers/Configure-Toolset.ps1)
# Specifying a Python version
@ -194,27 +244,30 @@ You should specify only a major and minor version if you are okay with the most
- Using the most recent patch version will result in a very quick setup since no downloads will be required since a locally installed version Python on the runner will be used.
# Specifying a PyPy version
The version of PyPy should be specified in the format `pypy-<python_version>[-v<pypy_version>]`.
The version of PyPy should be specified in the format `pypy<python_version>[-v<pypy_version>]` or `pypy-<python_version>[-v<pypy_version>]`.
The `<pypy_version>` parameter is optional and can be skipped. The latest version will be used in this case.
```
pypy-3.6 # the latest available version of PyPy that supports Python 3.6
pypy-3.7 # the latest available version of PyPy that supports Python 3.7
pypy-2.7 # the latest available version of PyPy that supports Python 2.7
pypy-3.7-v7.3.3 # Python 3.7 and PyPy 7.3.3
pypy-3.7-v7.x # Python 3.7 and the latest available PyPy 7.x
pypy-3.7-v7.3.3rc1 # Python 3.7 and preview version of PyPy
pypy-3.7-nightly # Python 3.7 and nightly PyPy
pypy3.7 or pypy-3.7 # the latest available version of PyPy that supports Python 3.7
pypy3.8 or pypy-3.8 # the latest available version of PyPy that supports Python 3.8
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.x or pypy-3.7-v7.x # Python 3.7 and the latest available PyPy 7.x
pypy3.7-v7.3.3rc1 or pypy-3.7-v7.3.3rc1 # Python 3.7 and preview version of PyPy
pypy3.7-nightly or pypy-3.7-nightly # Python 3.7 and nightly PyPy
```
Note: `pypy2` and `pypy3` have been removed in v3. Use the format above instead.
# Caching packages dependencies
The action has built-in functionality for caching and restoring dependencies. It uses [actions/cache](https://github.com/actions/toolkit/tree/main/packages/cache) under the hood for caching dependencies but requires less configuration settings. Supported package managers are `pip` and `pipenv`. The `cache` input is optional, and caching is turned off by default.
The action has built-in functionality for caching and restoring dependencies. It uses [actions/cache](https://github.com/actions/toolkit/tree/main/packages/cache) under the hood for caching dependencies but requires less configuration settings. Supported package managers are `pip`, `pipenv` and `poetry`. The `cache` input is optional, and caching is turned off by default.
The action defaults to searching for a dependency file (`requirements.txt` for pip or `Pipfile.lock` for pipenv) in the repository, and uses its hash as a part of the cache key. Use `cache-dependency-path` for cases where multiple dependency files are used, they are located in different subdirectories or different files for the hash want to be used.
The action defaults to searching for a dependency file (`requirements.txt` for pip, `Pipfile.lock` for pipenv or `poetry.lock` for poetry) in the repository, and uses its hash as a part of the cache key. Use `cache-dependency-path` for cases where multiple dependency files are used, they are located in different subdirectories or different files for the hash want to be used.
- For pip, the action will cache global cache directory
- For pipenv, the action will cache virtualenv directory
- For poetry, the action will cache virtualenv directory
**Please Note:** Restored cache will not be used if the requirements.txt file is not updated for a long time and a newer version of the dependency is available that can lead to an increase in total build time.
@ -224,59 +277,104 @@ The requirements file format allows to specify dependency versions using logical
```yaml
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.9'
cache: 'pip'
- run: pip install -r requirements.txt
- run: pip test
```
**Caching pipenv dependencies:**
```yaml
steps:
- uses: actions/checkout@v2
- name: Install pipenv
run: pipx install pipenv
- uses: actions/setup-python@v2
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.9'
cache: 'pipenv'
- name: Install pipenv
run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python
- run: pipenv install
- run: pipenv test
```
**Caching poetry dependencies:**
```yaml
steps:
- uses: actions/checkout@v3
- name: Install poetry
run: pipx install poetry
- uses: actions/setup-python@v4
with:
python-version: '3.9'
cache: 'poetry'
- run: poetry install
- run: poetry run pytest
```
**Using wildcard patterns to cache dependencies**
```yaml
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.9'
cache: 'pip'
cache-dependency-path: '**/requirements-dev.txt'
- run: pip install -r subdirectory/requirements-dev.txt
- run: pip test
```
**Using a list of file paths to cache dependencies**
```yaml
steps:
- uses: actions/checkout@v2
- name: Install pipenv
run: pipx install pipenv
- uses: actions/setup-python@v2
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.9'
cache: 'pipenv'
cache-dependency-path: |
server/app/Pipfile.lock
__test__/app/Pipfile.lock
- name: Install pipenv
run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python
- run: pipenv install
- run: pipenv test
```
**Using a list of wildcard patterns to cache dependencies**
```yaml
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.10'
cache: 'pip'
cache-dependency-path: |
**/setup.cfg
**/requirements*.txt
- run: pip install -e . -r subdirectory/requirements-dev.txt
```
# Environment variables
The `update-environment` flag defaults to `true`.
With this setting, the action will add/update environment variables (e.g. `PATH`, `PKG_CONFIG_PATH`, `pythonLocation`) for `python` to just work out of the box.
If `update-environment` is set to `false`, the action will not add/update environment variables.
This can prove useful if you want the only side-effect to be to ensure python is installed and rely on the `python-path` output to run python.
Such a requirement on side-effect could be because you don't want your composite action messing with your user's workflows.
```yaml
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
id: cp310
with:
python-version: '3.10'
update-environment: false
- run: ${{ steps.cp310.outputs.python-path }} my_script.py
```
# Using `setup-python` with a self hosted runner
Python distributions are only available for the same [environments](https://github.com/actions/virtual-environments#available-environments) that GitHub Actions hosted environments are available for. If you are using an unsupported version of Ubuntu such as `19.04` or another Linux distribution such as Fedora, `setup-python` will not work. If you have a supported self-hosted runner and you would like to use `setup-python`, there are a few extra things you need to make sure are set up so that new versions of Python can be downloaded and configured on your runner.
@ -294,7 +392,7 @@ If you are experiencing problems while configuring Python on your self-hosted ru
### Linux
- The Python packages that are downloaded from `actions/python-versions` are originally compiled from source in `/opt/hostedtoolcache/` with the [--enable-shared](https://github.com/actions/python-versions/blob/94f04ae6806c6633c82db94c6406a16e17decd5c/builders/ubuntu-python-builder.psm1#L35) flag, which makes them non-relocatable.
- Create an environment variable called `AGENT_TOOLSDIRECTORY` and set it to `/opt/hostedtoolcache`. This controls where the runner downloads and installs tools.
- By default runner downloads and install the tools to `/opt/hostedtoolcache`. The environment variable called `AGENT_TOOLSDIRECTORY` can be set to change this location.
- In the same shell that your runner is using, type `export AGENT_TOOLSDIRECTORY=/opt/hostedtoolcache`.
- A more permanent way of setting the environment variable is to create a `.env` file in the same directory as your runner and to add `AGENT_TOOLSDIRECTORY=/opt/hostedtoolcache`. This ensures the variable is always set if your runner is configured as a service.
- Create a directory called `hostedtoolcache` inside `/opt`.
@ -304,7 +402,7 @@ If you are experiencing problems while configuring Python on your self-hosted ru
- The user starting the runner is in the owning group, and the owning group has write permission.
- All users have write permission.
- One quick way to grant access is to change the user and group of `/opt/hostedtoolcache` to be the same as the runners using `chown`.
- `sudo chown runner-user:runner-group opt/hostedtoolcache/`.
- `sudo chown runner-user:runner-group /opt/hostedtoolcache/`.
- If your runner is configured as a service and you run into problems, make sure the user that the service is running as is correct. For more information, you can [check the status of your self-hosted runner](https://help.github.com/en/actions/hosting-your-own-runners/configuring-the-self-hosted-runner-application-as-a-service#checking-the-status-of-the-service).
### Mac

View File

@ -5,11 +5,21 @@ import {getCacheDistributor} from '../src/cache-distributions/cache-factory';
describe('restore-cache', () => {
const pipFileLockHash =
'67d817abcde9c72da0ed5b8f235647cb14638b9ff9d742b42e4406d2eb16fe3c';
'a3bdcc71289e4979ca9e051810d81999cc99823109faf6912e17ff14c8e621a6';
const requirementsHash =
'd8110e0006d7fb5ee76365d565eef9d37df1d11598b912d3eb66d398d57a1121';
const requirementsLinuxHash =
'2d0ff7f46b0e120e3d3294db65768b474934242637b9899b873e6283dfd16d7c';
const poetryLockHash =
'571bf984f8d210e6a97f854e479fdd4a2b5af67b5fdac109ec337a0ea16e7836';
const poetryConfigOutput = `
cache-dir = "/Users/patrick/Library/Caches/pypoetry"
experimental.new-installer = false
installer.parallel = true
virtualenvs.create = true
virtualenvs.in-project = true
virtualenvs.path = "{cache-dir}/virtualenvs" # /Users/patrick/Library/Caches/pypoetry/virtualenvs
`;
// core spy
let infoSpy: jest.SpyInstance;
@ -17,6 +27,7 @@ describe('restore-cache', () => {
let debugSpy: jest.SpyInstance;
let saveSatetSpy: jest.SpyInstance;
let getStateSpy: jest.SpyInstance;
let setOutputSpy: jest.SpyInstance;
// cache spy
let restoreCacheSpy: jest.SpyInstance;
@ -47,10 +58,16 @@ describe('restore-cache', () => {
if (input.includes('pip')) {
return {stdout: 'pip', stderr: '', exitCode: 0};
}
if (input.includes('poetry')) {
return {stdout: poetryConfigOutput, stderr: '', exitCode: 0};
}
return {stdout: '', stderr: 'Error occured', exitCode: 2};
});
setOutputSpy = jest.spyOn(core, 'setOutput');
setOutputSpy.mockImplementation(input => undefined);
restoreCacheSpy = jest.spyOn(cache, 'restoreCache');
restoreCacheSpy.mockImplementation(
(cachePaths: string[], primaryKey: string, restoreKey?: string) => {
@ -82,25 +99,23 @@ describe('restore-cache', () => {
],
['pip', '3.8.12', '__tests__/data/requirements.txt', requirementsHash],
['pipenv', '3.9.1', undefined, pipFileLockHash],
['pipenv', '3.9.12', '__tests__/data/requirements.txt', requirementsHash]
['pipenv', '3.9.12', '__tests__/data/requirements.txt', requirementsHash],
['poetry', '3.9.1', undefined, poetryLockHash]
])(
'restored dependencies for %s by primaryKey',
async (packageManager, pythonVersion, dependencyFile, fileHash) => {
const cacheDistributor = await getCacheDistributor(
const cacheDistributor = getCacheDistributor(
packageManager,
pythonVersion,
dependencyFile
);
await cacheDistributor.restoreCache();
let pythonKey = '';
if (packageManager === 'pipenv') {
pythonKey = `python-${pythonVersion}-`;
}
expect(infoSpy).toHaveBeenCalledWith(
`Cache restored from key: setup-python-${process.env['RUNNER_OS']}-${pythonKey}${packageManager}-${fileHash}`
`Cache restored from key: setup-python-${process.env['RUNNER_OS']}-python-${pythonVersion}-${packageManager}-${fileHash}`
);
}
},
30000
);
it.each([
@ -115,7 +130,7 @@ describe('restore-cache', () => {
dependencyFile,
cacheDependencyPath
) => {
const cacheDistributor = await getCacheDistributor(
const cacheDistributor = getCacheDistributor(
packageManager,
pythonVersion,
dependencyFile
@ -141,7 +156,8 @@ describe('restore-cache', () => {
],
['pip', '3.8.12', '__tests__/data/requirements.txt', pipFileLockHash],
['pipenv', '3.9.1', undefined, requirementsHash],
['pipenv', '3.9.12', '__tests__/data/requirements.txt', requirementsHash]
['pipenv', '3.9.12', '__tests__/data/requirements.txt', requirementsHash],
['poetry', '3.9.1', undefined, requirementsHash]
])(
'restored dependencies for %s by primaryKey',
async (packageManager, pythonVersion, dependencyFile, fileHash) => {
@ -150,17 +166,24 @@ describe('restore-cache', () => {
return primaryKey !== fileHash && restoreKey ? pipFileLockHash : '';
}
);
const cacheDistributor = await getCacheDistributor(
const cacheDistributor = getCacheDistributor(
packageManager,
pythonVersion,
dependencyFile
);
await cacheDistributor.restoreCache();
let result = '';
if (packageManager !== 'pipenv') {
result = `Cache restored from key: ${fileHash}`;
} else {
result = 'pipenv cache is not found';
switch (packageManager) {
case 'pip':
result = `Cache restored from key: ${fileHash}`;
break;
case 'pipenv':
result = 'pipenv cache is not found';
break;
case 'poetry':
result = 'poetry cache is not found';
break;
}
expect(infoSpy).toHaveBeenCalledWith(result);
@ -168,6 +191,38 @@ describe('restore-cache', () => {
);
});
describe('Check if handleMatchResult', () => {
it.each([
['pip', '3.8.12', 'requirements.txt', 'someKey', 'someKey', true],
['pipenv', '3.9.1', 'requirements.txt', 'someKey', 'someKey', true],
['poetry', '3.8.12', 'requirements.txt', 'someKey', 'someKey', true],
['pip', '3.9.2', 'requirements.txt', undefined, 'someKey', false],
['pipenv', '3.8.12', 'requirements.txt', undefined, 'someKey', false],
['poetry', '3.9.12', 'requirements.txt', undefined, 'someKey', false]
])(
'sets correct outputs',
async (
packageManager,
pythonVersion,
dependencyFile,
matchedKey,
restoredKey,
expectedOutputValue
) => {
const cacheDistributor = getCacheDistributor(
packageManager,
pythonVersion,
dependencyFile
);
cacheDistributor.handleMatchResult(matchedKey, restoredKey);
expect(setOutputSpy).toHaveBeenCalledWith(
'cache-hit',
expectedOutputValue
);
}
);
});
afterEach(() => {
jest.resetAllMocks();
jest.clearAllMocks();

View File

@ -6,11 +6,13 @@ import {State} from '../src/cache-distributions/cache-distributor';
describe('run', () => {
const pipFileLockHash =
'67d817abcde9c72da0ed5b8f235647cb14638b9ff9d742b42e4406d2eb16fe3c';
'd1dd6218299d8a6db5fc2001d988b34a8b31f1e9d0bb4534d377dde7c19f64b3';
const requirementsHash =
'd8110e0006d7fb5ee76365d565eef9d37df1d11598b912d3eb66d398d57a1121';
const requirementsLinuxHash =
'2d0ff7f46b0e120e3d3294db65768b474934242637b9899b873e6283dfd16d7c';
const poetryLockHash =
'571bf984f8d210e6a97f854e479fdd4a2b5af67b5fdac109ec337a0ea16e7836';
// core spy
let infoSpy: jest.SpyInstance;
@ -114,6 +116,22 @@ describe('run', () => {
);
expect(setFailedSpy).not.toHaveBeenCalled();
});
it('should not save cache for pipenv', async () => {
inputs['cache'] = 'pipenv';
await run();
expect(getInputSpy).toHaveBeenCalled();
expect(debugSpy).toHaveBeenCalledWith(
`paths for caching are ${__dirname}`
);
expect(getStateSpy).toHaveBeenCalledTimes(3);
expect(infoSpy).toHaveBeenCalledWith(
`Cache hit occurred on the primary key ${requirementsHash}, not saving cache.`
);
expect(setFailedSpy).not.toHaveBeenCalled();
});
});
describe('action saves the cache', () => {
@ -168,6 +186,85 @@ describe('run', () => {
);
expect(setFailedSpy).not.toHaveBeenCalled();
});
it('saves cache from poetry', async () => {
inputs['cache'] = 'poetry';
getStateSpy.mockImplementation((name: string) => {
if (name === State.CACHE_MATCHED_KEY) {
return poetryLockHash;
} else if (name === State.CACHE_PATHS) {
return JSON.stringify([__dirname]);
} else {
return requirementsHash;
}
});
await run();
expect(getInputSpy).toHaveBeenCalled();
expect(getStateSpy).toHaveBeenCalledTimes(3);
expect(infoSpy).not.toHaveBeenCalledWith(
`Cache hit occurred on the primary key ${poetryLockHash}, not saving cache.`
);
expect(saveCacheSpy).toHaveBeenCalled();
expect(infoSpy).toHaveBeenLastCalledWith(
`Cache saved with the key: ${requirementsHash}`
);
expect(setFailedSpy).not.toHaveBeenCalled();
});
it('saves with -1 cacheId , should not fail workflow', async () => {
inputs['cache'] = 'poetry';
getStateSpy.mockImplementation((name: string) => {
if (name === State.STATE_CACHE_PRIMARY_KEY) {
return poetryLockHash;
} else if (name === State.CACHE_PATHS) {
return JSON.stringify([__dirname]);
} else {
return requirementsHash;
}
});
saveCacheSpy.mockImplementation(() => {
return -1;
});
await run();
expect(getInputSpy).toHaveBeenCalled();
expect(getStateSpy).toHaveBeenCalledTimes(3);
expect(infoSpy).not.toHaveBeenCalled();
expect(saveCacheSpy).toHaveBeenCalled();
expect(infoSpy).not.toHaveBeenLastCalledWith(
`Cache saved with the key: ${poetryLockHash}`
);
expect(setFailedSpy).not.toHaveBeenCalled();
});
it('saves with error from toolkit, should fail workflow', async () => {
inputs['cache'] = 'npm';
getStateSpy.mockImplementation((name: string) => {
if (name === State.STATE_CACHE_PRIMARY_KEY) {
return poetryLockHash;
} else if (name === State.CACHE_PATHS) {
return JSON.stringify([__dirname]);
} else {
return requirementsHash;
}
});
saveCacheSpy.mockImplementation(() => {
throw new cache.ValidationError('Validation failed');
});
await run();
expect(getInputSpy).toHaveBeenCalled();
expect(getStateSpy).toHaveBeenCalledTimes(3);
expect(infoSpy).not.toHaveBeenCalledWith();
expect(saveCacheSpy).toHaveBeenCalled();
expect(setFailedSpy).toHaveBeenCalled();
});
});
afterEach(() => {

14
__tests__/check-python-path.sh Executable file
View File

@ -0,0 +1,14 @@
#!/bin/bash
set -euo pipefail
PYTHON_PATH="$1"
PATH_EXECUTABLE=$(python -c 'import sys; print(sys.executable)')
PYTHON_PATH_EXECUTABLE=$("${PYTHON_PATH}" -c 'import sys; print(sys.executable)')
if [ "${PATH_EXECUTABLE}" != "${PYTHON_PATH_EXECUTABLE}" ]; then
echo "Executable mismatch."
echo "python in PATH is: ${PATH_EXECUTABLE}"
echo "python-path (${PYTHON_PATH}) is: ${PYTHON_PATH_EXECUTABLE}"
exit 1
fi
echo "python-path: ${PYTHON_PATH}"

13
__tests__/data/Pipfile Normal file
View File

@ -0,0 +1,13 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
flake8 = "==4.0.1"
numpy = "==1.23.0"
[dev-packages]
[requires]
python_version = "*"

View File

@ -1,11 +1,11 @@
{
"_meta": {
"hash": {
"sha256": "408f110354c997d8df1e17841d5335ae690f5b25f8c78040d62257f9535c6005"
"sha256": "e9c37110984955621040e2dc8548c026eb8466c23db1b8e69430289b10be8938"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.7"
"python_version": "*"
},
"sources": [
{
@ -16,260 +16,64 @@
]
},
"default": {
"altgraph": {
"flake8": {
"hashes": [
"sha256:743628f2ac6a7c26f5d9223c91ed8ecbba535f506f4b6f558885a8a56a105857",
"sha256:ebf2269361b47d97b3b88e696439f6e4cbc607c17c51feb1754f90fb79839158"
],
"version": "==0.17.2"
},
"certifi": {
"hashes": [
"sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3",
"sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41"
"sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d",
"sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"
],
"index": "pypi",
"version": "==2020.6.20"
"version": "==4.0.1"
},
"chardet": {
"mccabe": {
"hashes": [
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
"sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
],
"version": "==0.6.1"
},
"numpy": {
"hashes": [
"sha256:092f5e6025813e64ad6d1b52b519165d08c730d099c114a9247c9bb635a2a450",
"sha256:196cd074c3f97c4121601790955f915187736f9cf458d3ee1f1b46aff2b1ade0",
"sha256:1c29b44905af288b3919803aceb6ec7fec77406d8b08aaa2e8b9e63d0fe2f160",
"sha256:2b2da66582f3a69c8ce25ed7921dcd8010d05e59ac8d89d126a299be60421171",
"sha256:5043bcd71fcc458dfb8a0fc5509bbc979da0131b9d08e3d5f50fb0bbb36f169a",
"sha256:58bfd40eb478f54ff7a5710dd61c8097e169bc36cc68333d00a9bcd8def53b38",
"sha256:79a506cacf2be3a74ead5467aee97b81fca00c9c4c8b3ba16dbab488cd99ba10",
"sha256:94b170b4fa0168cd6be4becf37cb5b127bd12a795123984385b8cd4aca9857e5",
"sha256:97a76604d9b0e79f59baeca16593c711fddb44936e40310f78bfef79ee9a835f",
"sha256:98e8e0d8d69ff4d3fa63e6c61e8cfe2d03c29b16b58dbef1f9baa175bbed7860",
"sha256:ac86f407873b952679f5f9e6c0612687e51547af0e14ddea1eedfcb22466babd",
"sha256:ae8adff4172692ce56233db04b7ce5792186f179c415c37d539c25de7298d25d",
"sha256:bd3fa4fe2e38533d5336e1272fc4e765cabbbde144309ccee8675509d5cd7b05",
"sha256:d0d2094e8f4d760500394d77b383a1b06d3663e8892cdf5df3c592f55f3bff66",
"sha256:d54b3b828d618a19779a84c3ad952e96e2c2311b16384e973e671aa5be1f6187",
"sha256:d6ca8dabe696c2785d0c8c9b0d8a9b6e5fdbe4f922bde70d57fa1a2848134f95",
"sha256:d8cc87bed09de55477dba9da370c1679bd534df9baa171dd01accbb09687dac3",
"sha256:f0f18804df7370571fb65db9b98bf1378172bd4e962482b857e612d1fec0f53e",
"sha256:f1d88ef79e0a7fa631bb2c3dda1ea46b32b1fe614e10fedd611d3d5398447f2f",
"sha256:f9c3fc2adf67762c9fe1849c859942d23f8d3e0bee7b5ed3d4a9c3eeb50a2f07",
"sha256:fc431493df245f3c627c0c05c2bd134535e7929dbe2e602b80e42bf52ff760bc",
"sha256:fe8b9683eb26d2c4d5db32cd29b38fdcf8381324ab48313b5b69088e0e355379"
],
"index": "pypi",
"version": "==3.0.4"
"version": "==1.23.0"
},
"docutils": {
"pycodestyle": {
"hashes": [
"sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af",
"sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc"
"sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20",
"sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"
],
"index": "pypi",
"version": "==0.16"
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==2.8.0"
},
"future": {
"pyflakes": {
"hashes": [
"sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"
"sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c",
"sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2'",
"version": "==0.18.2"
},
"idna": {
"hashes": [
"sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb",
"sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"
],
"index": "pypi",
"version": "==2.9"
},
"itsdangerous": {
"hashes": [
"sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19",
"sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"
],
"index": "pypi",
"version": "==1.1.0"
},
"kivy": {
"hashes": [
"sha256:090d3ded9835a17477cd93fbdaf0a7c42ff2218981cf198ded5ad8795bc74391",
"sha256:11e85eaf6efbfa2362a3334ffdad179a1b0ca8d255cca79eaa6a2765560d4982",
"sha256:1a1ff32f8a95f1e175198cbab81fcd2596783b180d4eafe63e87d171aa7fdb5e",
"sha256:1d28b198a64c30db8d94a0488e85f3037af60d514ab0d7ad5ab45add3ab77090",
"sha256:4a5480cbf837d3780c77a4f61b32b56d22ae9f03845e7a89dd3eaef1ae5fd037",
"sha256:4d0e596f74271e901b551f77661dde238df4765484fce9f5d1c72e8022984e84",
"sha256:5c3d0f2749522d62e9cce09cd54b2d823bf1b6b644ff1f627be49de6f3e3cba0",
"sha256:815a5c0b3b72fcd81ca7b2aa0744087163ed03e4cf9ab4e7c9733cea99fc1571",
"sha256:8819a27a09871af451760cb69486ced52e830c8a0a37480f22ef5e692f12c05b",
"sha256:a687602d90c4629dd036f577ca39acb76ba581370f9d915f3cab99be818ba8ad",
"sha256:b7ef6aad43a86d8df3fb865db864e354f2155a748019f8517f69f65c1a29cb64",
"sha256:b85ccf165050cbf2ee8447671eebbc222b369b40f0e0038dd9547d49a5e37373",
"sha256:c36652caa7f6c327dee834cfc699d5962d346b7a53e54bd81abc17c314226d89",
"sha256:ece170514db3f49844a41e4c910ad9ce9bc46da6f47a49158e11266bdcc6e479",
"sha256:f3bea6e4a21991827885d04127fc6d09a0e974ecfa12da7bf5faae93562ea102",
"sha256:f835462dd9aa491272552ef079b948a088598e2e95d68bb1d885d2c3f3d4e2c3"
],
"index": "pypi",
"version": "==1.11.1"
},
"kivy-deps-angle": {
"hashes": [
"sha256:50605fdd4c9fdbe9f717069734a598a9aba0afe5d3f0412afbe2ecff0326e92d",
"sha256:64ac7f33c000585dc30194e604aed925972c6b7c3848b5c3b073ae916fb0b55c",
"sha256:99c40d53582a958748e251dfbd61aa67fb85963e27529ca08a21f2f5eeed04e1",
"sha256:a2cea09e8a5e899629466403fbd540459f1cdef8d08c6c479b6607b95309be02",
"sha256:b167e19b3eea55a9a8c606a607bb909ec1bedda88deee40347c780b310155a79",
"sha256:b9d07976b0bf6bac724a42aa8ed5a8c7caa95609046db30c8f15bb731f8e4d36",
"sha256:bb4d53f15a093214adbbe205c108ede5cc0f6af6eff104c1b8c468ddaaf6400a",
"sha256:d0e7b7b9eb9669837a5d70808a7ea45f2b61961b56f9f69a233bad6bd36ce260"
],
"index": "pypi",
"version": "==0.3.0"
},
"kivy-deps.glew": {
"hashes": [
"sha256:09f72ee5ef33ff273332e2a229dc97d650d29818a0189339421949e4e0f63d93",
"sha256:1e28e40017af9d081fc0fc95b4fadaf31d15e9f63478dcee1c4257d67079894e",
"sha256:45aa7f0e8d9bcf5fc1810c9c38bc20edf7dee61df81ecf62102e0f84153f924a",
"sha256:6bb435620c3187d2c61054adb9ec277ed487256b457a0a7b1491bc0cb7247e18",
"sha256:92e72fa2c425887987d1aa861c99537033dc20d68ae1c54864871f0401682586",
"sha256:ab81783a82bef88a8d2bcf8a93bc21df6b8b0db6ee551eb802727d18f9074b17",
"sha256:c843104690c0c8f3a58105c53c57f31506f6f90562c18de00bd19317cc1045a7",
"sha256:cf351aad171796f8051af8e49ec430a9aa128d8557d8643e73f2bb1e5f9c2dab",
"sha256:ee8ab67abb2c98d84feede657cae472e7723e529af07394244bdd33caafb1a38",
"sha256:ef1116d99bd9cc737cb8c0e13e676955c17d6e4d6d1af5cfccef089a430071bb"
],
"index": "pypi",
"version": "==0.1.12"
},
"kivy-deps.gstreamer": {
"hashes": [
"sha256:0d9598d2d31c0e780adf4b767fa3a691123621fd0ffef94b83cf82c2da84341b",
"sha256:309eca64dee5939f16f8465e5cbb08bdde7c90ded1af6a00690c7e928326af79",
"sha256:3d53d2c84c0a997c4cac6c239b1e0a6486e533836321003dc365ec42b97a664b",
"sha256:4d996377111e854b3dea90846f9b2f98766a44529fd8b72125e18c552381d928",
"sha256:4f2ddd61d185310258d338ae80a646df7822efdd7d67e57f49dc7b87555c5d7e",
"sha256:6fa9f76afe600baa221abee31ce7dc63e653d0affe0f6c558bfc4f35af96396f",
"sha256:739cd331b9f33a822d700273674a79a3157054e9358a01a0d553f094a5f4a8c9",
"sha256:c29cfc63fe70a58dad889e631f1ba4711c9ea80103f2b2b8d670a97f093076c8",
"sha256:c4709765e2b17c6c96b46a92207b0457def147544d825654077603eaf0d424de"
],
"index": "pypi",
"version": "==0.1.17"
},
"kivy-deps.sdl2": {
"hashes": [
"sha256:053f26e8c05d5545bdbc7eeb8c450b8e4410ee355792e9345af536110fe247e2",
"sha256:1b987bdd4fbbcb31baf0d7fc9584ad99912179b8968311bb7e30fbeb14e98e0d",
"sha256:228128cdd8112dc7505ac43027a770476e9ef282e0b84ca68037133cd025960b",
"sha256:2c2fd5a12a7a9afe3bb962b273561099a180edae91bb9c8f8386b72253fcae4a",
"sha256:5ce23f1a3286d6288751a12b0eaefd02f947ea101bb807e9781b964e496fc3f3",
"sha256:7928746eaed51944c10d1bb36fcefebe3d1aff1b97ba32359c2c97ba74707e1b",
"sha256:9270fa8ed5130074b167a7a3a9c85efc3cfe3c04584ab084cb6ae9e4edfa8168",
"sha256:92ed97d3247bc8ce98f336cbc940bb889310199326e9ccf251c49ae7e4b80de8",
"sha256:96e1fa89fd8b5351f2d3c26bbffd50df8d554b03fba4025ecc941d773d241698",
"sha256:c3ace0ddde0e59cdcaf260eda1daa0c05ca9bf8cd0c4ea404539de25a5dcaec7"
],
"index": "pypi",
"version": "==0.1.22"
},
"kivy-garden": {
"hashes": [
"sha256:9b7d9de5efacbcd0c4b3dd873b30622a86093c9965aa47b523c7a32f3eb34610",
"sha256:c256f42788421273a08fbb0a228f0fb0e80dd86b629fb8c0920507f645be6c72"
],
"index": "pypi",
"version": "==0.1.4"
},
"packaging": {
"hashes": [
"sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7",
"sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"
],
"index": "pypi",
"version": "==21.0"
},
"pdf2image": {
"hashes": [
"sha256:a0d9906f5507192210a8d5d7ead63145e9dec4bccc4564b1fb644e923913c31c"
],
"index": "pypi",
"version": "==1.12.1"
},
"pefile": {
"hashes": [
"sha256:344a49e40a94e10849f0fe34dddc80f773a12b40675bf2f7be4b8be578bdd94a"
],
"markers": "python_full_version >= '3.6.0'",
"version": "==2021.9.3"
},
"pillow": {
"hashes": [
"sha256:0295442429645fa16d05bd567ef5cff178482439c9aad0411d3f0ce9b88b3a6f",
"sha256:06aba4169e78c439d528fdeb34762c3b61a70813527a2c57f0540541e9f433a8",
"sha256:09d7f9e64289cb40c2c8d7ad674b2ed6105f55dc3b09aa8e4918e20a0311e7ad",
"sha256:0a80dd307a5d8440b0a08bd7b81617e04d870e40a3e46a32d9c246e54705e86f",
"sha256:1ca594126d3c4def54babee699c055a913efb01e106c309fa6b04405d474d5ae",
"sha256:25930fadde8019f374400f7986e8404c8b781ce519da27792cbe46eabec00c4d",
"sha256:431b15cffbf949e89df2f7b48528be18b78bfa5177cb3036284a5508159492b5",
"sha256:52125833b070791fcb5710fabc640fc1df07d087fc0c0f02d3661f76c23c5b8b",
"sha256:5e51ee2b8114def244384eda1c82b10e307ad9778dac5c83fb0943775a653cd8",
"sha256:612cfda94e9c8346f239bf1a4b082fdd5c8143cf82d685ba2dba76e7adeeb233",
"sha256:6d7741e65835716ceea0fd13a7d0192961212fd59e741a46bbed7a473c634ed6",
"sha256:6edb5446f44d901e8683ffb25ebdfc26988ee813da3bf91e12252b57ac163727",
"sha256:725aa6cfc66ce2857d585f06e9519a1cc0ef6d13f186ff3447ab6dff0a09bc7f",
"sha256:8dad18b69f710bf3a001d2bf3afab7c432785d94fcf819c16b5207b1cfd17d38",
"sha256:94cf49723928eb6070a892cb39d6c156f7b5a2db4e8971cb958f7b6b104fb4c4",
"sha256:97f9e7953a77d5a70f49b9a48da7776dc51e9b738151b22dacf101641594a626",
"sha256:9ad7f865eebde135d526bb3163d0b23ffff365cf87e767c649550964ad72785d",
"sha256:9c87ef410a58dd54b92424ffd7e28fd2ec65d2f7fc02b76f5e9b2067e355ebf6",
"sha256:a060cf8aa332052df2158e5a119303965be92c3da6f2d93b6878f0ebca80b2f6",
"sha256:c79f9c5fb846285f943aafeafda3358992d64f0ef58566e23484132ecd8d7d63",
"sha256:c92302a33138409e8f1ad16731568c55c9053eee71bb05b6b744067e1b62380f",
"sha256:d08b23fdb388c0715990cbc06866db554e1822c4bdcf6d4166cf30ac82df8c41",
"sha256:d350f0f2c2421e65fbc62690f26b59b0bcda1b614beb318c81e38647e0f673a1",
"sha256:e901964262a56d9ea3c2693df68bc9860b8bdda2b04768821e4c44ae797de117",
"sha256:ec29604081f10f16a7aea809ad42e27764188fc258b02259a03a8ff7ded3808d",
"sha256:edf31f1150778abd4322444c393ab9c7bd2af271dd4dafb4208fb613b1f3cdc9",
"sha256:f7e30c27477dffc3e85c2463b3e649f751789e0f6c8456099eea7ddd53be4a8a",
"sha256:ffe538682dc19cc542ae7c3e504fdf54ca7f86fb8a135e59dd6bc8627eae6cce"
],
"index": "pypi",
"version": "==7.2"
},
"pygments": {
"hashes": [
"sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44",
"sha256:ff7a40b4860b727ab48fad6360eb351cc1b33cbf9b15a0f689ca5353e9463324"
],
"index": "pypi",
"version": "==2.6.1"
},
"pyinstaller": {
"hashes": [
"sha256:3730fa80d088f8bb7084d32480eb87cbb4ddb64123363763cf8f2a1378c1c4b7"
],
"index": "pypi",
"version": "==3.6"
},
"pyparsing": {
"hashes": [
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2'",
"version": "==2.4.7"
},
"pywin32-ctypes": {
"hashes": [
"sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942",
"sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"
],
"version": "==0.2.0"
},
"requests": {
"hashes": [
"sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b",
"sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"
],
"index": "pypi",
"version": "==2.24.0"
},
"urllib3": {
"hashes": [
"sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527",
"sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"
],
"index": "pypi",
"version": "==1.25.9"
},
"xlrd": {
"hashes": [
"sha256:546eb36cee8db40c3eaa46c351e67ffee6eeb5fa2650b71bc4c758a29a1b29b2",
"sha256:e551fb498759fa3a5384a94ccd4c3c02eb7c00ea424426e212ac0c57be9dfbde"
],
"index": "pypi",
"version": "==1.2.0"
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.4.0"
}
},
"develop": {}

View File

@ -0,0 +1,2 @@
numpy==1.22.3
pandas==1.4.2

413
__tests__/data/poetry.lock generated Normal file
View File

@ -0,0 +1,413 @@
[[package]]
name = "altgraph"
version = "0.17.2"
description = "Python graph (network) package"
category = "main"
optional = false
python-versions = "*"
[[package]]
name = "certifi"
version = "2020.6.20"
description = "Python package for providing Mozilla's CA Bundle."
category = "main"
optional = false
python-versions = "*"
[[package]]
name = "chardet"
version = "3.0.4"
description = "Universal encoding detector for Python 2 and 3"
category = "main"
optional = false
python-versions = "*"
[[package]]
name = "dis3"
version = "0.1.3"
description = "Python 2.7 backport of the \"dis\" module from Python 3.5+"
category = "main"
optional = false
python-versions = "*"
[[package]]
name = "docutils"
version = "0.16"
description = "Docutils -- Python Documentation Utilities"
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
name = "future"
version = "0.18.2"
description = "Clean single-source support for Python 3 and 2"
category = "main"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]]
name = "idna"
version = "2.9"
description = "Internationalized Domain Names in Applications (IDNA)"
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]]
name = "itsdangerous"
version = "1.1.0"
description = "Various helpers to pass data to untrusted environments and back."
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]]
name = "kivy"
version = "1.11.1"
description = "A software library for rapid development of hardware-accelerated multitouch applications."
category = "main"
optional = false
python-versions = "*"
[package.dependencies]
docutils = "*"
Kivy-Garden = ">=0.1.4"
pygments = "*"
[package.extras]
tuio = ["oscpy"]
[[package]]
name = "kivy-deps.angle"
version = "0.3.0"
description = "Repackaged binary dependency of Kivy."
category = "main"
optional = false
python-versions = "*"
[[package]]
name = "kivy-deps.glew"
version = "0.1.12"
description = "Repackaged binary dependency of Kivy."
category = "main"
optional = false
python-versions = "*"
[[package]]
name = "kivy-deps.gstreamer"
version = "0.1.17"
description = "Repackaged binary dependency of Kivy."
category = "main"
optional = false
python-versions = "*"
[[package]]
name = "kivy-deps.sdl2"
version = "0.1.22"
description = "Repackaged binary dependency of Kivy."
category = "main"
optional = false
python-versions = "*"
[[package]]
name = "kivy-garden"
version = "0.1.4"
description = "Garden tool for kivy flowers."
category = "main"
optional = false
python-versions = "*"
[package.dependencies]
requests = "*"
[[package]]
name = "packaging"
version = "21.0"
description = "Core utilities for Python packages"
category = "main"
optional = false
python-versions = ">=3.6"
[package.dependencies]
pyparsing = ">=2.0.2"
[[package]]
name = "pdf2image"
version = "1.12.1"
description = "A wrapper around the pdftoppm and pdftocairo command line tools to convert PDF to a PIL Image list."
category = "main"
optional = false
python-versions = "*"
[package.dependencies]
pillow = "*"
[[package]]
name = "pefile"
version = "2021.9.3"
description = "Python PE parsing module"
category = "main"
optional = false
python-versions = ">=3.6.0"
[package.dependencies]
future = "*"
[[package]]
name = "pillow"
version = "7.2.0"
description = "Python Imaging Library (Fork)"
category = "main"
optional = false
python-versions = ">=3.5"
[[package]]
name = "pygments"
version = "2.6.1"
description = "Pygments is a syntax highlighting package written in Python."
category = "main"
optional = false
python-versions = ">=3.5"
[[package]]
name = "pyinstaller"
version = "3.6"
description = "PyInstaller bundles a Python application and all its dependencies into a single package."
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[package.dependencies]
altgraph = "*"
dis3 = "*"
[[package]]
name = "pyparsing"
version = "2.4.7"
description = "Python parsing module"
category = "main"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]]
name = "pywin32-ctypes"
version = "0.2.0"
description = ""
category = "main"
optional = false
python-versions = "*"
[[package]]
name = "requests"
version = "2.24.0"
description = "Python HTTP for Humans."
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[package.dependencies]
certifi = ">=2017.4.17"
chardet = ">=3.0.2,<4"
idna = ">=2.5,<3"
urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26"
[package.extras]
security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"]
socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
[[package]]
name = "urllib3"
version = "1.25.9"
description = "HTTP library with thread-safe connection pooling, file post, and more."
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
[package.extras]
brotli = ["brotlipy (>=0.6.0)"]
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"]
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
[[package]]
name = "xlrd"
version = "1.2.0"
description = "Library for developers to extract data from Microsoft Excel (tm) spreadsheet files"
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[metadata]
lock-version = "1.1"
python-versions = "^3.8"
content-hash = "b3d607363c6daf2b5448aa5ee676cff28606af6200d8e9b42e89937a190a3d46"
[metadata.files]
altgraph = [
{file = "altgraph-0.17.2-py2.py3-none-any.whl", hash = "sha256:743628f2ac6a7c26f5d9223c91ed8ecbba535f506f4b6f558885a8a56a105857"},
{file = "altgraph-0.17.2.tar.gz", hash = "sha256:ebf2269361b47d97b3b88e696439f6e4cbc607c17c51feb1754f90fb79839158"},
]
certifi = [
{file = "certifi-2020.6.20-py2.py3-none-any.whl", hash = "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41"},
{file = "certifi-2020.6.20.tar.gz", hash = "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3"},
]
chardet = [
{file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"},
{file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"},
]
dis3 = [
{file = "dis3-0.1.3-py2-none-any.whl", hash = "sha256:61f7720dd0d8749d23fda3d7227ce74d73da11c2fade993a67ab2f9852451b14"},
{file = "dis3-0.1.3-py3-none-any.whl", hash = "sha256:30b6412d33d738663e8ded781b138f4b01116437f0872aa56aa3adba6aeff218"},
{file = "dis3-0.1.3.tar.gz", hash = "sha256:9259b881fc1df02ed12ac25f82d4a85b44241854330b1a651e40e0c675cb2d1e"},
]
docutils = [
{file = "docutils-0.16-py2.py3-none-any.whl", hash = "sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af"},
{file = "docutils-0.16.tar.gz", hash = "sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc"},
]
future = [
{file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"},
]
idna = [
{file = "idna-2.9-py2.py3-none-any.whl", hash = "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"},
{file = "idna-2.9.tar.gz", hash = "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb"},
]
itsdangerous = [
{file = "itsdangerous-1.1.0-py2.py3-none-any.whl", hash = "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"},
{file = "itsdangerous-1.1.0.tar.gz", hash = "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19"},
]
kivy = [
{file = "Kivy-1.11.1-cp27-cp27m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:11e85eaf6efbfa2362a3334ffdad179a1b0ca8d255cca79eaa6a2765560d4982"},
{file = "Kivy-1.11.1-cp27-cp27m-win32.whl", hash = "sha256:5c3d0f2749522d62e9cce09cd54b2d823bf1b6b644ff1f627be49de6f3e3cba0"},
{file = "Kivy-1.11.1-cp27-cp27m-win_amd64.whl", hash = "sha256:f835462dd9aa491272552ef079b948a088598e2e95d68bb1d885d2c3f3d4e2c3"},
{file = "Kivy-1.11.1-cp35-cp35m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:090d3ded9835a17477cd93fbdaf0a7c42ff2218981cf198ded5ad8795bc74391"},
{file = "Kivy-1.11.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:b85ccf165050cbf2ee8447671eebbc222b369b40f0e0038dd9547d49a5e37373"},
{file = "Kivy-1.11.1-cp35-cp35m-win32.whl", hash = "sha256:4a5480cbf837d3780c77a4f61b32b56d22ae9f03845e7a89dd3eaef1ae5fd037"},
{file = "Kivy-1.11.1-cp35-cp35m-win_amd64.whl", hash = "sha256:a687602d90c4629dd036f577ca39acb76ba581370f9d915f3cab99be818ba8ad"},
{file = "Kivy-1.11.1-cp36-cp36m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:c36652caa7f6c327dee834cfc699d5962d346b7a53e54bd81abc17c314226d89"},
{file = "Kivy-1.11.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:b7ef6aad43a86d8df3fb865db864e354f2155a748019f8517f69f65c1a29cb64"},
{file = "Kivy-1.11.1-cp36-cp36m-win32.whl", hash = "sha256:f3bea6e4a21991827885d04127fc6d09a0e974ecfa12da7bf5faae93562ea102"},
{file = "Kivy-1.11.1-cp36-cp36m-win_amd64.whl", hash = "sha256:ece170514db3f49844a41e4c910ad9ce9bc46da6f47a49158e11266bdcc6e479"},
{file = "Kivy-1.11.1-cp37-cp37m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:8819a27a09871af451760cb69486ced52e830c8a0a37480f22ef5e692f12c05b"},
{file = "Kivy-1.11.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:1a1ff32f8a95f1e175198cbab81fcd2596783b180d4eafe63e87d171aa7fdb5e"},
{file = "Kivy-1.11.1-cp37-cp37m-win32.whl", hash = "sha256:815a5c0b3b72fcd81ca7b2aa0744087163ed03e4cf9ab4e7c9733cea99fc1571"},
{file = "Kivy-1.11.1-cp37-cp37m-win_amd64.whl", hash = "sha256:1d28b198a64c30db8d94a0488e85f3037af60d514ab0d7ad5ab45add3ab77090"},
{file = "Kivy-1.11.1.tar.gz", hash = "sha256:4d0e596f74271e901b551f77661dde238df4765484fce9f5d1c72e8022984e84"},
]
"kivy-deps.angle" = [
{file = "kivy_deps.angle-0.3.0-cp310-cp310-win32.whl", hash = "sha256:7b56477c726e361592f794d49b2fdd96d579b7efd7225a8aadf7fd01d4e8cb80"},
{file = "kivy_deps.angle-0.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:a4b78fd9d47c76e5ff52fcbaa040920a2f97bff038f4c534346dd833dc8f3145"},
{file = "kivy_deps.angle-0.3.0-cp36-cp36m-win32.whl", hash = "sha256:a2cea09e8a5e899629466403fbd540459f1cdef8d08c6c479b6607b95309be02"},
{file = "kivy_deps.angle-0.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:b167e19b3eea55a9a8c606a607bb909ec1bedda88deee40347c780b310155a79"},
{file = "kivy_deps.angle-0.3.0-cp37-cp37m-win32.whl", hash = "sha256:d0e7b7b9eb9669837a5d70808a7ea45f2b61961b56f9f69a233bad6bd36ce260"},
{file = "kivy_deps.angle-0.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:b9d07976b0bf6bac724a42aa8ed5a8c7caa95609046db30c8f15bb731f8e4d36"},
{file = "kivy_deps.angle-0.3.0-cp38-cp38-win32.whl", hash = "sha256:99c40d53582a958748e251dfbd61aa67fb85963e27529ca08a21f2f5eeed04e1"},
{file = "kivy_deps.angle-0.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:50605fdd4c9fdbe9f717069734a598a9aba0afe5d3f0412afbe2ecff0326e92d"},
{file = "kivy_deps.angle-0.3.0-cp39-cp39-win32.whl", hash = "sha256:64ac7f33c000585dc30194e604aed925972c6b7c3848b5c3b073ae916fb0b55c"},
{file = "kivy_deps.angle-0.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:bb4d53f15a093214adbbe205c108ede5cc0f6af6eff104c1b8c468ddaaf6400a"},
]
"kivy-deps.glew" = [
{file = "kivy_deps.glew-0.1.12-cp27-cp27m-win32.whl", hash = "sha256:92e72fa2c425887987d1aa861c99537033dc20d68ae1c54864871f0401682586"},
{file = "kivy_deps.glew-0.1.12-cp27-cp27m-win_amd64.whl", hash = "sha256:c843104690c0c8f3a58105c53c57f31506f6f90562c18de00bd19317cc1045a7"},
{file = "kivy_deps.glew-0.1.12-cp35-cp35m-win32.whl", hash = "sha256:ee8ab67abb2c98d84feede657cae472e7723e529af07394244bdd33caafb1a38"},
{file = "kivy_deps.glew-0.1.12-cp35-cp35m-win_amd64.whl", hash = "sha256:ab81783a82bef88a8d2bcf8a93bc21df6b8b0db6ee551eb802727d18f9074b17"},
{file = "kivy_deps.glew-0.1.12-cp36-cp36m-win32.whl", hash = "sha256:45aa7f0e8d9bcf5fc1810c9c38bc20edf7dee61df81ecf62102e0f84153f924a"},
{file = "kivy_deps.glew-0.1.12-cp36-cp36m-win_amd64.whl", hash = "sha256:ef1116d99bd9cc737cb8c0e13e676955c17d6e4d6d1af5cfccef089a430071bb"},
{file = "kivy_deps.glew-0.1.12-cp37-cp37m-win32.whl", hash = "sha256:1e28e40017af9d081fc0fc95b4fadaf31d15e9f63478dcee1c4257d67079894e"},
{file = "kivy_deps.glew-0.1.12-cp37-cp37m-win_amd64.whl", hash = "sha256:6bb435620c3187d2c61054adb9ec277ed487256b457a0a7b1491bc0cb7247e18"},
{file = "kivy_deps.glew-0.1.12-cp38-cp38-win32.whl", hash = "sha256:09f72ee5ef33ff273332e2a229dc97d650d29818a0189339421949e4e0f63d93"},
{file = "kivy_deps.glew-0.1.12-cp38-cp38-win_amd64.whl", hash = "sha256:cf351aad171796f8051af8e49ec430a9aa128d8557d8643e73f2bb1e5f9c2dab"},
]
"kivy-deps.gstreamer" = [
{file = "kivy_deps.gstreamer-0.1.17-cp27-cp27m-win32.whl", hash = "sha256:309eca64dee5939f16f8465e5cbb08bdde7c90ded1af6a00690c7e928326af79"},
{file = "kivy_deps.gstreamer-0.1.17-cp27-cp27m-win_amd64.whl", hash = "sha256:0d9598d2d31c0e780adf4b767fa3a691123621fd0ffef94b83cf82c2da84341b"},
{file = "kivy_deps.gstreamer-0.1.17-cp35-cp35m-win32.whl", hash = "sha256:4f2ddd61d185310258d338ae80a646df7822efdd7d67e57f49dc7b87555c5d7e"},
{file = "kivy_deps.gstreamer-0.1.17-cp35-cp35m-win_amd64.whl", hash = "sha256:6fa9f76afe600baa221abee31ce7dc63e653d0affe0f6c558bfc4f35af96396f"},
{file = "kivy_deps.gstreamer-0.1.17-cp36-cp36m-win32.whl", hash = "sha256:c4709765e2b17c6c96b46a92207b0457def147544d825654077603eaf0d424de"},
{file = "kivy_deps.gstreamer-0.1.17-cp36-cp36m-win_amd64.whl", hash = "sha256:c29cfc63fe70a58dad889e631f1ba4711c9ea80103f2b2b8d670a97f093076c8"},
{file = "kivy_deps.gstreamer-0.1.17-cp37-cp37m-win32.whl", hash = "sha256:4d996377111e854b3dea90846f9b2f98766a44529fd8b72125e18c552381d928"},
{file = "kivy_deps.gstreamer-0.1.17-cp37-cp37m-win_amd64.whl", hash = "sha256:739cd331b9f33a822d700273674a79a3157054e9358a01a0d553f094a5f4a8c9"},
{file = "kivy_deps.gstreamer-0.1.17-cp38-cp38-win_amd64.whl", hash = "sha256:3d53d2c84c0a997c4cac6c239b1e0a6486e533836321003dc365ec42b97a664b"},
]
"kivy-deps.sdl2" = [
{file = "kivy_deps.sdl2-0.1.22-cp27-cp27m-win32.whl", hash = "sha256:1b987bdd4fbbcb31baf0d7fc9584ad99912179b8968311bb7e30fbeb14e98e0d"},
{file = "kivy_deps.sdl2-0.1.22-cp27-cp27m-win_amd64.whl", hash = "sha256:228128cdd8112dc7505ac43027a770476e9ef282e0b84ca68037133cd025960b"},
{file = "kivy_deps.sdl2-0.1.22-cp35-cp35m-win32.whl", hash = "sha256:053f26e8c05d5545bdbc7eeb8c450b8e4410ee355792e9345af536110fe247e2"},
{file = "kivy_deps.sdl2-0.1.22-cp35-cp35m-win_amd64.whl", hash = "sha256:5ce23f1a3286d6288751a12b0eaefd02f947ea101bb807e9781b964e496fc3f3"},
{file = "kivy_deps.sdl2-0.1.22-cp36-cp36m-win32.whl", hash = "sha256:96e1fa89fd8b5351f2d3c26bbffd50df8d554b03fba4025ecc941d773d241698"},
{file = "kivy_deps.sdl2-0.1.22-cp36-cp36m-win_amd64.whl", hash = "sha256:c3ace0ddde0e59cdcaf260eda1daa0c05ca9bf8cd0c4ea404539de25a5dcaec7"},
{file = "kivy_deps.sdl2-0.1.22-cp37-cp37m-win32.whl", hash = "sha256:7928746eaed51944c10d1bb36fcefebe3d1aff1b97ba32359c2c97ba74707e1b"},
{file = "kivy_deps.sdl2-0.1.22-cp37-cp37m-win_amd64.whl", hash = "sha256:2c2fd5a12a7a9afe3bb962b273561099a180edae91bb9c8f8386b72253fcae4a"},
{file = "kivy_deps.sdl2-0.1.22-cp38-cp38-win32.whl", hash = "sha256:9270fa8ed5130074b167a7a3a9c85efc3cfe3c04584ab084cb6ae9e4edfa8168"},
{file = "kivy_deps.sdl2-0.1.22-cp38-cp38-win_amd64.whl", hash = "sha256:92ed97d3247bc8ce98f336cbc940bb889310199326e9ccf251c49ae7e4b80de8"},
]
kivy-garden = [
{file = "Kivy Garden-0.1.4.tar.gz", hash = "sha256:9b7d9de5efacbcd0c4b3dd873b30622a86093c9965aa47b523c7a32f3eb34610"},
{file = "kivy-garden-0.1.4.tar.gz", hash = "sha256:c256f42788421273a08fbb0a228f0fb0e80dd86b629fb8c0920507f645be6c72"},
]
packaging = [
{file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"},
{file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"},
]
pdf2image = [
{file = "pdf2image-1.12.1.tar.gz", hash = "sha256:a0d9906f5507192210a8d5d7ead63145e9dec4bccc4564b1fb644e923913c31c"},
]
pefile = [
{file = "pefile-2021.9.3.tar.gz", hash = "sha256:344a49e40a94e10849f0fe34dddc80f773a12b40675bf2f7be4b8be578bdd94a"},
]
pillow = [
{file = "Pillow-7.2.0-cp35-cp35m-macosx_10_10_intel.whl", hash = "sha256:1ca594126d3c4def54babee699c055a913efb01e106c309fa6b04405d474d5ae"},
{file = "Pillow-7.2.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c92302a33138409e8f1ad16731568c55c9053eee71bb05b6b744067e1b62380f"},
{file = "Pillow-7.2.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:8dad18b69f710bf3a001d2bf3afab7c432785d94fcf819c16b5207b1cfd17d38"},
{file = "Pillow-7.2.0-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:431b15cffbf949e89df2f7b48528be18b78bfa5177cb3036284a5508159492b5"},
{file = "Pillow-7.2.0-cp35-cp35m-win32.whl", hash = "sha256:09d7f9e64289cb40c2c8d7ad674b2ed6105f55dc3b09aa8e4918e20a0311e7ad"},
{file = "Pillow-7.2.0-cp35-cp35m-win_amd64.whl", hash = "sha256:0295442429645fa16d05bd567ef5cff178482439c9aad0411d3f0ce9b88b3a6f"},
{file = "Pillow-7.2.0-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:ec29604081f10f16a7aea809ad42e27764188fc258b02259a03a8ff7ded3808d"},
{file = "Pillow-7.2.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:612cfda94e9c8346f239bf1a4b082fdd5c8143cf82d685ba2dba76e7adeeb233"},
{file = "Pillow-7.2.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0a80dd307a5d8440b0a08bd7b81617e04d870e40a3e46a32d9c246e54705e86f"},
{file = "Pillow-7.2.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:06aba4169e78c439d528fdeb34762c3b61a70813527a2c57f0540541e9f433a8"},
{file = "Pillow-7.2.0-cp36-cp36m-win32.whl", hash = "sha256:f7e30c27477dffc3e85c2463b3e649f751789e0f6c8456099eea7ddd53be4a8a"},
{file = "Pillow-7.2.0-cp36-cp36m-win_amd64.whl", hash = "sha256:ffe538682dc19cc542ae7c3e504fdf54ca7f86fb8a135e59dd6bc8627eae6cce"},
{file = "Pillow-7.2.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:94cf49723928eb6070a892cb39d6c156f7b5a2db4e8971cb958f7b6b104fb4c4"},
{file = "Pillow-7.2.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6edb5446f44d901e8683ffb25ebdfc26988ee813da3bf91e12252b57ac163727"},
{file = "Pillow-7.2.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:52125833b070791fcb5710fabc640fc1df07d087fc0c0f02d3661f76c23c5b8b"},
{file = "Pillow-7.2.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:9ad7f865eebde135d526bb3163d0b23ffff365cf87e767c649550964ad72785d"},
{file = "Pillow-7.2.0-cp37-cp37m-win32.whl", hash = "sha256:c79f9c5fb846285f943aafeafda3358992d64f0ef58566e23484132ecd8d7d63"},
{file = "Pillow-7.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d350f0f2c2421e65fbc62690f26b59b0bcda1b614beb318c81e38647e0f673a1"},
{file = "Pillow-7.2.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:6d7741e65835716ceea0fd13a7d0192961212fd59e741a46bbed7a473c634ed6"},
{file = "Pillow-7.2.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:edf31f1150778abd4322444c393ab9c7bd2af271dd4dafb4208fb613b1f3cdc9"},
{file = "Pillow-7.2.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:d08b23fdb388c0715990cbc06866db554e1822c4bdcf6d4166cf30ac82df8c41"},
{file = "Pillow-7.2.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:5e51ee2b8114def244384eda1c82b10e307ad9778dac5c83fb0943775a653cd8"},
{file = "Pillow-7.2.0-cp38-cp38-win32.whl", hash = "sha256:725aa6cfc66ce2857d585f06e9519a1cc0ef6d13f186ff3447ab6dff0a09bc7f"},
{file = "Pillow-7.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:a060cf8aa332052df2158e5a119303965be92c3da6f2d93b6878f0ebca80b2f6"},
{file = "Pillow-7.2.0-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:9c87ef410a58dd54b92424ffd7e28fd2ec65d2f7fc02b76f5e9b2067e355ebf6"},
{file = "Pillow-7.2.0-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:e901964262a56d9ea3c2693df68bc9860b8bdda2b04768821e4c44ae797de117"},
{file = "Pillow-7.2.0-pp36-pypy36_pp73-win32.whl", hash = "sha256:25930fadde8019f374400f7986e8404c8b781ce519da27792cbe46eabec00c4d"},
{file = "Pillow-7.2.0.tar.gz", hash = "sha256:97f9e7953a77d5a70f49b9a48da7776dc51e9b738151b22dacf101641594a626"},
]
pygments = [
{file = "Pygments-2.6.1-py3-none-any.whl", hash = "sha256:ff7a40b4860b727ab48fad6360eb351cc1b33cbf9b15a0f689ca5353e9463324"},
{file = "Pygments-2.6.1.tar.gz", hash = "sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44"},
]
pyinstaller = [
{file = "PyInstaller-3.6.tar.gz", hash = "sha256:3730fa80d088f8bb7084d32480eb87cbb4ddb64123363763cf8f2a1378c1c4b7"},
]
pyparsing = [
{file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
{file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
]
pywin32-ctypes = [
{file = "pywin32-ctypes-0.2.0.tar.gz", hash = "sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942"},
{file = "pywin32_ctypes-0.2.0-py2.py3-none-any.whl", hash = "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"},
]
requests = [
{file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"},
{file = "requests-2.24.0.tar.gz", hash = "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b"},
]
urllib3 = [
{file = "urllib3-1.25.9-py2.py3-none-any.whl", hash = "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"},
{file = "urllib3-1.25.9.tar.gz", hash = "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527"},
]
xlrd = [
{file = "xlrd-1.2.0-py2.py3-none-any.whl", hash = "sha256:e551fb498759fa3a5384a94ccd4c3c02eb7c00ea424426e212ac0c57be9dfbde"},
{file = "xlrd-1.2.0.tar.gz", hash = "sha256:546eb36cee8db40c3eaa46c351e67ffee6eeb5fa2650b71bc4c758a29a1b29b2"},
]

View File

@ -5,6 +5,7 @@ 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';
@ -37,16 +38,34 @@ describe('parsePyPyVersion', () => {
['pypy-3.6-v7.x', {pythonVersion: '3.6', pypyVersion: 'v7.x'}],
['pypy-3.6', {pythonVersion: '3.6', pypyVersion: 'x'}],
['pypy-3.6-nightly', {pythonVersion: '3.6', pypyVersion: 'nightly'}],
['pypy-3.6-v7.3.3rc1', {pythonVersion: '3.6', pypyVersion: 'v7.3.3-rc.1'}]
['pypy-3.6-v7.3.3rc1', {pythonVersion: '3.6', pypyVersion: 'v7.3.3-rc.1'}],
['pypy3.8-v7.3.7', {pythonVersion: '3.8', pypyVersion: 'v7.3.7'}],
['pypy3.8-v7.3.x', {pythonVersion: '3.8', pypyVersion: 'v7.3.x'}],
['pypy3.8-v7.x', {pythonVersion: '3.8', pypyVersion: 'v7.x'}],
['pypy3.8', {pythonVersion: '3.8', pypyVersion: 'x'}],
['pypy3.9-nightly', {pythonVersion: '3.9', pypyVersion: 'nightly'}],
['pypy3.9-v7.3.8rc1', {pythonVersion: '3.9', pypyVersion: 'v7.3.8-rc.1'}]
])('%s -> %s', (input, expected) => {
expect(finder.parsePyPyVersion(input)).toEqual(expected);
});
it('throw on invalid input', () => {
expect(() => finder.parsePyPyVersion('pypy-')).toThrowError(
"Invalid 'version' property for PyPy. PyPy version should be specified as 'pypy-<python-version>'. See README for examples and documentation."
);
});
it.each(['', 'pypy-', 'pypy', 'p', 'notpypy-'])(
'throw on invalid input "%s"',
input => {
expect(() => finder.parsePyPyVersion(input)).toThrowError(
"Invalid 'version' property for PyPy. PyPy version should be specified as 'pypy<python-version>' or 'pypy-<python-version>'. See README for examples and documentation."
);
}
);
it.each(['pypy-2', 'pypy-3', 'pypy2', 'pypy3', 'pypy3.x', 'pypy3.8.10'])(
'throw on invalid input "%s"',
input => {
expect(() => finder.parsePyPyVersion(input)).toThrowError(
"Invalid format of Python version for PyPy. Python version should be specified in format 'x.y'. See README for examples and documentation."
);
}
);
});
describe('getPyPyVersionFromPath', () => {
@ -130,8 +149,13 @@ describe('findPyPyVersion', () => {
let spyWriteExactPyPyVersionFile: jest.SpyInstance;
let spyCacheDir: jest.SpyInstance;
let spyChmodSync: jest.SpyInstance;
let spyCoreAddPath: jest.SpyInstance;
let spyCoreExportVariable: jest.SpyInstance;
const env = process.env;
beforeEach(() => {
jest.resetModules();
process.env = {...env};
tcFind = jest.spyOn(tc, 'find');
tcFind.mockImplementation((tool: string, version: string) => {
const semverRange = new semver.Range(version);
@ -183,32 +207,46 @@ describe('findPyPyVersion', () => {
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 PyPy in toolcache', async () => {
await expect(
finder.findPyPyVersion('pypy-3.6-v7.3.x', architecture)
finder.findPyPyVersion('pypy-3.6-v7.3.x', architecture, true)
).resolves.toEqual({
resolvedPythonVersion: '3.6.12',
resolvedPyPyVersion: '7.3.3'
});
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.findPyPyVersion('pypy3.7-v7.3.x', architecture)
finder.findPyPyVersion('pypy3.7-v7.3.x', architecture, true)
).rejects.toThrow();
});
it('throw on invalid input format pypy3.7-7.3.x', async () => {
await expect(
finder.findPyPyVersion('pypy3.7-v7.3.x', architecture)
finder.findPyPyVersion('pypy3.7-v7.3.x', architecture, true)
).rejects.toThrow();
});
@ -220,16 +258,42 @@ describe('findPyPyVersion', () => {
spyChmodSync = jest.spyOn(fs, 'chmodSync');
spyChmodSync.mockImplementation(() => undefined);
await expect(
finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture)
finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture, true)
).resolves.toEqual({
resolvedPythonVersion: '3.7.9',
resolvedPyPyVersion: '7.3.3'
});
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, 'PyPy', '3.7.7', architecture)
);
spyChmodSync = jest.spyOn(fs, 'chmodSync');
spyChmodSync.mockImplementation(() => undefined);
await expect(
finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture, false)
).resolves.toEqual({
resolvedPythonVersion: '3.7.9',
resolvedPyPyVersion: '7.3.3'
});
expect(spyCoreAddPath).not.toHaveBeenCalled();
expect(spyCoreExportVariable).not.toHaveBeenCalled();
});
it('throw if release is not found', async () => {
await expect(
finder.findPyPyVersion('pypy-3.7-v7.5.x', architecture)
finder.findPyPyVersion('pypy-3.7-v7.5.x', architecture, true)
).rejects.toThrowError(
`PyPy version 3.7 (v7.5.x) with arch ${architecture} not found`
);

View File

@ -19,15 +19,29 @@ process.env['RUNNER_TOOL_CACHE'] = toolDir;
process.env['RUNNER_TEMP'] = tempDir;
import * as tc from '@actions/tool-cache';
import * as core from '@actions/core';
import * as finder from '../src/find-python';
import * as installer from '../src/install-python';
const manifestData = require('./data/versions-manifest.json');
describe('Finder tests', () => {
let spyCoreAddPath: jest.SpyInstance;
let spyCoreExportVariable: jest.SpyInstance;
const env = process.env;
beforeEach(() => {
jest.resetModules();
process.env = {...env};
spyCoreAddPath = jest.spyOn(core, 'addPath');
spyCoreExportVariable = jest.spyOn(core, 'exportVariable');
});
afterEach(() => {
jest.resetAllMocks();
jest.clearAllMocks();
jest.restoreAllMocks();
process.env = env;
});
it('Finds Python if it is installed', async () => {
@ -35,7 +49,26 @@ describe('Finder tests', () => {
await io.mkdirP(pythonDir);
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
await finder.findPythonVersion('3.x', 'x64');
await finder.useCpythonVersion('3.x', 'x64', true);
expect(spyCoreAddPath).toHaveBeenCalled();
expect(spyCoreExportVariable).toHaveBeenCalledWith(
'pythonLocation',
expect.anything()
);
expect(spyCoreExportVariable).toHaveBeenCalledWith(
'PKG_CONFIG_PATH',
expect.anything()
);
});
it('Finds Python if it is installed without environment update', async () => {
const pythonDir: string = path.join(toolDir, 'Python', '3.0.0', 'x64');
await io.mkdirP(pythonDir);
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
await finder.useCpythonVersion('3.x', 'x64', false);
expect(spyCoreAddPath).not.toHaveBeenCalled();
expect(spyCoreExportVariable).not.toHaveBeenCalled();
});
it('Finds stable Python version if it is not installed, but exists in the manifest', async () => {
@ -52,7 +85,16 @@ describe('Finder tests', () => {
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
});
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
await finder.findPythonVersion('1.2.3', 'x64');
await finder.useCpythonVersion('1.2.3', 'x64', true);
expect(spyCoreAddPath).toHaveBeenCalled();
expect(spyCoreExportVariable).toHaveBeenCalledWith(
'pythonLocation',
expect.anything()
);
expect(spyCoreExportVariable).toHaveBeenCalledWith(
'PKG_CONFIG_PATH',
expect.anything()
);
});
it('Finds pre-release Python version in the manifest', async () => {
@ -74,25 +116,28 @@ describe('Finder tests', () => {
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
});
// This will throw if it doesn't find it in the manifest (because no such version exists)
await finder.findPythonVersion('1.2.3-beta.2', 'x64');
await finder.useCpythonVersion('1.2.3-beta.2', 'x64', true);
expect(spyCoreAddPath).toHaveBeenCalled();
expect(spyCoreExportVariable).toHaveBeenCalledWith(
'pythonLocation',
expect.anything()
);
expect(spyCoreExportVariable).toHaveBeenCalledWith(
'PKG_CONFIG_PATH',
expect.anything()
);
});
it('Errors if Python is not installed', async () => {
// This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
let thrown = false;
try {
await finder.findPythonVersion('3.300000', 'x64');
await finder.useCpythonVersion('3.300000', 'x64', true);
} catch {
thrown = true;
}
expect(thrown).toBeTruthy();
});
it('Finds PyPy if it is installed', async () => {
const pythonDir: string = path.join(toolDir, 'PyPy', '2.0.0', 'x64');
await io.mkdirP(pythonDir);
fs.writeFileSync(`${pythonDir}.complete`, 'hello');
// This will throw if it doesn't find it in the cache (because no such version exists)
await finder.findPythonVersion('pypy2', 'x64');
expect(spyCoreAddPath).not.toHaveBeenCalled();
expect(spyCoreExportVariable).not.toHaveBeenCalled();
});
});

View File

@ -1,8 +1,14 @@
import * as cache from '@actions/cache';
import * as core from '@actions/core';
import {
validateVersion,
validatePythonVersionFormatForPyPy
validatePythonVersionFormatForPyPy,
isCacheFeatureAvailable
} from '../src/utils';
jest.mock('@actions/cache');
jest.mock('@actions/core');
describe('validatePythonVersionFormatForPyPy', () => {
it.each([
['3.6', true],
@ -32,3 +38,39 @@ describe('validateVersion', () => {
expect(validateVersion(input)).toEqual(expected);
});
});
describe('isCacheFeatureAvailable', () => {
it('isCacheFeatureAvailable disabled on GHES', () => {
jest.spyOn(cache, 'isFeatureAvailable').mockImplementation(() => false);
try {
process.env['GITHUB_SERVER_URL'] = 'http://example.com';
isCacheFeatureAvailable();
} catch (error) {
expect(error).toHaveProperty(
'message',
'Caching is only supported on GHES version >= 3.5. If you are on a version >= 3.5, please check with your GHES admin if the Actions cache service is enabled or not.'
);
} finally {
delete process.env['GITHUB_SERVER_URL'];
}
});
it('isCacheFeatureAvailable disabled on dotcom', () => {
jest.spyOn(cache, 'isFeatureAvailable').mockImplementation(() => false);
const infoMock = jest.spyOn(core, 'warning');
const message =
'The runner was not able to contact the cache service. Caching will be skipped';
try {
process.env['GITHUB_SERVER_URL'] = 'http://github.com';
expect(isCacheFeatureAvailable()).toBe(false);
expect(infoMock).toHaveBeenCalledWith(message);
} finally {
delete process.env['GITHUB_SERVER_URL'];
}
});
it('isCacheFeatureAvailable is enabled', () => {
jest.spyOn(cache, 'isFeatureAvailable').mockImplementation(() => true);
expect(isCacheFeatureAvailable()).toBe(true);
});
});

View File

@ -4,10 +4,11 @@ description: 'Set up a specific version of Python and add the command-line tools
author: 'GitHub'
inputs:
python-version:
description: "Version range or exact version of a Python version to use, using SemVer's version range syntax."
default: '3.x'
description: "Version range or exact version of Python to use, using SemVer's version range syntax. Reads from .python-version if unset."
python-version-file:
description: "File containing the Python version to use. Example: .python-version"
cache:
description: 'Used to specify a package manager for caching in the default directory. Supported values: pip, pipenv.'
description: 'Used to specify a package manager for caching in the default directory. Supported values: pip, pipenv, poetry.'
required: false
architecture:
description: 'The target architecture (x86, x64) of the Python interpreter.'
@ -16,11 +17,18 @@ inputs:
default: ${{ github.token }}
cache-dependency-path:
description: 'Used to specify the path to dependency files. Supports wildcards or a list of file names for caching multiple dependencies.'
update-environment:
description: 'Set this option if you want the action to update environment variables.'
default: true
outputs:
python-version:
description: "The installed python version. Useful when given a version range as input."
cache-hit:
description: 'A boolean value to indicate a cache entry was found'
python-path:
description: "The absolute path to the Python executable."
runs:
using: 'node12'
using: 'node16'
main: 'dist/setup/index.js'
post: 'dist/cache-save/index.js'
post-if: success()

52655
dist/cache-save/index.js vendored

File diff suppressed because one or more lines are too long

65636
dist/setup/index.js vendored

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,93 @@
## 0. Caching dependencies
Date: 2021-10-01
Status: Accepted
## Context
`actions/setup-python` is one the most popular python's action in GitHub Actions. A lot of customers use it in conjunction with `actions/cache` to speed up dependencies installation.
See more examples on proper usage in [actions/cache documentation](https://github.com/actions/cache/blob/main/examples.md#python---pip).
## Goals & Anti-Goals
Integration of caching functionality into `actions/setup-python` action will bring the following benefits for action users:
- Decrease the entry threshold for using the cache for Python dependencies and simplify initial configuration
- Simplify YAML pipelines by reducing the need for additional steps to enable caching
- More users will use caching for Python so users will have faster builds!
We will add support for Pip and Pipenv dependency caching.
We won't pursue the goal to provide wide customization of caching in the scope of `actions/setup-python` action. The purpose of this integration is to cover ~90% of basic use-cases. If users need flexible customization, we will advise them to use `actions/cache` directly.
## Decision
- Add a `cache` input parameter to `actions/setup-python`. For now the input will accept the following values:
- pip - enable caching for pip dependencies
- pipenv - enable caching for pipenv dependencies
- '' - disable caching (default value)
- Cache feature will be disabled by default to make sure that we don't break existing customers.
- Action will try to search dependencies files (requirements.txt for pip and Pipfile.lock for pipenv) in the repository root (or relative to the repository root, if patterns are used) and throw error if no one is found.
- The hash of found file will be used as part of cache key (the same approach like actions/cache recommends)
- The following cache key will be used for pip: `setup-python-${{ runner.os }}-pip-${{ hashFiles('<package-file-path>') }}`
- The following cache key will be used for pipenv: `setup-python-${{ runner.os }}-python-${{ python-version }}-pipenv-${{ hashFiles('<package-file-path>') }}`. We add the python version to the cache key because the created virtualenv folder with the project name contains a copy of the python binary as a symlink to paths like `/opt/hostedtoolcache/Python/3.7.11`, so the cache can be fetched with a wrong python version. See details in the related [pull request](https://github.com/actions/cache/pull/607) in the actions/cache.
- Action will save the packages global cache:
- Pip (retrieved via pip cache dir). The command is available With pip 20.1 or later. We always update pip during installation, that is why this command should be available.
- Pipenv (default cache paths):
- ~/.local/share/virtualenvs (macOS)
- ~/.virtualenvs (Windows)
- ~/.local/share/virtualenvs (Ubuntu)
- Add a `cache-dependency-path` input parameter to `actions/setup-python`. The new input will accept an array or regex of dependency files. The field will accept a path (relative to the repository root) to dependency files. If the provided path contains wildcards, the action will search all matching files and calculate a common hash like the `${{ hashFiles('**/requirements-dev.txt') }}` YAML construction does
## Example of real use-cases
- Pip package manager
```
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: 3.9
cache: pip
```
- Pipenv package manager
```
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: 3.9
cache: pipenv
```
- With `cache-dependency-path`
```
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: 3.9
cache: pip
cache-dependency-path: |
**/requirements-dev.txt
**/requirements-test.txt
**/requirements.txt
```
```
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: 3.9
cache: pip
cache-dependency-path: **/requirements-dev.txt
```
## Release process
As soon as the functionality is implemented, we will release a minor update of the action. No need to bump the major version since there are no breaking changes for existing users. After that, we will update [starter-workflows](https://github.com/actions/starter-workflows/blob/main/ci/python-app.yml) and [GitHub Action documentation](https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#caching-dependencies).

11439
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,15 @@
{
"name": "setup-python",
"version": "2.2.2",
"version": "4.0.0",
"private": true,
"description": "Setup python action",
"main": "dist/index.js",
"scripts": {
"build": "tsc",
"build": "ncc build -o dist/setup src/setup-python.ts && ncc build -o dist/cache-save src/cache-save.ts",
"format": "prettier --write \"{,!(node_modules)/**/}*.ts\"",
"format-check": "prettier --check \"{,!(node_modules)/**/}*.ts\"",
"release": "ncc build -o dist/setup src/setup-python.ts && ncc build -o dist/cache-save src/cache-save.ts && git add -f dist/",
"test": "jest"
"test": "jest --coverage"
},
"repository": {
"type": "git",
@ -23,8 +23,8 @@
"author": "GitHub",
"license": "MIT",
"dependencies": {
"@actions/cache": "^1.0.7",
"@actions/core": "^1.2.3",
"@actions/cache": "^3.0.0",
"@actions/core": "^1.7.0",
"@actions/exec": "^1.1.0",
"@actions/glob": "^0.2.0",
"@actions/io": "^1.0.2",
@ -33,15 +33,15 @@
},
"devDependencies": {
"@types/jest": "^27.0.2",
"@types/node": "^12.20.36",
"@types/node": "^16.11.25",
"@types/semver": "^7.1.0",
"@zeit/ncc": "^0.22.0",
"@vercel/ncc": "^0.33.4",
"husky": "^7.0.2",
"jest": "^27.2.5",
"jest-circus": "^27.2.5",
"prettier": "^2.0.2",
"ts-jest": "^27.0.5",
"typescript": "^3.8.3"
"typescript": "^4.2.3"
},
"husky": {
"skipCI": true,

View File

@ -41,12 +41,17 @@ abstract class CacheDistributor {
restoreKey
);
this.handleMatchResult(matchedKey, primaryKey);
}
public handleMatchResult(matchedKey: string | undefined, primaryKey: string) {
if (matchedKey) {
core.saveState(State.CACHE_MATCHED_KEY, matchedKey);
core.info(`Cache restored from key: ${matchedKey}`);
} else {
core.info(`${this.packageManager} cache is not found`);
}
core.setOutput('cache-hit', matchedKey === primaryKey);
}
}

View File

@ -1,9 +1,11 @@
import PipCache from './pip-cache';
import PipenvCache from './pipenv-cache';
import PoetryCache from './poetry-cache';
export enum PackageManagers {
Pip = 'pip',
Pipenv = 'pipenv'
Pipenv = 'pipenv',
Poetry = 'poetry'
}
export function getCacheDistributor(
@ -13,9 +15,11 @@ export function getCacheDistributor(
) {
switch (packageManager) {
case PackageManagers.Pip:
return new PipCache(cacheDependencyPath);
return new PipCache(pythonVersion, cacheDependencyPath);
case PackageManagers.Pipenv:
return new PipenvCache(pythonVersion, cacheDependencyPath);
case PackageManagers.Poetry:
return new PoetryCache(pythonVersion, cacheDependencyPath);
default:
throw new Error(`Caching for '${packageManager}' is not supported`);
}

View File

@ -1,21 +1,42 @@
import * as glob from '@actions/glob';
import * as core from '@actions/core';
import * as exec from '@actions/exec';
import * as child_process from 'child_process';
import utils from 'util';
import * as path from 'path';
import os from 'os';
import CacheDistributor from './cache-distributor';
import {IS_WINDOWS} from '../utils';
class PipCache extends CacheDistributor {
constructor(cacheDependencyPath: string = '**/requirements.txt') {
constructor(
private pythonVersion: string,
cacheDependencyPath: string = '**/requirements.txt'
) {
super('pip', cacheDependencyPath);
}
protected async getCacheGlobalDirectories() {
const {stdout, stderr, exitCode} = await exec.getExecOutput(
'pip cache dir'
);
let exitCode = 1;
let stdout = '';
let stderr = '';
// Add temporary fix for Windows
// On windows it is necessary to execute through an exec
// because the getExecOutput gives a non zero code or writes to stderr for pip 22.0.2,
// or spawn must be started with the shell option enabled for getExecOutput
// Related issue: https://github.com/actions/setup-python/issues/328
if (IS_WINDOWS) {
const execPromisify = utils.promisify(child_process.exec);
({stdout: stdout, stderr: stderr} = await execPromisify('pip cache dir'));
} else {
({
stdout: stdout,
stderr: stderr,
exitCode: exitCode
} = await exec.getExecOutput('pip cache dir'));
}
if (exitCode && stderr) {
throw new Error(
@ -36,8 +57,8 @@ class PipCache extends CacheDistributor {
protected async computeKeys() {
const hash = await glob.hashFiles(this.cacheDependencyPath);
const primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${this.packageManager}-${hash}`;
const restoreKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${this.packageManager}`;
const primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}-${hash}`;
const restoreKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}`;
return {
primaryKey,

View File

@ -0,0 +1,76 @@
import * as glob from '@actions/glob';
import * as os from 'os';
import * as path from 'path';
import * as exec from '@actions/exec';
import CacheDistributor from './cache-distributor';
class PoetryCache extends CacheDistributor {
constructor(
private pythonVersion: string,
protected patterns: string = '**/poetry.lock'
) {
super('poetry', patterns);
}
protected async getCacheGlobalDirectories() {
const poetryConfig = await this.getPoetryConfiguration();
const cacheDir = poetryConfig['cache-dir'];
const virtualenvsPath = poetryConfig['virtualenvs.path'].replace(
'{cache-dir}',
cacheDir
);
const paths = [virtualenvsPath];
if (poetryConfig['virtualenvs.in-project'] === true) {
paths.push(path.join(process.cwd(), '.venv'));
}
return paths;
}
protected async computeKeys() {
const hash = await glob.hashFiles(this.patterns);
const primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}-${hash}`;
const restoreKey = undefined;
return {
primaryKey,
restoreKey
};
}
private async getPoetryConfiguration() {
const {stdout, stderr, exitCode} = await exec.getExecOutput('poetry', [
'config',
'--list'
]);
if (exitCode && stderr) {
throw new Error(
'Could not get cache folder path for poetry package manager'
);
}
const lines = stdout.trim().split('\n');
const config: any = {};
for (let line of lines) {
line = line.replace(/#.*$/gm, '');
const [key, value] = line.split('=').map(part => part.trim());
config[key] = JSON.parse(value);
}
return config as {
'cache-dir': string;
'virtualenvs.in-project': boolean;
'virtualenvs.path': string;
};
}
}
export default PoetryCache;

View File

@ -43,17 +43,11 @@ async function saveCache(packageManager: string) {
return;
}
try {
await cache.saveCache(cachePaths, primaryKey);
core.info(`Cache saved with the key: ${primaryKey}`);
} catch (error) {
const err = error as Error;
if (err.name === cache.ReserveCacheError.name) {
core.info(err.message);
} else {
throw error;
}
const cacheId = await cache.saveCache(cachePaths, primaryKey);
if (cacheId == -1) {
return;
}
core.info(`Cache saved with the key: ${primaryKey}`);
}
function isCacheDirectoryExists(cacheDirectory: string[]) {

View File

@ -20,7 +20,8 @@ interface IPyPyVersionSpec {
export async function findPyPyVersion(
versionSpec: string,
architecture: string
architecture: string,
updateEnvironment: boolean
): Promise<{resolvedPyPyVersion: string; resolvedPythonVersion: string}> {
let resolvedPyPyVersion = '';
let resolvedPythonVersion = '';
@ -48,10 +49,26 @@ export async function findPyPyVersion(
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 = pypyInstall.getPyPyBinaryPath(installDir);
core.exportVariable('pythonLocation', pythonLocation);
core.addPath(pythonLocation);
core.addPath(_binDir);
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', 'pypy' + resolvedPyPyVersion.trim());
core.setOutput('python-path', pythonPath);
return {resolvedPyPyVersion, resolvedPythonVersion};
}
@ -96,9 +113,14 @@ export function findPyPyToolCache(
export function parsePyPyVersion(versionSpec: string): IPyPyVersionSpec {
const versions = versionSpec.split('-').filter(item => !!item);
if (/^(pypy)(.+)/.test(versions[0])) {
let pythonVersion = versions[0].replace('pypy', '');
versions.splice(0, 1, 'pypy', pythonVersion);
}
if (versions.length < 2 || versions[0] != 'pypy') {
throw new Error(
"Invalid 'version' property for PyPy. PyPy version should be specified as 'pypy-<python-version>'. See README for examples and documentation."
"Invalid 'version' property for PyPy. PyPy version should be specified as 'pypy<python-version>' or 'pypy-<python-version>'. See README for examples and documentation."
);
}

View File

@ -30,54 +30,10 @@ function binDir(installDir: string): string {
}
}
// Note on the tool cache layout for PyPy:
// PyPy has its own versioning scheme that doesn't follow the Python versioning scheme.
// A particular version of PyPy may contain one or more versions of the Python interpreter.
// For example, PyPy 7.0 contains Python 2.7, 3.5, and 3.6-alpha.
// We only care about the Python version, so we don't use the PyPy version for the tool cache.
function usePyPy(
majorVersion: '2' | '3.6',
architecture: string
): InstalledVersion {
const findPyPy = tc.find.bind(undefined, 'PyPy', majorVersion);
let installDir: string | null = findPyPy(architecture);
if (!installDir && IS_WINDOWS) {
// PyPy only precompiles binaries for x86, but the architecture parameter defaults to x64.
// On our Windows virtual environments, we only install an x86 version.
// Fall back to x86.
installDir = findPyPy('x86');
}
if (!installDir) {
// PyPy not installed in $(Agent.ToolsDirectory)
throw new Error(`PyPy ${majorVersion} not found`);
}
// For PyPy, Windows uses 'bin', not 'Scripts'.
const _binDir = path.join(installDir, 'bin');
// On Linux and macOS, the Python interpreter is in 'bin'.
// On Windows, it is in the installation root.
const pythonLocation = IS_WINDOWS ? installDir : _binDir;
core.exportVariable('pythonLocation', pythonLocation);
core.addPath(installDir);
core.addPath(_binDir);
// Starting from PyPy 7.3.1, the folder that is used for pip and anything that pip installs should be "Scripts" on Windows.
if (IS_WINDOWS) {
core.addPath(path.join(installDir, 'Scripts'));
}
const impl = 'pypy' + majorVersion.toString();
core.setOutput('python-version', impl);
return {impl: impl, version: versionFromPath(installDir)};
}
async function useCpythonVersion(
export async function useCpythonVersion(
version: string,
architecture: string
architecture: string,
updateEnvironment: boolean
): Promise<InstalledVersion> {
const desugaredVersionSpec = desugarDevVersion(version);
const semanticVersionSpec = pythonVersionToSemantic(desugaredVersionSpec);
@ -114,54 +70,67 @@ async function useCpythonVersion(
);
}
core.exportVariable('pythonLocation', installDir);
const _binDir = binDir(installDir);
const binaryExtension = IS_WINDOWS ? '.exe' : '';
const pythonPath = path.join(
IS_WINDOWS ? installDir : _binDir,
`python${binaryExtension}`
);
if (updateEnvironment) {
core.exportVariable('pythonLocation', installDir);
core.exportVariable('PKG_CONFIG_PATH', installDir + '/lib/pkgconfig');
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', installDir + '/lib/pkgconfig');
if (IS_LINUX) {
const libPath = process.env.LD_LIBRARY_PATH
? `:${process.env.LD_LIBRARY_PATH}`
: '';
const pyLibPath = path.join(installDir, 'lib');
if (IS_LINUX) {
const libPath = process.env.LD_LIBRARY_PATH
? `:${process.env.LD_LIBRARY_PATH}`
: '';
const pyLibPath = path.join(installDir, 'lib');
if (!libPath.split(':').includes(pyLibPath)) {
core.exportVariable('LD_LIBRARY_PATH', pyLibPath + libPath);
if (!libPath.split(':').includes(pyLibPath)) {
core.exportVariable('LD_LIBRARY_PATH', pyLibPath + libPath);
}
}
core.addPath(installDir);
core.addPath(_binDir);
if (IS_WINDOWS) {
// Add --user directory
// `installDir` from tool cache should look like $RUNNER_TOOL_CACHE/Python/<semantic version>/x64/
// So if `findLocalTool` succeeded above, we must have a conformant `installDir`
const version = path.basename(path.dirname(installDir));
const major = semver.major(version);
const minor = semver.minor(version);
const userScriptsDir = path.join(
process.env['APPDATA'] || '',
'Python',
`Python${major}${minor}`,
'Scripts'
);
core.addPath(userScriptsDir);
}
// On Linux and macOS, pip will create the --user directory and add it to PATH as needed.
}
core.addPath(installDir);
core.addPath(binDir(installDir));
if (IS_WINDOWS) {
// Add --user directory
// `installDir` from tool cache should look like $RUNNER_TOOL_CACHE/Python/<semantic version>/x64/
// So if `findLocalTool` succeeded above, we must have a conformant `installDir`
const version = path.basename(path.dirname(installDir));
const major = semver.major(version);
const minor = semver.minor(version);
const userScriptsDir = path.join(
process.env['APPDATA'] || '',
'Python',
`Python${major}${minor}`,
'Scripts'
);
core.addPath(userScriptsDir);
}
// On Linux and macOS, pip will create the --user directory and add it to PATH as needed.
const installed = versionFromPath(installDir);
core.setOutput('python-version', installed);
core.setOutput('python-path', pythonPath);
return {impl: 'CPython', version: installed};
}
/** Convert versions like `3.8-dev` to a version like `>= 3.8.0-a0`. */
/** Convert versions like `3.8-dev` to a version like `~3.8.0-0`. */
function desugarDevVersion(versionSpec: string) {
if (versionSpec.endsWith('-dev')) {
const versionRoot = versionSpec.slice(0, -'-dev'.length);
return `>= ${versionRoot}.0-a0`;
} else {
return versionSpec;
}
const devVersion = /^(\d+)\.(\d+)-dev$/;
return versionSpec.replace(devVersion, '~$1.$2.0-0');
}
/** Extracts python version from install path from hosted tool cache as described in README.md */
@ -186,18 +155,3 @@ export function pythonVersionToSemantic(versionSpec: string) {
const prereleaseVersion = /(\d+\.\d+\.\d+)((?:a|b|rc)\d*)/g;
return versionSpec.replace(prereleaseVersion, '$1-$2');
}
export async function findPythonVersion(
version: string,
architecture: string
): Promise<InstalledVersion> {
switch (version.toUpperCase()) {
case 'PYPY2':
return usePyPy('2', architecture);
case 'PYPY3':
// keep pypy3 pointing to 3.6 for backward compatibility
return usePyPy('3.6', architecture);
default:
return await useCpythonVersion(version, architecture);
}
}

View File

@ -98,7 +98,9 @@ async function createPyPySymlink(
) {
const version = semver.coerce(pythonVersion)!;
const pythonBinaryPostfix = semver.major(version);
const pythonMinor = semver.minor(version);
const pypyBinaryPostfix = pythonBinaryPostfix === 2 ? '' : '3';
const pypyMajorMinorBinaryPostfix = `${pythonBinaryPostfix}.${pythonMinor}`;
let binaryExtension = IS_WINDOWS ? '.exe' : '';
core.info('Creating symlinks...');
@ -115,6 +117,13 @@ async function createPyPySymlink(
`python${binaryExtension}`,
true
);
createSymlinkInFolder(
pypyBinaryPath,
`pypy${pypyBinaryPostfix}${binaryExtension}`,
`pypy${pypyMajorMinorBinaryPostfix}${binaryExtension}`,
true
);
}
async function installPip(pythonLocation: string) {

View File

@ -3,17 +3,15 @@ import * as finder from './find-python';
import * as finderPyPy from './find-pypy';
import * as path from 'path';
import * as os from 'os';
import fs from 'fs';
import {getCacheDistributor} from './cache-distributions/cache-factory';
import {isGhes} from './utils';
import {isCacheFeatureAvailable, IS_LINUX, IS_WINDOWS} from './utils';
function isPyPyVersion(versionSpec: string) {
return versionSpec.startsWith('pypy-');
return versionSpec.startsWith('pypy');
}
async function cacheDependencies(cache: string, pythonVersion: string) {
if (isGhes()) {
throw new Error('Caching is not supported on GHES');
}
const cacheDependencyPath =
core.getInput('cache-dependency-path') || undefined;
const cacheDistributor = getCacheDistributor(
@ -24,28 +22,89 @@ async function cacheDependencies(cache: string, pythonVersion: string) {
await cacheDistributor.restoreCache();
}
function resolveVersionInput(): string {
let version = core.getInput('python-version');
let versionFile = core.getInput('python-version-file');
if (version && versionFile) {
core.warning(
'Both python-version and python-version-file inputs are specified, only python-version will be used.'
);
}
if (version) {
return version;
}
if (versionFile) {
if (!fs.existsSync(versionFile)) {
logWarning(
`The specified python version file at: ${versionFile} doesn't exist. Attempting to find .python-version file.`
);
versionFile = '.python-version';
if (!fs.existsSync(versionFile)) {
throw new Error(`The ${versionFile} doesn't exist.`);
}
}
version = fs.readFileSync(versionFile, 'utf8');
core.info(`Resolved ${versionFile} as ${version}`);
return version;
}
core.warning(
"Neither 'python-version' nor 'python-version-file' inputs were supplied."
);
return version;
}
async function run() {
// According to the README windows binaries do not require to be installed
// in the specific location, but Mac and Linux do
if (!IS_WINDOWS && !process.env.AGENT_TOOLSDIRECTORY?.trim()) {
if (IS_LINUX) process.env['AGENT_TOOLSDIRECTORY'] = '/opt/hostedtoolcache';
else process.env['AGENT_TOOLSDIRECTORY'] = '/Users/runner/hostedtoolcache';
process.env['RUNNER_TOOL_CACHE'] = process.env['AGENT_TOOLSDIRECTORY'];
}
core.debug(
`Python is expected to be installed into RUNNER_TOOL_CACHE=${process.env['RUNNER_TOOL_CACHE']}`
);
try {
const version = core.getInput('python-version');
const version = resolveVersionInput();
if (version) {
let pythonVersion: string;
const arch: string = core.getInput('architecture') || os.arch();
const updateEnvironment = core.getBooleanInput('update-environment');
if (isPyPyVersion(version)) {
const installed = await finderPyPy.findPyPyVersion(version, arch);
const installed = await finderPyPy.findPyPyVersion(
version,
arch,
updateEnvironment
);
pythonVersion = `${installed.resolvedPyPyVersion}-${installed.resolvedPythonVersion}`;
core.info(
`Successfully setup PyPy ${installed.resolvedPyPyVersion} with Python (${installed.resolvedPythonVersion})`
`Successfully set up PyPy ${installed.resolvedPyPyVersion} with Python (${installed.resolvedPythonVersion})`
);
} else {
const installed = await finder.findPythonVersion(version, arch);
const installed = await finder.useCpythonVersion(
version,
arch,
updateEnvironment
);
pythonVersion = installed.version;
core.info(`Successfully setup ${installed.impl} (${pythonVersion})`);
core.info(`Successfully set up ${installed.impl} (${pythonVersion})`);
}
const cache = core.getInput('cache');
if (cache) {
if (cache && isCacheFeatureAvailable()) {
await cacheDependencies(cache, pythonVersion);
}
} else {
core.warning(
'The `python-version` input is not set. The version of Python currently in `PATH` will be used.'
);
}
const matchersPath = path.join(__dirname, '../..', '.github');
core.info(`##[add-matcher]${path.join(matchersPath, 'python.json')}`);
@ -54,4 +113,9 @@ async function run() {
}
}
export function logWarning(message: string): void {
const warningPrefix = '[warning]';
core.info(`${warningPrefix}${message}`);
}
run();

View File

@ -1,3 +1,5 @@
import * as cache from '@actions/cache';
import * as core from '@actions/core';
import fs from 'fs';
import * as path from 'path';
import * as semver from 'semver';
@ -99,3 +101,21 @@ export function isGhes(): boolean {
);
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM';
}
export function isCacheFeatureAvailable(): boolean {
if (!cache.isFeatureAvailable()) {
if (isGhes()) {
throw new Error(
'Caching is only supported on GHES version >= 3.5. If you are on a version >= 3.5, please check with your GHES admin if the Actions cache service is enabled or not.'
);
} else {
core.warning(
'The runner was not able to contact the cache service. Caching will be skipped'
);
}
return false;
}
return true;
}