Compare commits

...

51 Commits

Author SHA1 Message Date
61a6322f88 Fix typos found by codespell (#650) 2023-07-13 15:35:02 +02:00
ea5b57fccc Bump semver from 7.3.8 to 7.5.2 (#692) 2023-07-13 15:25:58 +02:00
014d32a830 Bump tough-cookie and @azure/ms-rest-js (#697) 2023-07-13 15:02:04 +02:00
c16c4b8d18 Fix pipenv jobs (#699) 2023-07-13 14:11:40 +02:00
0d5da6a89a Read python version from pyproject.toml (fix #542) (#669) 2023-06-28 22:02:44 +02:00
3f824b7ca6 remove python 2.7 from the tests (#687) 2023-06-19 13:20:44 +02:00
bd6b4b6205 Add warning for python 2.7 (#673) 2023-05-24 14:37:35 +02:00
0cbcb9a3d7 Merge pull request #668 from akv-platform/disallow-implicit-dependencies
Remove implicit dependency
2023-05-23 12:48:06 +02:00
669664dac1 Merge branch 'tool-config-auto-update' into disallow-implicit-dependencies 2023-05-23 10:33:18 +02:00
9cbf792a3c Update configuration files 2023-05-23 08:23:56 +00:00
e732e40717 Update licenses 2023-05-22 12:13:00 +02:00
a0d867bfa9 Change http-client dependency to one matching previous version 2023-05-22 11:53:31 +02:00
d99bed8b21 Update license 2023-05-22 11:03:05 +02:00
f71253fee3 Change to @action/http-client version to the one that was used in the most recent build 2023-05-22 11:02:56 +02:00
b51c97f6e3 Add eslint rule for disallowing implicit dependencies 2023-05-22 10:41:59 +02:00
db9987b4c1 Fix a incorrect link advanced-usage.md (#657) 2023-04-25 11:31:57 +02:00
6db7460265 fix allow-prereleases sample configuration (#615) 2023-04-20 14:46:49 +02:00
57ded4d7d5 update @azure/storage-blob (#655) 2023-04-20 14:13:16 +02:00
df6abcc733 update xml2js (#652) 2023-04-19 13:40:45 +02:00
7a4f344e33 Add warning for empty cache paths (#642) 2023-04-06 12:02:34 +02:00
d1244c8404 Remove ubuntu-18.04 from e2e (#641) 2023-04-04 16:18:24 +02:00
3091b37310 Fix glob bug in package.json scripts section (#637) 2023-04-03 12:46:57 +02:00
dfa76f8d0d Update configuration files (#622)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-03-15 00:32:39 +01:00
03eb867e3d Add error handling for saving and restoring cache (#618) 2023-03-10 12:15:18 +01:00
b41aaf9f0c Merge pull request #621 from akv-platform/reusable-workflow
Turn on automatic update of ESLint and Prettier configuration files
2023-03-10 10:55:42 +01:00
0ffa49cfca Add update-config-files.yml 2023-03-09 11:47:39 +01:00
ec365b4eba Add and configure ESLint and update configuration for Prettier (#617)
* Add ESLint, update Prettier

* Update docs

* Update tests

* Update licenses

* Fix review points
2023-03-09 12:44:56 +02:00
7b9ef6fc5a Add another pip default dependency file for cache hash (#604) 2023-02-20 13:36:57 +01:00
869e769ec8 Trim trailing newlines from resolvedPyPyVersion (#610)
Fixes #609
2023-02-20 11:28:16 +01:00
3faddefb4c Fix GHE documentation link (#602)
Co-authored-by: Fevrin <fevrin@users.noreply.github.com>
2023-02-09 09:31:03 +01:00
181184007f Update workflow badges (#594) 2023-01-31 08:46:32 +02:00
2652534ead feature: fallback to pre-release when no stable version is found (#414)
This allows to specify version like `3.11` or `pypy3.10` in workflows before those versions are released.
This lessen the burden for users of `setup-python` by not having to modify their workflow twice: once when a pre-release is available (e.g. `3.11-dev`) and once when the first stable release is published (e.g. `3.11`)
2023-01-27 16:19:31 -05:00
a6eba85bba Fix small action version typo in docs (#590) 2023-01-18 14:43:44 +01:00
34b4b622e3 Encourage the use of pre-release Python 3.12, not 3.11 (#586) 2023-01-16 10:27:26 +01:00
f60fe39c45 Update release-new-action-version.yml (#584) 2023-01-12 13:52:32 +01:00
d27e3f3d7c Fix outdated ref to actions/setup-python@v3 in doc (#581) 2023-01-09 09:55:39 +01:00
dec86ecf4e Bump json5 from 2.2.0 to 2.2.3 (#579)
Bumps [json5](https://github.com/json5/json5) from 2.2.0 to 2.2.3.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v2.2.0...v2.2.3)

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

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-04 12:41:23 -05:00
4dcd67678f Update CODEOWNERS (#576) 2023-01-04 17:01:11 +01:00
8b89ef08a0 Use correct Poetry config when collecting Poetry projects (#447)
* Use correct Poetry config when collecting Poetry projects

When collecting Poetry projects for caching, a '**/poetry.lock' glob is
used.  However, in order to process the Poetry configuration, the
"poetry" command is run from the repo's root directory; this causes
Poetry to return an invalid configuration when there is a Poetry project
inside an inner directory.

Instead of running a single Poetry command, glob for the same pattern,
and run a Poetry command for every discovered project.

* Fix typo: saveSatetSpy -> saveStateSpy

* poetry: Support same virtualenv appearing in multiple projects

* Add nested Poetry projects test

* poetry: Set up environment for each project individually

* tests/cache-restore: Do not look for dependency files outside `data`

When the default dependency path is used for cache distributors, they
are looking for the dependency file in the project's root (including the
source code), which leads to tests taking a significant amount of time,
especially on Windows runners.  We thus hit sporadic test failures.

Change the test cases such that dependency files are always searched for
inside of `__tests__/data`, ignoring the rest of the project.

* poetry: Simplify `virtualenvs.in-project` boolean check

* README: Explain that poetry might create multiple caches

* poetry: Run `poetry env use` only after cache is loaded

The virtualenv cache might contain invalid entries, such as virtualenvs
built in previous, buggy versions of this action.  The `poetry env use`
command will recreate virtualenvs in case they are invalid, but it has
to be run only *after* the cache is loaded.

Refactor `CacheDistributor` a bit such that the validation (and possible
recreation) of virtualenvs happens only after the cache is loaded.

* poetry: Bump cache primary key
2023-01-03 11:13:00 -05:00
5ccb29d877 Install multiple python versions (#567) 2022-12-22 13:02:09 +01:00
c3e033939c Update action to use reusable workflows (#569)
* Update workflows to use reusable-workflows

* Update licensed.yml

* Update workflows

* Add links to reusable workflows

* Update action to use reusable-workflows repo

* Fix review points
2022-12-22 11:17:13 +02:00
206e984b94 refactor: Use early return pattern to avoid nested conditions (#566)
* refactor: Use early return pattern

Signed-off-by: jongwooo <jongwooo.han@gmail.com>

* fix: Replace throw with warn

Signed-off-by: jongwooo <jongwooo.han@gmail.com>

Signed-off-by: jongwooo <jongwooo.han@gmail.com>
2022-12-19 14:00:46 +01:00
2c3dd9e7e2 Add OS info to the error message (#559) 2022-12-07 18:12:42 +01:00
76bbdfadd7 Update minimatch (#558) 2022-12-07 18:08:22 +01:00
1aafadcfb9 Caching projects that use setup.py (#549) 2022-11-29 12:46:57 -05:00
b80efd6bc5 Update to latest actions/publish-action (#546)
To avoid Actions core deprecation messages.

https://github.com/actions/publish-action/releases/tag/v0.2.1
2022-11-24 12:14:51 +01:00
5cddb27885 Recommend setting python-version (#545)
* Recommend setting python-version

* Recommend both options to set Python version

Co-authored-by: MaksimZhukov <46996400+MaksimZhukov@users.noreply.github.com>

Co-authored-by: MaksimZhukov <46996400+MaksimZhukov@users.noreply.github.com>
2022-11-21 13:47:16 +01:00
47c4a7af1d fix(ci): run .github/workflows/workflow.yml on ubuntu-20.04 (#535) 2022-11-07 13:10:21 +01:00
af57b64994 Extend docu regarding rate limit issues. (#510) 2022-10-31 09:50:28 +01:00
4818a5a153 Handle download HTTP error (#511) 2022-10-24 11:10:18 +02:00
8bcd2560e2 Add architecture input check for PyPy for Windows platform (#520)
* Revert cache index.js

* build cache index file

* Refactor

* Debug

* Debug

* Debug

* Debug

* Debug

* Debug

* Debug

* Debug

* Format code

* Rebuild dist

* Minor refactor

* Format code

* Minor fixes

* Check platform firstly
2022-10-18 11:01:15 +02:00
73 changed files with 17184 additions and 21666 deletions

6
.eslintignore Normal file
View File

@ -0,0 +1,6 @@
# Ignore list
/*
# Do not ignore these folders:
!__tests__/
!src/

51
.eslintrc.js Normal file
View File

@ -0,0 +1,51 @@
// This is a reusable configuration file copied from https://github.com/actions/reusable-workflows/tree/main/reusable-configurations. Please don't make changes to this file as it's the subject of an automatic update.
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:eslint-plugin-jest/recommended',
'eslint-config-prettier'
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint', 'eslint-plugin-node', 'eslint-plugin-jest'],
rules: {
'@typescript-eslint/no-require-imports': 'error',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/ban-ts-comment': [
'error',
{
'ts-ignore': 'allow-with-description'
}
],
'no-console': 'error',
'yoda': 'error',
'prefer-const': [
'error',
{
destructuring: 'all'
}
],
'no-control-regex': 'off',
'no-constant-condition': ['error', {checkLoops: false}],
'node/no-extraneous-import': 'error'
},
overrides: [
{
files: ['**/*{test,spec}.ts'],
rules: {
'@typescript-eslint/no-unused-vars': 'off',
'jest/no-standalone-expect': 'off',
'jest/no-conditional-expect': 'off',
'no-console': 'off',
}
}
],
env: {
node: true,
es6: true,
'jest/globals': true
}
};

2
.github/CODEOWNERS vendored
View File

@ -1 +1 @@
* @actions/actions-service * @actions/setup-actions-team

View File

@ -1 +1 @@
blank_issues_enabled: false blank_issues_enabled: false

15
.github/workflows/basic-validation.yml vendored Normal file
View File

@ -0,0 +1,15 @@
name: Basic validation
on:
push:
branches:
- main
paths-ignore:
- '**.md'
pull_request:
paths-ignore:
- '**.md'
jobs:
call-basic-validation:
name: Basic validation
uses: actions/reusable-workflows/.github/workflows/basic-validation.yml@main

View File

@ -1,8 +1,3 @@
# `dist/index.js` is a special file in Actions.
# When you reference an action with `uses:` in a workflow,
# `index.js` is the code that will run.
# For our project, we generate this file through a build process from other source files.
# We need to make sure the checked-in `index.js` actually matches what we expect it to be.
name: Check dist/ name: Check dist/
on: on:
@ -17,36 +12,6 @@ on:
workflow_dispatch: workflow_dispatch:
jobs: jobs:
check-dist: call-check-dist:
runs-on: ubuntu-latest name: Check dist/
uses: actions/reusable-workflows/.github/workflows/check-dist.yml@main
steps:
- uses: actions/checkout@v3
- name: Set Node.js 16.x
uses: actions/setup-node@v3
with:
node-version: 16.x
cache: npm
- name: Install dependencies
run: npm ci
- name: Rebuild the dist/ directory
run: npm run build
- name: Compare the expected and actual dist/ directories
run: |
if [ "$(git diff --ignore-space-at-eol dist/ | wc -l)" -gt "0" ]; then
echo "Detected uncommitted changes after build. See status below:"
git diff
exit 1
fi
id: diff
# If index.js was different than expected, upload the expected version as an artifact
- uses: actions/upload-artifact@v3
if: ${{ failure() && steps.diff.conclusion == 'failure' }}
with:
name: dist
path: dist/

View File

@ -1,47 +1,13 @@
name: "Code scanning - action" name: CodeQL analysis
on: on:
push: push:
branches: [ 'main' ] branches: ['main']
pull_request: pull_request:
schedule: schedule:
- cron: '25 3 * * 5' - cron: '0 3 * * 0'
jobs: jobs:
CodeQL-Build: call-codeQL-analysis:
name: CodeQL analysis
strategy: uses: actions/reusable-workflows/.github/workflows/codeql-analysis.yml@main
fail-fast: false
# CodeQL runs on ubuntu-latest and windows-latest
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
# Override language selection by uncommenting this and choosing your languages
# with:
# languages: go, javascript, csharp, python, cpp, java
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2

View File

@ -43,22 +43,30 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup Python - name: Setup Python
id: cache-pipenv
uses: ./ uses: ./
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
cache: 'pipenv' cache: 'pipenv'
- name: Install pipenv - name: Install pipenv
run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python
- name: Install dependencies - name: Prepare environment
shell: pwsh shell: pwsh
run: | run: |
mv ./__tests__/data/Pipfile.lock . mv ./__tests__/data/Pipfile.lock .
mv ./__tests__/data/Pipfile . mv ./__tests__/data/Pipfile .
mv ./__tests__/test-pipenv.py .
- name: Install dependencies
shell: pwsh
if: steps.cache-pipenv.outputs.cache-hit != 'true'
run: |
if ("${{ matrix.python-version }}" -Match "pypy") { if ("${{ matrix.python-version }}" -Match "pypy") {
pipenv install --keep-outdated --python pypy pipenv install --python pypy # --keep-outdated
} else { } else {
pipenv install --keep-outdated --python ${{ matrix.python-version }} pipenv install --python ${{ matrix.python-version }} # --keep-outdated
} }
- name: Run Python Script
run: pipenv run python test-pipenv.py
python-poetry-dependencies-caching: python-poetry-dependencies-caching:
name: Test poetry (Python ${{ matrix.python-version}}, ${{ matrix.os }}) name: Test poetry (Python ${{ matrix.python-version}}, ${{ matrix.os }})
@ -112,6 +120,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup Python - name: Setup Python
id: cache-pipenv
uses: ./ uses: ./
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
@ -119,13 +128,20 @@ jobs:
cache-dependency-path: '**/pipenv-requirements.txt' cache-dependency-path: '**/pipenv-requirements.txt'
- name: Install pipenv - name: Install pipenv
run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python run: curl https://raw.githubusercontent.com/pypa/pipenv/master/get-pipenv.py | python
- name: Install dependencies - name: Prepare environment
shell: pwsh shell: pwsh
run: | run: |
mv ./__tests__/data/Pipfile.lock . mv ./__tests__/data/Pipfile.lock .
mv ./__tests__/data/Pipfile . mv ./__tests__/data/Pipfile .
mv ./__tests__/test-pipenv.py .
- name: Install dependencies
shell: pwsh
if: steps.cache-pipenv.outputs.cache-hit != 'true'
run: |
if ("${{ matrix.python-version }}" -Match "pypy") { if ("${{ matrix.python-version }}" -Match "pypy") {
pipenv install --keep-outdated --python pypy pipenv install --python pypy # --keep-outdated
} else { } else {
pipenv install --keep-outdated --python ${{ matrix.python-version }} pipenv install --python ${{ matrix.python-version }} # --keep-outdated
} }
- name: Run Python Script
run: pipenv run python test-pipenv.py

102
.github/workflows/e2e-tests.yml vendored Normal file
View File

@ -0,0 +1,102 @@
name: e2e tests
on:
push:
branches:
- main
paths-ignore:
- '**.md'
pull_request:
paths-ignore:
- '**.md'
jobs:
test-setup-python:
name: Test setup-python
runs-on: ${{ matrix.operating-system }}
strategy:
matrix:
operating-system: [ubuntu-20.04, windows-latest]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Run with setup-python 3.5
uses: ./
with:
python-version: 3.5
- name: Verify 3.5
run: python __tests__/verify-python.py 3.5
- name: Run with setup-python 3.6
uses: ./
with:
python-version: 3.6
- name: Verify 3.6
run: python __tests__/verify-python.py 3.6
- name: Run with setup-python 3.7
uses: ./
with:
python-version: 3.7
- name: Verify 3.7
run: python __tests__/verify-python.py 3.7
- name: Run with setup-python 3.8
uses: ./
with:
python-version: 3.8
- name: Verify 3.8
run: python __tests__/verify-python.py 3.8
- name: Run with setup-python 3.7.5
uses: ./
with:
python-version: 3.7.5
- name: Verify 3.7.5
run: python __tests__/verify-python.py 3.7.5
- name: Run with setup-python 3.6.7
uses: ./
with:
python-version: 3.6.7
- name: Verify 3.6.7
run: python __tests__/verify-python.py 3.6.7
- name: Run with setup-python 3.8.1
uses: ./
with:
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
- name: Run with setup-python ==3.8
uses: ./
with:
python-version: '==3.8'
- name: Verify ==3.8
run: python __tests__/verify-python.py 3.8
- name: Run with setup-python <3.11
uses: ./
with:
python-version: '<3.11'
- name: Verify <3.11
run: python __tests__/verify-python.py 3.10
- name: Run with setup-python >3.8
uses: ./
with:
python-version: '>3.8'
- name: Verify >3.8
run: python __tests__/verify-python.py 3.11

View File

@ -9,21 +9,6 @@ on:
- main - main
jobs: jobs:
test: call-licensed:
runs-on: ubuntu-latest name: Licensed
name: Check licenses uses: actions/reusable-workflows/.github/workflows/licensed.yml@main
steps:
- uses: actions/checkout@v3
- 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/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

@ -1,4 +1,5 @@
name: Release new action version name: Release new action version
on: on:
release: release:
types: [released] types: [released]
@ -20,8 +21,8 @@ jobs:
name: releaseNewActionVersion name: releaseNewActionVersion
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Update the ${{ env.TAG_NAME }} tag - name: Update the ${{ env.TAG_NAME }} tag
uses: actions/publish-action@v0.2.0 uses: actions/publish-action@v0.2.2
with: with:
source-tag: ${{ env.TAG_NAME }} source-tag: ${{ env.TAG_NAME }}
slack-webhook: ${{ secrets.SLACK_WEBHOOK }} slack-webhook: ${{ secrets.SLACK_WEBHOOK }}

View File

@ -1,5 +1,6 @@
name: Validate PyPy e2e name: Validate PyPy e2e
on:
on:
push: push:
branches: branches:
- main - main
@ -18,24 +19,24 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-latest] os: [macos-latest, windows-latest, ubuntu-20.04, ubuntu-latest]
pypy: pypy:
- 'pypy-2.7' - 'pypy-2.7'
- 'pypy-3.7' - 'pypy-3.7'
- 'pypy3.9' - 'pypy3.9'
- 'pypy-2.7-v7.3.4' - 'pypy-2.7-v7.3.4'
- 'pypy-3.7-v7.3.5' - 'pypy-3.7-v7.3.5'
- 'pypy-3.7-v7.3.4' - 'pypy-3.7-v7.3.4'
- 'pypy-3.7-v7.3.x' - 'pypy-3.7-v7.3.x'
- 'pypy-3.7-v7.x' - 'pypy-3.7-v7.x'
- 'pypy-2.7-v7.3.4rc1' - 'pypy-2.7-v7.3.4rc1'
- 'pypy-3.7-nightly' - 'pypy-3.7-nightly'
- 'pypy3.8-v7.3.7' - 'pypy3.8-v7.3.7'
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: setup-python ${{ matrix.pypy }} - name: setup-python ${{ matrix.pypy }}
id: setup-python id: setup-python
uses: ./ uses: ./
@ -48,7 +49,7 @@ jobs:
- name: PyPy and Python version - name: PyPy and Python version
run: python --version run: python --version
- name: Run simple code - name: Run simple code
run: python -c 'import math; print(math.factorial(5))' run: python -c 'import math; print(math.factorial(5))'
@ -72,7 +73,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-latest] os: [macos-latest, windows-latest, ubuntu-20.04, ubuntu-latest]
pypy: ['pypy2.7', 'pypy3.7', 'pypy3.8', 'pypy3.9-nightly'] pypy: ['pypy2.7', 'pypy3.7', 'pypy3.8', 'pypy3.9-nightly']
steps: steps:
@ -123,4 +124,46 @@ jobs:
EXECUTABLE=${EXECUTABLE/-/} # remove the first '-' in "pypy-X.Y" -> "pypyX.Y" to match executable name EXECUTABLE=${EXECUTABLE/-/} # remove the first '-' in "pypy-X.Y" -> "pypyX.Y" to match executable name
EXECUTABLE=${EXECUTABLE%%-*} # remove any -* suffixe EXECUTABLE=${EXECUTABLE%%-*} # remove any -* suffixe
${EXECUTABLE} --version ${EXECUTABLE} --version
shell: bash shell: bash
setup-pypy-multiple-versions:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/checkout@v3
- name: Setup PyPy and check latest
uses: ./
with:
python-version: |
pypy-3.7-v7.3.x
pypy3.8
check-latest: true
- 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="pypy-3.7-v7.3.x"
EXECUTABLE=${EXECUTABLE/-/} # remove the first '-' in "pypy-X.Y" -> "pypyX.Y" to match executable name
EXECUTABLE=${EXECUTABLE%%-*} # remove any -* suffixe
${EXECUTABLE} --version
shell: bash
- name: Assert expected binaries (or symlinks) are present
run: |
EXECUTABLE='pypy3.8'
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

View File

@ -1,4 +1,5 @@
name: Validate Python e2e name: Validate Python e2e
on: on:
push: push:
branches: branches:
@ -19,34 +20,43 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-20.04] os: [macos-latest, windows-latest, ubuntu-20.04, ubuntu-22.04]
python: [3.5.4, 3.6.7, 3.7.5, 3.8.1] python: [3.5.4, 3.6.7, 3.7.5, 3.8.15, 3.9.13]
exclude:
- os: ubuntu-22.04
python: 3.5.4
- os: ubuntu-22.04
python: 3.6.7
- os: ubuntu-22.04
python: 3.7.5
- os: windows-latest
python: 3.8.15
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: setup-python ${{ matrix.python }} - name: setup-python ${{ matrix.python }}
id: setup-python id: setup-python
uses: ./ uses: ./
with: with:
python-version: ${{ matrix.python }} python-version: ${{ matrix.python }}
- name: Check python-path - name: Check python-path
run: ./__tests__/check-python-path.sh '${{ steps.setup-python.outputs.python-path }}' run: ./__tests__/check-python-path.sh '${{ steps.setup-python.outputs.python-path }}'
shell: bash shell: bash
- name: Validate version - name: Validate version
run: | run: |
$pythonVersion = (python --version) $pythonVersion = (python --version)
if ("Python ${{ matrix.python }}" -ne "$pythonVersion"){ if ("Python ${{ matrix.python }}" -ne "$pythonVersion"){
Write-Host "The current version is $pythonVersion; expected version is ${{ matrix.python }}" Write-Host "The current version is $pythonVersion; expected version is ${{ matrix.python }}"
exit 1 exit 1
} }
$pythonVersion $pythonVersion
shell: pwsh shell: pwsh
- name: Run simple code - name: Run simple code
run: python -c 'import math; print(math.factorial(5))' run: python -c 'import math; print(math.factorial(5))'
setup-versions-from-file: setup-versions-from-file:
name: Setup ${{ matrix.python }} ${{ matrix.os }} version file name: Setup ${{ matrix.python }} ${{ matrix.os }} version file
@ -54,37 +64,191 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-20.04] os: [macos-latest, windows-latest, ubuntu-20.04, ubuntu-22.04]
python: [3.5.4, 3.6.7, 3.7.5, 3.8.1] python: [3.5.4, 3.6.7, 3.7.5, 3.8.15, 3.9.13]
exclude:
- os: ubuntu-22.04
python: 3.5.4
- os: ubuntu-22.04
python: 3.6.7
- os: ubuntu-22.04
python: 3.7.5
- os: windows-latest
python: 3.8.15
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: build-version-file ${{ matrix.python }} - name: build-version-file ${{ matrix.python }}
run: echo ${{ matrix.python }} > .python-version run: echo ${{ matrix.python }} > .python-version
- name: setup-python ${{ matrix.python }} - name: setup-python ${{ matrix.python }}
id: setup-python id: setup-python
uses: ./ uses: ./
with: with:
python-version-file: '.python-version' python-version-file: .python-version
- name: Check python-path - name: Check python-path
run: ./__tests__/check-python-path.sh '${{ steps.setup-python.outputs.python-path }}' run: ./__tests__/check-python-path.sh '${{ steps.setup-python.outputs.python-path }}'
shell: bash shell: bash
- name: Validate version - name: Validate version
run: | run: |
$pythonVersion = (python --version) $pythonVersion = (python --version)
if ("Python ${{ matrix.python }}" -ne "$pythonVersion"){ if ("Python ${{ matrix.python }}" -ne "$pythonVersion"){
Write-Host "The current version is $pythonVersion; expected version is ${{ matrix.python }}" Write-Host "The current version is $pythonVersion; expected version is ${{ matrix.python }}"
exit 1 exit 1
} }
$pythonVersion $pythonVersion
shell: pwsh shell: pwsh
- name: Run simple code - name: Run simple code
run: python -c 'import math; print(math.factorial(5))' run: python -c 'import math; print(math.factorial(5))'
setup-versions-from-file-without-parameter:
name: Setup ${{ matrix.python }} ${{ matrix.os }} version file without parameter
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-20.04, ubuntu-22.04]
python: [3.5.4, 3.6.7, 3.7.5, 3.8.15, 3.9.13]
exclude:
- os: ubuntu-22.04
python: 3.5.4
- os: ubuntu-22.04
python: 3.6.7
- os: ubuntu-22.04
python: 3.7.5
- os: windows-latest
python: 3.8.15
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: ./
- 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-standard-pyproject-file:
name: Setup ${{ matrix.python }} ${{ matrix.os }} standard pyproject file
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-20.04, ubuntu-22.04]
python: [3.5.4, 3.6.7, 3.7.5, 3.8.15, 3.9.13]
exclude:
- os: ubuntu-22.04
python: 3.5.4
- os: ubuntu-22.04
python: 3.6.7
- os: ubuntu-22.04
python: 3.7.5
- os: windows-latest
python: 3.8.15
steps:
- name: Checkout
uses: actions/checkout@v3
- name: build-version-file ${{ matrix.python }}
run: |
echo '[project]
requires-python = "${{ matrix.python }}"
' > pyproject.toml
- name: setup-python ${{ matrix.python }}
id: setup-python
uses: ./
with:
python-version-file: pyproject.toml
- 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-poetry-pyproject-file:
name: Setup ${{ matrix.python }} ${{ matrix.os }} poetry pyproject file
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-20.04, ubuntu-22.04]
python: [3.5.4, 3.6.7, 3.7.5, 3.8.15, 3.9.13]
exclude:
- os: ubuntu-22.04
python: 3.5.4
- os: ubuntu-22.04
python: 3.6.7
- os: ubuntu-22.04
python: 3.7.5
- os: windows-latest
python: 3.8.15
steps:
- name: Checkout
uses: actions/checkout@v3
- name: build-version-file ${{ matrix.python }}
run: |
echo '[tool.poetry.dependencies]
python = "${{ matrix.python }}"
' > pyproject.toml
- name: setup-python ${{ matrix.python }}
id: setup-python
uses: ./
with:
python-version-file: pyproject.toml
- 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-pre-release-version-from-manifest: setup-pre-release-version-from-manifest:
name: Setup 3.9.0-beta.4 ${{ matrix.os }} name: Setup 3.9.0-beta.4 ${{ matrix.os }}
@ -92,33 +256,33 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-20.04] os: [macos-latest, windows-latest, ubuntu-20.04]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: setup-python 3.9.0-beta.4 - name: setup-python 3.9.0-beta.4
id: setup-python id: setup-python
uses: ./ uses: ./
with: with:
python-version: '3.9.0-beta.4' python-version: '3.9.0-beta.4'
- name: Check python-path - name: Check python-path
run: ./__tests__/check-python-path.sh '${{ steps.setup-python.outputs.python-path }}' run: ./__tests__/check-python-path.sh '${{ steps.setup-python.outputs.python-path }}'
shell: bash shell: bash
- name: Validate version - name: Validate version
run: | run: |
$pythonVersion = (python --version) $pythonVersion = (python --version)
if ("Python 3.9.0b4" -ne "$pythonVersion"){ if ("Python 3.9.0b4" -ne "$pythonVersion"){
Write-Host "The current version is $pythonVersion; expected version is 3.9.0b4" Write-Host "The current version is $pythonVersion; expected version is 3.9.0b4"
exit 1 exit 1
} }
$pythonVersion $pythonVersion
shell: pwsh shell: pwsh
- name: Run simple code - name: Run simple code
run: python -c 'import math; print(math.factorial(5))' run: python -c 'import math; print(math.factorial(5))'
setup-dev-version: setup-dev-version:
name: Setup 3.9-dev ${{ matrix.os }} name: Setup 3.9-dev ${{ matrix.os }}
@ -128,25 +292,54 @@ jobs:
matrix: matrix:
os: [macos-latest, windows-latest, ubuntu-latest] os: [macos-latest, windows-latest, ubuntu-latest]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: setup-python 3.9-dev - name: setup-python 3.9-dev
id: setup-python id: setup-python
uses: ./ uses: ./
with: with:
python-version: '3.9-dev' python-version: '3.9-dev'
- name: Check python-path - name: Check python-path
run: ./__tests__/check-python-path.sh '${{ steps.setup-python.outputs.python-path }}' run: ./__tests__/check-python-path.sh '${{ steps.setup-python.outputs.python-path }}'
shell: bash shell: bash
- name: Validate version - name: Validate version
run: ${{ startsWith(steps.setup-python.outputs.python-version, '3.9.') }} run: ${{ startsWith(steps.setup-python.outputs.python-version, '3.9.') }}
shell: bash shell: bash
- name: Run simple code - name: Run simple code
run: python -c 'import math; print(math.factorial(5))' run: python -c 'import math; print(math.factorial(5))'
setup-prerelease-version:
name: Setup 3.12 ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: setup-python 3.12
id: setup-python
uses: ./
with:
python-version: '3.12'
allow-prereleases: true
- 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.12.') }}
shell: bash
- name: Run simple code
run: python -c 'import math; print(math.factorial(5))'
setup-versions-noenv: setup-versions-noenv:
name: Setup ${{ matrix.python }} ${{ matrix.os }} (noenv) name: Setup ${{ matrix.python }} ${{ matrix.os }} (noenv)
@ -154,24 +347,24 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [macos-latest, windows-latest, ubuntu-18.04, ubuntu-20.04] os: [macos-latest, windows-latest, ubuntu-20.04, ubuntu-22.04]
python: ["3.7", "3.8", "3.9", "3.10"] python: ['3.7', '3.8', '3.9', '3.10']
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: setup-python ${{ matrix.python }} - name: setup-python ${{ matrix.python }}
id: setup-python id: setup-python
uses: ./ uses: ./
with: with:
python-version: ${{ matrix.python }} python-version: ${{ matrix.python }}
update-environment: false update-environment: false
- name: Python version - name: Python version
run: ${{ steps.setup-python.outputs.python-path }} --version run: ${{ steps.setup-python.outputs.python-path }} --version
- name: Run simple code - name: Run simple code
run: ${{ steps.setup-python.outputs.python-path }} -c 'import math; print(math.factorial(5))' run: ${{ steps.setup-python.outputs.python-path }} -c 'import math; print(math.factorial(5))'
check-latest: check-latest:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
@ -179,7 +372,7 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest, macos-latest] os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ["3.8", "3.9", "3.10"] python-version: ['3.8', '3.9', '3.10']
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup Python and check latest - name: Setup Python and check latest
@ -190,9 +383,36 @@ jobs:
- name: Validate version - name: Validate version
run: | run: |
$pythonVersion = (python --version) $pythonVersion = (python --version)
if ("$pythonVersion" -NotMatch "${{ matrix.python }}"){ if ("$pythonVersion" -NotMatch "${{ matrix.python-version }}"){
Write-Host "The current version is $pythonVersion; expected version is ${{ matrix.python }}" Write-Host "The current version is $pythonVersion; expected version is ${{ matrix.python-version }}"
exit 1 exit 1
} }
$pythonVersion $pythonVersion
shell: pwsh shell: pwsh
setup-python-multiple-python-versions:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/checkout@v3
- name: Setup Python and check latest
uses: ./
with:
python-version: |
3.7
3.8
3.9
3.10
check-latest: true
- name: Validate version
run: |
$pythonVersion = (python --version)
if ("$pythonVersion" -NotMatch "3.10"){
Write-Host "The current version is $pythonVersion; expected version is 3.10"
exit 1
}
$pythonVersion
shell: pwsh

View File

@ -0,0 +1,11 @@
name: Update configuration files
on:
schedule:
- cron: '0 3 * * 0'
workflow_dispatch:
jobs:
call-update-configuration-files:
name: Update configuration files
uses: actions/reusable-workflows/.github/workflows/update-config-files.yml@main

View File

@ -1,101 +0,0 @@
name: Main workflow
on:
push:
branches:
- main
paths-ignore:
- '**.md'
pull_request:
paths-ignore:
- '**.md'
jobs:
run:
name: Run
runs-on: ${{ matrix.operating-system }}
strategy:
matrix:
operating-system: [ubuntu-latest, windows-latest]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set Node.js 16.x
uses: actions/setup-node@v3
with:
node-version: 16.x
cache: npm
- name: npm ci
run: npm ci
- name: Lint
run: npm run format-check
- name: npm test
run: npm test
- name: Run with setup-python 2.7
uses: ./
with:
python-version: 2.7
- name: Verify 2.7
run: python __tests__/verify-python.py 2.7
- name: Run with setup-python 3.5
uses: ./
with:
python-version: 3.5
- name: Verify 3.5
run: python __tests__/verify-python.py 3.5
- name: Run with setup-python 3.6
uses: ./
with:
python-version: 3.6
- name: Verify 3.6
run: python __tests__/verify-python.py 3.6
- name: Run with setup-python 3.7
uses: ./
with:
python-version: 3.7
- name: Verify 3.7
run: python __tests__/verify-python.py 3.7
- name: Run with setup-python 3.8
uses: ./
with:
python-version: 3.8
- name: Verify 3.8
run: python __tests__/verify-python.py 3.8
- name: Run with setup-python 3.7.5
uses: ./
with:
python-version: 3.7.5
- name: Verify 3.7.5
run: python __tests__/verify-python.py 3.7.5
- name: Run with setup-python 3.6.7
uses: ./
with:
python-version: 3.6.7
- name: Verify 3.6.7
run: python __tests__/verify-python.py 3.6.7
- name: Run with setup-python 3.8.1
uses: ./
with:
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" name: "@actions/cache"
version: 3.0.4 version: 3.1.4
type: npm type: npm
summary: Actions cache lib summary: Actions cache lib
homepage: https://github.com/actions/toolkit/tree/main/packages/cache homepage: https://github.com/actions/toolkit/tree/main/packages/cache

View File

@ -1,9 +1,9 @@
--- ---
name: "@actions/http-client" name: "@actions/http-client"
version: 2.0.1 version: 2.1.0
type: npm type: npm
summary: Actions Http Client summary: Actions Http Client
homepage: https://github.com/actions/http-client#readme homepage: https://github.com/actions/toolkit/tree/main/packages/http-client
license: mit license: mit
licenses: licenses:
- sources: LICENSE - sources: LICENSE

View File

@ -1,9 +1,9 @@
--- ---
name: "@azure/abort-controller" name: "@azure/abort-controller"
version: 1.0.4 version: 1.1.0
type: npm type: npm
summary: Microsoft Azure SDK for JavaScript - Aborter summary: Microsoft Azure SDK for JavaScript - Aborter
homepage: https://github.com/Azure/azure-sdk-for-js/tree/master/sdk/core/abort-controller/README.md homepage: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/abort-controller/README.md
license: mit license: mit
licenses: licenses:
- sources: LICENSE - sources: LICENSE

View File

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

View File

@ -1,16 +1,16 @@
--- ---
name: ip-regex name: "@azure/core-util"
version: 2.1.0 version: 1.3.1
type: npm type: npm
summary: Regular expression for matching IP addresses (IPv4 & IPv6) summary: Core library for shared utility methods
homepage: https://github.com/sindresorhus/ip-regex#readme homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-util/
license: mit license: mit
licenses: licenses:
- sources: license - sources: LICENSE
text: | text: |
The MIT License (MIT) The MIT License (MIT)
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com) Copyright (c) 2020 Microsoft
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -19,16 +19,14 @@ licenses:
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in The above copyright notice and this permission notice shall be included in all
all copies or substantial portions of the Software. copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 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 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
THE SOFTWARE. SOFTWARE.
- sources: readme.md
text: MIT © [Sindre Sorhus](https://sindresorhus.com)
notices: [] notices: []

View File

@ -1,6 +1,6 @@
--- ---
name: "@azure/ms-rest-js" name: "@azure/ms-rest-js"
version: 2.6.0 version: 2.7.0
type: npm type: npm
summary: Isomorphic client Runtime for Typescript/node.js/browser javascript client summary: Isomorphic client Runtime for Typescript/node.js/browser javascript client
libraries generated using AutoRest libraries generated using AutoRest

View File

@ -1,6 +1,6 @@
--- ---
name: "@azure/storage-blob" name: "@azure/storage-blob"
version: 12.8.0 version: 12.14.0
type: npm type: npm
summary: Microsoft Azure Storage SDK for JavaScript - Blob summary: Microsoft Azure Storage SDK for JavaScript - Blob
homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/storage/storage-blob/ homepage: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/storage/storage-blob/

26
.licenses/npm/@iarna/toml.dep.yml generated Normal file
View File

@ -0,0 +1,26 @@
---
name: "@iarna/toml"
version: 2.2.5
type: npm
summary: Better TOML parsing and stringifying all in that familiar JSON interface.
homepage: https://github.com/iarna/iarna-toml#readme
license: isc
licenses:
- sources: LICENSE
text: |+
Copyright (c) 2016, Rebecca Turner <me@re-becca.org>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
notices: []
...

View File

@ -1,6 +1,6 @@
--- ---
name: "@types/node-fetch" name: "@types/node-fetch"
version: 2.5.12 version: 2.6.3
type: npm type: npm
summary: TypeScript definitions for node-fetch summary: TypeScript definitions for node-fetch
homepage: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node-fetch homepage: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node-fetch

26
.licenses/npm/lru-cache.dep.yml generated Normal file
View File

@ -0,0 +1,26 @@
---
name: lru-cache
version: 6.0.0
type: npm
summary: A cache object that deletes the least-recently-used items.
homepage:
license: isc
licenses:
- sources: LICENSE
text: |
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
notices: []

View File

@ -1,6 +1,6 @@
--- ---
name: minimatch name: minimatch
version: 3.0.4 version: 3.1.2
type: npm type: npm
summary: a glob matcher in javascript summary: a glob matcher in javascript
homepage: https://github.com/isaacs/minimatch#readme homepage: https://github.com/isaacs/minimatch#readme

View File

@ -1,43 +0,0 @@
---
name: psl
version: 1.8.0
type: npm
summary: Domain name parser based on the Public Suffix List
homepage: https://github.com/lupomontero/psl#readme
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License (MIT)
Copyright (c) 2017 Lupo Montero lupomontero@gmail.com
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.
- sources: README.md
text: |-
The MIT License (MIT)
Copyright (c) 2017 Lupo Montero <lupomontero@gmail.com>
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,34 +0,0 @@
---
name: punycode
version: 2.1.1
type: npm
summary: A robust Punycode converter that fully complies to RFC 3492 and RFC 5891,
and works on nearly all JavaScript platforms.
homepage: https://mths.be/punycode
license: mit
licenses:
- sources: LICENSE-MIT.txt
text: |
Copyright Mathias Bynens <https://mathiasbynens.be/>
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.
- sources: README.md
text: Punycode.js is available under the [MIT](https://mths.be/mit) license.
notices: []

View File

@ -1,9 +1,9 @@
--- ---
name: semver name: semver
version: 7.1.3 version: 7.5.2
type: npm type: npm
summary: The semantic version parser used by npm. summary: The semantic version parser used by npm.
homepage: https://github.com/npm/node-semver#readme homepage:
license: isc license: isc
licenses: licenses:
- sources: LICENSE - sources: LICENSE

View File

@ -1,23 +0,0 @@
---
name: tough-cookie
version: 3.0.1
type: npm
summary: RFC6265 Cookies and Cookie Jar for node.js
homepage: https://github.com/salesforce/tough-cookie
license: bsd-3-clause
licenses:
- sources: LICENSE
text: |
Copyright (c) 2015, Salesforce.com, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of Salesforce.com nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
notices: []

View File

@ -1,23 +0,0 @@
---
name: tough-cookie
version: 4.0.0
type: npm
summary: RFC6265 Cookies and Cookie Jar for node.js
homepage: https://github.com/salesforce/tough-cookie
license: bsd-3-clause
licenses:
- sources: LICENSE
text: |
Copyright (c) 2015, Salesforce.com, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of Salesforce.com nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
notices: []

35
.licenses/npm/tslib-2.5.0.dep.yml generated Normal file
View File

@ -0,0 +1,35 @@
---
name: tslib
version: 2.5.0
type: npm
summary: Runtime library for TypeScript helper functions
homepage: https://www.typescriptlang.org/
license: 0bsd
licenses:
- sources: LICENSE.txt
text: |-
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
notices:
- sources: CopyrightNotice.txt
text: "/******************************************************************************\r\nCopyright
(c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute
this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE
SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE,
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS
SOFTWARE.\r\n*****************************************************************************
*/"

View File

@ -1,33 +0,0 @@
---
name: universalify
version: 0.1.2
type: npm
summary: Make a callback- or promise-based function support both promises and callbacks.
homepage: https://github.com/RyanZim/universalify#readme
license: mit
licenses:
- sources: LICENSE
text: |
(The MIT License)
Copyright (c) 2017, Ryan Zimmerman <opensrc@ryanzim.com>
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.
- sources: README.md
text: MIT
notices: []

View File

@ -1,6 +1,6 @@
--- ---
name: xml2js name: xml2js
version: 0.4.23 version: 0.5.0
type: npm type: npm
summary: Simple XML to JavaScript object converter. summary: Simple XML to JavaScript object converter.
homepage: https://github.com/Leonidas-from-XIV/node-xml2js homepage: https://github.com/Leonidas-from-XIV/node-xml2js

26
.licenses/npm/yallist.dep.yml generated Normal file
View File

@ -0,0 +1,26 @@
---
name: yallist
version: 4.0.0
type: npm
summary: Yet Another Linked List
homepage:
license: isc
licenses:
- sources: LICENSE
text: |
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
notices: []

7
.prettierignore Normal file
View File

@ -0,0 +1,7 @@
# Ignore list
/*
# Do not ignore these folders:
!__tests__/
!.github/
!src/

11
.prettierrc.js Normal file
View File

@ -0,0 +1,11 @@
// This is a reusable configuration file copied from https://github.com/actions/reusable-workflows/tree/main/reusable-configurations. Please don't make changes to this file as it's the subject of an automatic update.
module.exports = {
printWidth: 80,
tabWidth: 2,
useTabs: false,
semi: true,
singleQuote: true,
trailingComma: 'none',
bracketSpacing: false,
arrowParens: 'avoid'
};

View File

@ -1,11 +0,0 @@
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"trailingComma": "none",
"bracketSpacing": false,
"arrowParens": "avoid",
"parser": "typescript"
}

View File

@ -1,8 +1,9 @@
# setup-python # setup-python
<p align="left"> [![Basic validation](https://github.com/actions/setup-python/actions/workflows/basic-validation.yml/badge.svg?branch=main)](https://github.com/actions/setup-python/actions/workflows/basic-validation.yml)
<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> [![Validate Python e2e](https://github.com/actions/setup-python/actions/workflows/test-python.yml/badge.svg?branch=main)](https://github.com/actions/setup-python/actions/workflows/test-python.yml)
</p> [![Validate PyPy e2e](https://github.com/actions/setup-python/actions/workflows/test-pypy.yml/badge.svg?branch=main)](https://github.com/actions/setup-python/actions/workflows/test-pypy.yml)
[![e2e-cache](https://github.com/actions/setup-python/actions/workflows/e2e-cache.yml/badge.svg?branch=main)](https://github.com/actions/setup-python/actions/workflows/e2e-cache.yml)
This action provides the following functionality for GitHub Actions users: This action provides the following functionality for GitHub Actions users:
@ -33,7 +34,7 @@ steps:
python-version: 'pypy3.9' python-version: 'pypy3.9'
- run: python my_script.py - run: python my_script.py
``` ```
The `python-version` input is optional. If not supplied, the action will try to resolve the version from the default `.python-version` file. If the `.python-version` file doesn't exist Python or PyPy version from the PATH will be used. The default version of Python or PyPy in PATH varies between runners and can be changed unexpectedly so we recommend always using `setup-python`. The `python-version` input is optional. If not supplied, the action will try to resolve the version from the default `.python-version` file. If the `.python-version` file doesn't exist Python or PyPy version from the PATH will be used. The default version of Python or PyPy in PATH varies between runners and can be changed unexpectedly so we recommend always setting Python version explicitly using the `python-version` or `python-version-file` inputs.
The action will first check the local [tool cache](docs/advanced-usage.md#hosted-tool-cache) for a [semver](https://github.com/npm/node-semver#versions) match. If unable to find a specific version in the tool cache, the action will attempt to download a version of Python from [GitHub Releases](https://github.com/actions/python-versions/releases) and for PyPy from the official [PyPy's dist](https://downloads.python.org/pypy/). The action will first check the local [tool cache](docs/advanced-usage.md#hosted-tool-cache) for a [semver](https://github.com/npm/node-semver#versions) match. If unable to find a specific version in the tool cache, the action will attempt to download a version of Python from [GitHub Releases](https://github.com/actions/python-versions/releases) and for PyPy from the official [PyPy's dist](https://downloads.python.org/pypy/).
@ -51,11 +52,11 @@ Using `architecture` input it is possible to specify the required Python or PyPy
The action has built-in functionality for caching and restoring dependencies. It uses [toolkit/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 has built-in functionality for caching and restoring dependencies. It uses [toolkit/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, `Pipfile.lock` for pipenv or `poetry.lock` for poetry) in the repository, and uses its hash as a part of the cache key. Input `cache-dependency-path` is used for cases when multiple dependency files are used, they are located in different subdirectories or different files for the hash that want to be used. The action defaults to searching for a dependency file (`requirements.txt` or `pyproject.toml` 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. Input `cache-dependency-path` is used for cases when multiple dependency files are used, they are located in different subdirectories or different files for the hash that want to be used.
- For `pip`, the action will cache the global cache directory - For `pip`, the action will cache the global cache directory
- For `pipenv`, the action will cache virtualenv directory - For `pipenv`, the action will cache virtualenv directory
- For `poetry`, the action will cache virtualenv directory - For `poetry`, the action will cache virtualenv directories -- one for each poetry project found
**Caching pip dependencies:** **Caching pip dependencies:**
@ -85,6 +86,7 @@ See examples of using `cache` and `cache-dependency-path` for `pipenv` and `poet
- [Hosted tool cache](docs/advanced-usage.md#hosted-tool-cache) - [Hosted tool cache](docs/advanced-usage.md#hosted-tool-cache)
- [Using `setup-python` with a self-hosted runner](docs/advanced-usage.md#using-setup-python-with-a-self-hosted-runner) - [Using `setup-python` with a self-hosted runner](docs/advanced-usage.md#using-setup-python-with-a-self-hosted-runner)
- [Using `setup-python` on GHES](docs/advanced-usage.md#using-setup-python-on-ghes) - [Using `setup-python` on GHES](docs/advanced-usage.md#using-setup-python-on-ghes)
- [Allow pre-releases](docs/advanced-usage.md#allow-pre-releases)
## License ## License

View File

@ -1,19 +1,20 @@
import * as path from 'path';
import * as core from '@actions/core'; import * as core from '@actions/core';
import * as cache from '@actions/cache'; import * as cache from '@actions/cache';
import * as exec from '@actions/exec'; import * as exec from '@actions/exec';
import * as io from '@actions/io'; import * as io from '@actions/io';
import {getCacheDistributor} from '../src/cache-distributions/cache-factory'; import {getCacheDistributor} from '../src/cache-distributions/cache-factory';
import * as utils from './../src/utils'; import {State} from '../src/cache-distributions/cache-distributor';
describe('restore-cache', () => { describe('restore-cache', () => {
const pipFileLockHash = const pipFileLockHash =
'a3bdcc71289e4979ca9e051810d81999cc99823109faf6912e17ff14c8e621a6'; 'f8428d7cf00ea53a5c3702f0a9cb3cc467f76cd86a34723009350c4e4b32751a';
const requirementsHash = const requirementsHash =
'd8110e0006d7fb5ee76365d565eef9d37df1d11598b912d3eb66d398d57a1121'; 'd8110e0006d7fb5ee76365d565eef9d37df1d11598b912d3eb66d398d57a1121';
const requirementsLinuxHash = const requirementsLinuxHash =
'2d0ff7f46b0e120e3d3294db65768b474934242637b9899b873e6283dfd16d7c'; '2d0ff7f46b0e120e3d3294db65768b474934242637b9899b873e6283dfd16d7c';
const poetryLockHash = const poetryLockHash =
'571bf984f8d210e6a97f854e479fdd4a2b5af67b5fdac109ec337a0ea16e7836'; 'f24ea1ad73968e6c8d80c16a093ade72d9332c433aeef979a0dd943e6a99b2ab';
const poetryConfigOutput = ` const poetryConfigOutput = `
cache-dir = "/Users/patrick/Library/Caches/pypoetry" cache-dir = "/Users/patrick/Library/Caches/pypoetry"
experimental.new-installer = false experimental.new-installer = false
@ -27,10 +28,9 @@ virtualenvs.path = "{cache-dir}/virtualenvs" # /Users/patrick/Library/Caches/py
let infoSpy: jest.SpyInstance; let infoSpy: jest.SpyInstance;
let warningSpy: jest.SpyInstance; let warningSpy: jest.SpyInstance;
let debugSpy: jest.SpyInstance; let debugSpy: jest.SpyInstance;
let saveSatetSpy: jest.SpyInstance; let saveStateSpy: jest.SpyInstance;
let getStateSpy: jest.SpyInstance; let getStateSpy: jest.SpyInstance;
let setOutputSpy: jest.SpyInstance; let setOutputSpy: jest.SpyInstance;
let getLinuxOSReleaseInfoSpy: jest.SpyInstance;
// cache spy // cache spy
let restoreCacheSpy: jest.SpyInstance; let restoreCacheSpy: jest.SpyInstance;
@ -53,8 +53,8 @@ virtualenvs.path = "{cache-dir}/virtualenvs" # /Users/patrick/Library/Caches/py
debugSpy = jest.spyOn(core, 'debug'); debugSpy = jest.spyOn(core, 'debug');
debugSpy.mockImplementation(input => undefined); debugSpy.mockImplementation(input => undefined);
saveSatetSpy = jest.spyOn(core, 'saveState'); saveStateSpy = jest.spyOn(core, 'saveState');
saveSatetSpy.mockImplementation(input => undefined); saveStateSpy.mockImplementation(input => undefined);
getStateSpy = jest.spyOn(core, 'getState'); getStateSpy = jest.spyOn(core, 'getState');
getStateSpy.mockImplementation(input => undefined); getStateSpy.mockImplementation(input => undefined);
@ -67,6 +67,9 @@ virtualenvs.path = "{cache-dir}/virtualenvs" # /Users/patrick/Library/Caches/py
if (input.includes('poetry')) { if (input.includes('poetry')) {
return {stdout: poetryConfigOutput, stderr: '', exitCode: 0}; return {stdout: poetryConfigOutput, stderr: '', exitCode: 0};
} }
if (input.includes('lsb_release')) {
return {stdout: 'Ubuntu\n20.04', stderr: '', exitCode: 0};
}
return {stdout: '', stderr: 'Error occured', exitCode: 2}; return {stdout: '', stderr: 'Error occured', exitCode: 2};
}); });
@ -83,7 +86,6 @@ virtualenvs.path = "{cache-dir}/virtualenvs" # /Users/patrick/Library/Caches/py
whichSpy = jest.spyOn(io, 'which'); whichSpy = jest.spyOn(io, 'which');
whichSpy.mockImplementation(() => '/path/to/python'); whichSpy.mockImplementation(() => '/path/to/python');
getLinuxOSReleaseInfoSpy = jest.spyOn(utils, 'getLinuxOSReleaseInfo');
}); });
describe('Validate provided package manager', () => { describe('Validate provided package manager', () => {
@ -92,45 +94,103 @@ virtualenvs.path = "{cache-dir}/virtualenvs" # /Users/patrick/Library/Caches/py
async packageManager => { async packageManager => {
expect(() => expect(() =>
getCacheDistributor(packageManager, '3.8.12', undefined) getCacheDistributor(packageManager, '3.8.12', undefined)
).toThrowError(`Caching for '${packageManager}' is not supported`); ).toThrow(`Caching for '${packageManager}' is not supported`);
} }
); );
}); });
describe('Restore dependencies', () => { describe('Restore dependencies', () => {
it.each([ it.each([
['pip', '3.8.12', undefined, requirementsHash], [
['pip', '3.8.12', '**/requirements-linux.txt', requirementsLinuxHash], 'pip',
'3.8.12',
'__tests__/data/**/requirements.txt',
requirementsHash,
undefined
],
[
'pip',
'3.8.12',
'__tests__/data/**/requirements-linux.txt',
requirementsLinuxHash,
undefined
],
[ [
'pip', 'pip',
'3.8.12', '3.8.12',
'__tests__/data/requirements-linux.txt', '__tests__/data/requirements-linux.txt',
requirementsLinuxHash requirementsLinuxHash,
undefined
], ],
['pip', '3.8.12', '__tests__/data/requirements.txt', requirementsHash], [
['pipenv', '3.9.1', undefined, pipFileLockHash], 'pip',
['pipenv', '3.9.12', '__tests__/data/requirements.txt', requirementsHash], '3.8.12',
['poetry', '3.9.1', undefined, poetryLockHash] '__tests__/data/requirements.txt',
requirementsHash,
undefined
],
[
'pipenv',
'3.9.1',
'__tests__/data/**/Pipfile.lock',
pipFileLockHash,
undefined
],
[
'pipenv',
'3.9.12',
'__tests__/data/requirements.txt',
requirementsHash,
undefined
],
[
'poetry',
'3.9.1',
'__tests__/data/**/poetry.lock',
poetryLockHash,
[
'/Users/patrick/Library/Caches/pypoetry/virtualenvs',
path.join(__dirname, 'data', 'inner', '.venv'),
path.join(__dirname, 'data', '.venv')
]
]
])( ])(
'restored dependencies for %s by primaryKey', 'restored dependencies for %s by primaryKey',
async (packageManager, pythonVersion, dependencyFile, fileHash) => { async (
packageManager,
pythonVersion,
dependencyFile,
fileHash,
cachePaths
) => {
restoreCacheSpy.mockImplementation(
(cachePaths: string[], primaryKey: string, restoreKey?: string) => {
return primaryKey.includes(fileHash) ? primaryKey : '';
}
);
const cacheDistributor = getCacheDistributor( const cacheDistributor = getCacheDistributor(
packageManager, packageManager,
pythonVersion, pythonVersion,
dependencyFile dependencyFile
); );
if (process.platform === 'linux') { await cacheDistributor.restoreCache();
getLinuxOSReleaseInfoSpy.mockImplementation(() =>
Promise.resolve('Ubuntu-20.4') if (cachePaths !== undefined) {
expect(saveStateSpy).toHaveBeenCalledWith(
State.CACHE_PATHS,
cachePaths
); );
} }
await cacheDistributor.restoreCache();
if (process.platform === 'linux' && packageManager === 'pip') { if (process.platform === 'linux' && packageManager === 'pip') {
expect(infoSpy).toHaveBeenCalledWith( expect(infoSpy).toHaveBeenCalledWith(
`Cache restored from key: setup-python-${process.env['RUNNER_OS']}-Ubuntu-20.4-python-${pythonVersion}-${packageManager}-${fileHash}` `Cache restored from key: setup-python-${process.env['RUNNER_OS']}-20.04-Ubuntu-python-${pythonVersion}-${packageManager}-${fileHash}`
);
} else if (packageManager === 'poetry') {
expect(infoSpy).toHaveBeenCalledWith(
`Cache restored from key: setup-python-${process.env['RUNNER_OS']}-python-${pythonVersion}-${packageManager}-v2-${fileHash}`
); );
} else { } else {
expect(infoSpy).toHaveBeenCalledWith( expect(infoSpy).toHaveBeenCalledWith(
@ -141,11 +201,7 @@ virtualenvs.path = "{cache-dir}/virtualenvs" # /Users/patrick/Library/Caches/py
30000 30000
); );
it.each([ it.each([['pipenv', '3.9.12', 'requirements.txt', 'requirements.txt']])(
['pip', '3.8.12', 'requirements-linux.txt', 'requirements-linux.txt'],
['pip', '3.8.12', 'requirements.txt', 'requirements.txt'],
['pipenv', '3.9.12', 'requirements.txt', 'requirements.txt']
])(
'Should throw an error because dependency file is not found', 'Should throw an error because dependency file is not found',
async ( async (
packageManager, packageManager,
@ -158,19 +214,58 @@ virtualenvs.path = "{cache-dir}/virtualenvs" # /Users/patrick/Library/Caches/py
pythonVersion, pythonVersion,
dependencyFile dependencyFile
); );
await expect(cacheDistributor.restoreCache()).rejects.toThrowError(
await expect(cacheDistributor.restoreCache()).rejects.toThrow(
`No file in ${process.cwd()} matched to [${cacheDependencyPath `No file in ${process.cwd()} matched to [${cacheDependencyPath
.split('\n') .split('\n')
.join(',')}], make sure you have checked out the target repository` .join(',')}], make sure you have checked out the target repository`
); );
} }
); );
it.each([
['pip', '3.8.12', 'requirements-linux.txt'],
['pip', '3.8.12', 'requirements.txt']
])(
'Shouldn`t throw an error as there is a default file `pyproject.toml` to use when requirements.txt is not specified',
async (packageManager, pythonVersion, dependencyFile) => {
const cacheDistributor = getCacheDistributor(
packageManager,
pythonVersion,
dependencyFile
);
await expect(cacheDistributor.restoreCache()).resolves.not.toThrow();
}
);
it.each([
['pip', '3.8.12', 'requirements-linux.txt'],
['pip', '3.8.12', 'requirements.txt']
])(
'Should throw an error as there is no default file `pyproject.toml` to use when requirements.txt is not specified',
async (packageManager, pythonVersion, dependencyFile) => {
const cacheDistributor = getCacheDistributor(
packageManager,
pythonVersion,
dependencyFile
) as any; // Widening PipCache | PipenvCache | PoetryCache type to any allow us to change private property on the cacheDistributor to test value: "**/pyprojecttest.toml"
cacheDistributor.cacheDependencyBackupPath = '**/pyprojecttest.toml';
await expect(cacheDistributor.restoreCache()).rejects.toThrow();
}
);
}); });
describe('Dependencies changed', () => { describe('Dependencies changed', () => {
it.each([ it.each([
['pip', '3.8.12', undefined, pipFileLockHash], ['pip', '3.8.12', '__tests__/data/**/requirements.txt', pipFileLockHash],
['pip', '3.8.12', '**/requirements-linux.txt', pipFileLockHash], [
'pip',
'3.8.12',
'__tests__/data/**/requirements-linux.txt',
pipFileLockHash
],
[ [
'pip', 'pip',
'3.8.12', '3.8.12',
@ -178,9 +273,9 @@ virtualenvs.path = "{cache-dir}/virtualenvs" # /Users/patrick/Library/Caches/py
pipFileLockHash pipFileLockHash
], ],
['pip', '3.8.12', '__tests__/data/requirements.txt', pipFileLockHash], ['pip', '3.8.12', '__tests__/data/requirements.txt', pipFileLockHash],
['pipenv', '3.9.1', undefined, requirementsHash], ['pipenv', '3.9.1', '__tests__/data/**/Pipfile.lock', 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] ['poetry', '3.9.1', '__tests__/data/**/poetry.lock', requirementsHash]
])( ])(
'restored dependencies for %s by primaryKey', 'restored dependencies for %s by primaryKey',
async (packageManager, pythonVersion, dependencyFile, fileHash) => { async (packageManager, pythonVersion, dependencyFile, fileHash) => {

View File

@ -18,7 +18,7 @@ describe('run', () => {
let infoSpy: jest.SpyInstance; let infoSpy: jest.SpyInstance;
let warningSpy: jest.SpyInstance; let warningSpy: jest.SpyInstance;
let debugSpy: jest.SpyInstance; let debugSpy: jest.SpyInstance;
let saveSatetSpy: jest.SpyInstance; let saveStateSpy: jest.SpyInstance;
let getStateSpy: jest.SpyInstance; let getStateSpy: jest.SpyInstance;
let getInputSpy: jest.SpyInstance; let getInputSpy: jest.SpyInstance;
let setFailedSpy: jest.SpyInstance; let setFailedSpy: jest.SpyInstance;
@ -43,8 +43,8 @@ describe('run', () => {
debugSpy = jest.spyOn(core, 'debug'); debugSpy = jest.spyOn(core, 'debug');
debugSpy.mockImplementation(input => undefined); debugSpy.mockImplementation(input => undefined);
saveSatetSpy = jest.spyOn(core, 'saveState'); saveStateSpy = jest.spyOn(core, 'saveState');
saveSatetSpy.mockImplementation(input => undefined); saveStateSpy.mockImplementation(input => undefined);
getStateSpy = jest.spyOn(core, 'getState'); getStateSpy = jest.spyOn(core, 'getState');
getStateSpy.mockImplementation(input => { getStateSpy.mockImplementation(input => {
@ -87,6 +87,7 @@ describe('run', () => {
describe('Validate unchanged cache is not saved', () => { describe('Validate unchanged cache is not saved', () => {
it('should not save cache for pip', async () => { it('should not save cache for pip', async () => {
inputs['cache'] = 'pip'; inputs['cache'] = 'pip';
inputs['python-version'] = '3.10.0';
await run(); await run();
@ -103,22 +104,7 @@ describe('run', () => {
it('should not save cache for pipenv', async () => { it('should not save cache for pipenv', async () => {
inputs['cache'] = 'pipenv'; inputs['cache'] = 'pipenv';
inputs['python-version'] = '3.10.0';
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();
});
it('should not save cache for pipenv', async () => {
inputs['cache'] = 'pipenv';
await run(); await run();
@ -137,6 +123,7 @@ describe('run', () => {
describe('action saves the cache', () => { describe('action saves the cache', () => {
it('saves cache from pip', async () => { it('saves cache from pip', async () => {
inputs['cache'] = 'pip'; inputs['cache'] = 'pip';
inputs['python-version'] = '3.10.0';
getStateSpy.mockImplementation((name: string) => { getStateSpy.mockImplementation((name: string) => {
if (name === State.CACHE_MATCHED_KEY) { if (name === State.CACHE_MATCHED_KEY) {
return requirementsHash; return requirementsHash;
@ -163,6 +150,7 @@ describe('run', () => {
it('saves cache from pipenv', async () => { it('saves cache from pipenv', async () => {
inputs['cache'] = 'pipenv'; inputs['cache'] = 'pipenv';
inputs['python-version'] = '3.10.0';
getStateSpy.mockImplementation((name: string) => { getStateSpy.mockImplementation((name: string) => {
if (name === State.CACHE_MATCHED_KEY) { if (name === State.CACHE_MATCHED_KEY) {
return pipFileLockHash; return pipFileLockHash;
@ -189,6 +177,7 @@ describe('run', () => {
it('saves cache from poetry', async () => { it('saves cache from poetry', async () => {
inputs['cache'] = 'poetry'; inputs['cache'] = 'poetry';
inputs['python-version'] = '3.10.0';
getStateSpy.mockImplementation((name: string) => { getStateSpy.mockImplementation((name: string) => {
if (name === State.CACHE_MATCHED_KEY) { if (name === State.CACHE_MATCHED_KEY) {
return poetryLockHash; return poetryLockHash;
@ -215,6 +204,7 @@ describe('run', () => {
it('saves with -1 cacheId , should not fail workflow', async () => { it('saves with -1 cacheId , should not fail workflow', async () => {
inputs['cache'] = 'poetry'; inputs['cache'] = 'poetry';
inputs['python-version'] = '3.10.0';
getStateSpy.mockImplementation((name: string) => { getStateSpy.mockImplementation((name: string) => {
if (name === State.STATE_CACHE_PRIMARY_KEY) { if (name === State.STATE_CACHE_PRIMARY_KEY) {
return poetryLockHash; return poetryLockHash;
@ -241,8 +231,9 @@ describe('run', () => {
expect(setFailedSpy).not.toHaveBeenCalled(); expect(setFailedSpy).not.toHaveBeenCalled();
}); });
it('saves with error from toolkit, should fail workflow', async () => { it('saves with error from toolkit, should not fail the workflow', async () => {
inputs['cache'] = 'npm'; inputs['cache'] = 'npm';
inputs['python-version'] = '3.10.0';
getStateSpy.mockImplementation((name: string) => { getStateSpy.mockImplementation((name: string) => {
if (name === State.STATE_CACHE_PRIMARY_KEY) { if (name === State.STATE_CACHE_PRIMARY_KEY) {
return poetryLockHash; return poetryLockHash;
@ -263,7 +254,7 @@ describe('run', () => {
expect(getStateSpy).toHaveBeenCalledTimes(3); expect(getStateSpy).toHaveBeenCalledTimes(3);
expect(infoSpy).not.toHaveBeenCalledWith(); expect(infoSpy).not.toHaveBeenCalledWith();
expect(saveCacheSpy).toHaveBeenCalled(); expect(saveCacheSpy).toHaveBeenCalled();
expect(setFailedSpy).toHaveBeenCalled(); expect(setFailedSpy).not.toHaveBeenCalled();
}); });
}); });

View File

@ -4,8 +4,8 @@ verify_ssl = true
name = "pypi" name = "pypi"
[packages] [packages]
flake8 = "==4.0.1" flake8 = "==6.0.0"
numpy = "==1.23.0" numpy = "==1.25.1"
[dev-packages] [dev-packages]

View File

@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "e9c37110984955621040e2dc8548c026eb8466c23db1b8e69430289b10be8938" "sha256": "dcea65dabfe8442466b5e9280ecab72cfa7bf555791ee0ad55b6e7255dca1f43"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": { "requires": {
@ -18,62 +18,66 @@
"default": { "default": {
"flake8": { "flake8": {
"hashes": [ "hashes": [
"sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d", "sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7",
"sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d" "sha256:c61007e76655af75e6785a931f452915b371dc48f56efd765247c8fe68f2b181"
], ],
"index": "pypi", "index": "pypi",
"version": "==4.0.1" "version": "==6.0.0"
}, },
"mccabe": { "mccabe": {
"hashes": [ "hashes": [
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325",
"sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"
], ],
"version": "==0.6.1" "markers": "python_version >= '3.6'",
"version": "==0.7.0"
}, },
"numpy": { "numpy": {
"hashes": [ "hashes": [
"sha256:092f5e6025813e64ad6d1b52b519165d08c730d099c114a9247c9bb635a2a450", "sha256:012097b5b0d00a11070e8f2e261128c44157a8689f7dedcf35576e525893f4fe",
"sha256:196cd074c3f97c4121601790955f915187736f9cf458d3ee1f1b46aff2b1ade0", "sha256:0d3fe3dd0506a28493d82dc3cf254be8cd0d26f4008a417385cbf1ae95b54004",
"sha256:1c29b44905af288b3919803aceb6ec7fec77406d8b08aaa2e8b9e63d0fe2f160", "sha256:0def91f8af6ec4bb94c370e38c575855bf1d0be8a8fbfba42ef9c073faf2cf19",
"sha256:2b2da66582f3a69c8ce25ed7921dcd8010d05e59ac8d89d126a299be60421171", "sha256:1a180429394f81c7933634ae49b37b472d343cccb5bb0c4a575ac8bbc433722f",
"sha256:5043bcd71fcc458dfb8a0fc5509bbc979da0131b9d08e3d5f50fb0bbb36f169a", "sha256:1d5d3c68e443c90b38fdf8ef40e60e2538a27548b39b12b73132456847f4b631",
"sha256:58bfd40eb478f54ff7a5710dd61c8097e169bc36cc68333d00a9bcd8def53b38", "sha256:20e1266411120a4f16fad8efa8e0454d21d00b8c7cee5b5ccad7565d95eb42dd",
"sha256:79a506cacf2be3a74ead5467aee97b81fca00c9c4c8b3ba16dbab488cd99ba10", "sha256:247d3ffdd7775bdf191f848be8d49100495114c82c2bd134e8d5d075fb386a1c",
"sha256:94b170b4fa0168cd6be4becf37cb5b127bd12a795123984385b8cd4aca9857e5", "sha256:35a9527c977b924042170a0887de727cd84ff179e478481404c5dc66b4170009",
"sha256:97a76604d9b0e79f59baeca16593c711fddb44936e40310f78bfef79ee9a835f", "sha256:38eb6548bb91c421261b4805dc44def9ca1a6eef6444ce35ad1669c0f1a3fc5d",
"sha256:98e8e0d8d69ff4d3fa63e6c61e8cfe2d03c29b16b58dbef1f9baa175bbed7860", "sha256:3d7abcdd85aea3e6cdddb59af2350c7ab1ed764397f8eec97a038ad244d2d105",
"sha256:ac86f407873b952679f5f9e6c0612687e51547af0e14ddea1eedfcb22466babd", "sha256:41a56b70e8139884eccb2f733c2f7378af06c82304959e174f8e7370af112e09",
"sha256:ae8adff4172692ce56233db04b7ce5792186f179c415c37d539c25de7298d25d", "sha256:4a90725800caeaa160732d6b31f3f843ebd45d6b5f3eec9e8cc287e30f2805bf",
"sha256:bd3fa4fe2e38533d5336e1272fc4e765cabbbde144309ccee8675509d5cd7b05", "sha256:6b82655dd8efeea69dbf85d00fca40013d7f503212bc5259056244961268b66e",
"sha256:d0d2094e8f4d760500394d77b383a1b06d3663e8892cdf5df3c592f55f3bff66", "sha256:6c6c9261d21e617c6dc5eacba35cb68ec36bb72adcff0dee63f8fbc899362588",
"sha256:d54b3b828d618a19779a84c3ad952e96e2c2311b16384e973e671aa5be1f6187", "sha256:77d339465dff3eb33c701430bcb9c325b60354698340229e1dff97745e6b3efa",
"sha256:d6ca8dabe696c2785d0c8c9b0d8a9b6e5fdbe4f922bde70d57fa1a2848134f95", "sha256:791f409064d0a69dd20579345d852c59822c6aa087f23b07b1b4e28ff5880fcb",
"sha256:d8cc87bed09de55477dba9da370c1679bd534df9baa171dd01accbb09687dac3", "sha256:9a3a9f3a61480cc086117b426a8bd86869c213fc4072e606f01c4e4b66eb92bf",
"sha256:f0f18804df7370571fb65db9b98bf1378172bd4e962482b857e612d1fec0f53e", "sha256:c1516db588987450b85595586605742879e50dcce923e8973f79529651545b57",
"sha256:f1d88ef79e0a7fa631bb2c3dda1ea46b32b1fe614e10fedd611d3d5398447f2f", "sha256:c40571fe966393b212689aa17e32ed905924120737194b5d5c1b20b9ed0fb171",
"sha256:f9c3fc2adf67762c9fe1849c859942d23f8d3e0bee7b5ed3d4a9c3eeb50a2f07", "sha256:d412c1697c3853c6fc3cb9751b4915859c7afe6a277c2bf00acf287d56c4e625",
"sha256:fc431493df245f3c627c0c05c2bd134535e7929dbe2e602b80e42bf52ff760bc", "sha256:d5154b1a25ec796b1aee12ac1b22f414f94752c5f94832f14d8d6c9ac40bcca6",
"sha256:fe8b9683eb26d2c4d5db32cd29b38fdcf8381324ab48313b5b69088e0e355379" "sha256:d736b75c3f2cb96843a5c7f8d8ccc414768d34b0a75f466c05f3a739b406f10b",
"sha256:e8f6049c4878cb16960fbbfb22105e49d13d752d4d8371b55110941fb3b17800",
"sha256:f76aebc3358ade9eacf9bc2bb8ae589863a4f911611694103af05346637df1b7",
"sha256:fd67b306320dcadea700a8f79b9e671e607f8696e98ec255915c0c6d6b818503"
], ],
"index": "pypi", "index": "pypi",
"version": "==1.23.0" "version": "==1.25.1"
}, },
"pycodestyle": { "pycodestyle": {
"hashes": [ "hashes": [
"sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20", "sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053",
"sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f" "sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"
], ],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "markers": "python_version >= '3.6'",
"version": "==2.8.0" "version": "==2.10.0"
}, },
"pyflakes": { "pyflakes": {
"hashes": [ "hashes": [
"sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c", "sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf",
"sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e" "sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd"
], ],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "markers": "python_version >= '3.6'",
"version": "==2.4.0" "version": "==3.0.1"
} }
}, },
"develop": {} "develop": {}

1
__tests__/data/inner/poetry.lock generated Symbolic link
View File

@ -0,0 +1 @@
../poetry.lock

View File

@ -0,0 +1 @@
../pyproject.toml

View File

@ -1,2 +1,2 @@
numpy==1.22.3 numpy==1.22.3
pandas==1.4.2 flake8==6.0.0

View File

@ -1,4 +1,94 @@
[ [
{
"pypy_version": "7.3.8rc2",
"python_version": "3.8.12",
"stable": false,
"latest_pypy": false,
"date": "2022-02-11",
"files": [
{
"filename": "pypy3.8-v7.3.8rc2-linux32.tar.bz2",
"arch": "i686",
"platform": "linux",
"download_url": "https://test.download.python.org/pypy/pypy3.8-v7.3.8rc2-linux32.tar.bz2"
},
{
"filename": "pypy3.8-v7.3.8rc2-linux64.tar.bz2",
"arch": "x64",
"platform": "linux",
"download_url": "https://test.download.python.org/pypy/pypy3.8-v7.3.8rc2-linux64.tar.bz2"
},
{
"filename": "pypy3.8-v7.3.8rc2-darwin64.tar.bz2",
"arch": "x64",
"platform": "darwin",
"download_url": "https://test.download.python.org/pypy/pypy3.8-v7.3.8rc2-darwin64.tar.bz2"
},
{
"filename": "pypy3.8-v7.3.8rc2-s390x.tar.bz2",
"arch": "s390x",
"platform": "linux",
"download_url": "https://test.download.python.org/pypy/pypy3.8-v7.3.8rc2-s390x.tar.bz2"
},
{
"filename": "pypy3.8-v7.3.8rc2-win64.zip",
"arch": "x64",
"platform": "win64",
"download_url": "https://test.download.python.org/pypy/pypy3.8-v7.3.8rc2-win64.zip"
},
{
"filename": "pypy3.8-v7.3.8rc2-win32.zip",
"arch": "x86",
"platform": "win32",
"download_url": "https://test.download.python.org/pypy/pypy3.8-v7.3.8rc2-win32.zip"
}
]
},
{
"pypy_version": "7.4.0rc1",
"python_version": "3.6.12",
"stable": false,
"latest_pypy": false,
"date": "2021-11-11",
"files": [
{
"filename": "pypy3.6-v7.4.0rc1-aarch64.tar.bz2",
"arch": "aarch64",
"platform": "linux",
"download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-aarch64.tar.bz2"
},
{
"filename": "pypy3.6-v7.4.0rc1-linux32.tar.bz2",
"arch": "i686",
"platform": "linux",
"download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-linux32.tar.bz2"
},
{
"filename": "pypy3.6-v7.4.0rc1-linux64.tar.bz2",
"arch": "x64",
"platform": "linux",
"download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-linux64.tar.bz2"
},
{
"filename": "pypy3.6-v7.4.0rc1-darwin64.tar.bz2",
"arch": "x64",
"platform": "darwin",
"download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-darwin64.tar.bz2"
},
{
"filename": "pypy3.6-v7.4.0rc1-win32.zip",
"arch": "x86",
"platform": "win32",
"download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-win32.zip"
},
{
"filename": "pypy3.6-v7.4.0rc1-s390x.tar.bz2",
"arch": "s390x",
"platform": "linux",
"download_url": "https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-s390x.tar.bz2"
}
]
},
{ {
"pypy_version": "7.3.3", "pypy_version": "7.3.3",
"python_version": "3.6.12", "python_version": "3.6.12",
@ -530,4 +620,4 @@
} }
] ]
} }
] ]

View File

@ -1,4 +1,29 @@
[ [
{
"version": "1.2.4-beta.2",
"stable": false,
"release_url": "https://github.com/actions/sometool/releases/tag/1.2.4-beta.2-20200402.5",
"files": [
{
"filename": "sometool-1.2.4-linux-x64.tar.gz",
"arch": "x64",
"platform": "linux",
"download_url": "https://github.com/actions/sometool/releases/tag/1.2.4-beta.2-20200402.5/sometool-1.2.4-linux-x64.tar.gz"
},
{
"filename": "sometool-1.2.4-darwin-x64.tar.gz",
"arch": "x64",
"platform": "darwin",
"download_url": "https://github.com/actions/sometool/releases/tag/1.2.4-beta.2-20200402.5/sometool-1.2.4-darwin-x64.tar.gz"
},
{
"filename": "sometool-1.2.4-win32-x64.tar.gz",
"arch": "x64",
"platform": "win32",
"download_url": "https://github.com/actions/sometool/releases/tag/1.2.4-beta.2-20200402.5/sometool-1.2.4-win32-x64.tar.gz"
}
]
},
{ {
"version": "1.2.3", "version": "1.2.3",
"stable": true, "stable": true,
@ -25,28 +50,28 @@
] ]
}, },
{ {
"version": "1.2.3-beta.2", "version": "1.1.0-beta.2",
"stable": false, "stable": false,
"release_url": "https://github.com/actions/sometool/releases/tag/1.2.3-beta.2-20200402.5", "release_url": "https://github.com/actions/sometool/releases/tag/1.1.0-beta.2-20200402.5",
"files": [ "files": [
{ {
"filename": "sometool-1.2.3-linux-x64.tar.gz", "filename": "sometool-1.1.0-linux-x64.tar.gz",
"arch": "x64", "arch": "x64",
"platform": "linux", "platform": "linux",
"download_url": "https://github.com/actions/sometool/releases/tag/1.2.3-beta.2-20200402.5/sometool-1.2.3-linux-x64.tar.gz" "download_url": "https://github.com/actions/sometool/releases/tag/1.1.0-beta.2-20200402.5/sometool-1.1.0-linux-x64.tar.gz"
}, },
{ {
"filename": "sometool-1.2.3-darwin-x64.tar.gz", "filename": "sometool-1.1.0-darwin-x64.tar.gz",
"arch": "x64", "arch": "x64",
"platform": "darwin", "platform": "darwin",
"download_url": "https://github.com/actions/sometool/releases/tag/1.2.3-20200402.5/sometool-1.2.3-darwin-x64.tar.gz" "download_url": "https://github.com/actions/sometool/releases/tag/1.1.0-beta.2-20200402.5/sometool-1.1.0-darwin-x64.tar.gz"
}, },
{ {
"filename": "sometool-1.2.3-win32-x64.tar.gz", "filename": "sometool-1.1.0-win32-x64.tar.gz",
"arch": "x64", "arch": "x64",
"platform": "win32", "platform": "win32",
"download_url": "https://github.com/actions/sometool/releases/tag/1.2.3-20200402.5/sometool-1.2.3-win32-x64.tar.gz" "download_url": "https://github.com/actions/sometool/releases/tag/1.1.0-beta.2-20200402.5/sometool-1.1.0-win32-x64.tar.gz"
} }
] ]
} }
] ]

View File

@ -17,7 +17,7 @@ import {
getPyPyVersionFromPath getPyPyVersionFromPath
} from '../src/utils'; } from '../src/utils';
const manifestData = require('./data/pypy.json'); import manifestData from './data/pypy.json';
let architecture: string; let architecture: string;
@ -51,7 +51,7 @@ describe('parsePyPyVersion', () => {
it.each(['', 'pypy-', 'pypy', 'p', 'notpypy-'])( it.each(['', 'pypy-', 'pypy', 'p', 'notpypy-'])(
'throw on invalid input "%s"', 'throw on invalid input "%s"',
input => { input => {
expect(() => finder.parsePyPyVersion(input)).toThrowError( expect(() => finder.parsePyPyVersion(input)).toThrow(
"Invalid 'version' property for PyPy. PyPy version should be specified as 'pypy<python-version>' or '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."
); );
} }
@ -60,7 +60,7 @@ describe('parsePyPyVersion', () => {
it.each(['pypy-2', 'pypy-3', 'pypy2', 'pypy3', 'pypy3.x', 'pypy3.8.10'])( it.each(['pypy-2', 'pypy-3', 'pypy2', 'pypy3', 'pypy3.x', 'pypy3.8.10'])(
'throw on invalid input "%s"', 'throw on invalid input "%s"',
input => { input => {
expect(() => finder.parsePyPyVersion(input)).toThrowError( expect(() => finder.parsePyPyVersion(input)).toThrow(
"Invalid format of Python version for PyPy. Python version should be specified in format 'x.y'. See README for examples and documentation." "Invalid format of Python version for PyPy. Python version should be specified in format 'x.y'. See README for examples and documentation."
); );
} }
@ -273,7 +273,13 @@ describe('findPyPyVersion', () => {
it('found PyPy in toolcache', async () => { it('found PyPy in toolcache', async () => {
await expect( await expect(
finder.findPyPyVersion('pypy-3.6-v7.3.x', architecture, true, false) finder.findPyPyVersion(
'pypy-3.6-v7.3.x',
architecture,
true,
false,
false
)
).resolves.toEqual({ ).resolves.toEqual({
resolvedPythonVersion: '3.6.12', resolvedPythonVersion: '3.6.12',
resolvedPyPyVersion: '7.3.3' resolvedPyPyVersion: '7.3.3'
@ -291,13 +297,13 @@ describe('findPyPyVersion', () => {
it('throw on invalid input format', async () => { it('throw on invalid input format', async () => {
await expect( await expect(
finder.findPyPyVersion('pypy3.7-v7.3.x', architecture, true, false) finder.findPyPyVersion('pypy3.7-v7.3.x', architecture, true, false, false)
).rejects.toThrow(); ).rejects.toThrow();
}); });
it('throw on invalid input format pypy3.7-7.3.x', async () => { it('throw on invalid input format pypy3.7-7.3.x', async () => {
await expect( await expect(
finder.findPyPyVersion('pypy3.7-v7.3.x', architecture, true, false) finder.findPyPyVersion('pypy3.7-v7.3.x', architecture, true, false, false)
).rejects.toThrow(); ).rejects.toThrow();
}); });
@ -309,7 +315,13 @@ describe('findPyPyVersion', () => {
spyChmodSync = jest.spyOn(fs, 'chmodSync'); spyChmodSync = jest.spyOn(fs, 'chmodSync');
spyChmodSync.mockImplementation(() => undefined); spyChmodSync.mockImplementation(() => undefined);
await expect( await expect(
finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture, true, false) finder.findPyPyVersion(
'pypy-3.7-v7.3.x',
architecture,
true,
false,
false
)
).resolves.toEqual({ ).resolves.toEqual({
resolvedPythonVersion: '3.7.9', resolvedPythonVersion: '3.7.9',
resolvedPyPyVersion: '7.3.3' resolvedPyPyVersion: '7.3.3'
@ -333,7 +345,13 @@ describe('findPyPyVersion', () => {
spyChmodSync = jest.spyOn(fs, 'chmodSync'); spyChmodSync = jest.spyOn(fs, 'chmodSync');
spyChmodSync.mockImplementation(() => undefined); spyChmodSync.mockImplementation(() => undefined);
await expect( await expect(
finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture, false, false) finder.findPyPyVersion(
'pypy-3.7-v7.3.x',
architecture,
false,
false,
false
)
).resolves.toEqual({ ).resolves.toEqual({
resolvedPythonVersion: '3.7.9', resolvedPythonVersion: '3.7.9',
resolvedPyPyVersion: '7.3.3' resolvedPyPyVersion: '7.3.3'
@ -344,15 +362,27 @@ describe('findPyPyVersion', () => {
it('throw if release is not found', async () => { it('throw if release is not found', async () => {
await expect( await expect(
finder.findPyPyVersion('pypy-3.7-v7.5.x', architecture, true, false) finder.findPyPyVersion(
).rejects.toThrowError( 'pypy-3.7-v7.5.x',
architecture,
true,
false,
false
)
).rejects.toThrow(
`PyPy version 3.7 (v7.5.x) with arch ${architecture} not found` `PyPy version 3.7 (v7.5.x) with arch ${architecture} not found`
); );
}); });
it('check-latest enabled version found and used from toolcache', async () => { it('check-latest enabled version found and used from toolcache', async () => {
await expect( await expect(
finder.findPyPyVersion('pypy-3.6-v7.3.x', architecture, false, true) finder.findPyPyVersion(
'pypy-3.6-v7.3.x',
architecture,
false,
true,
false
)
).resolves.toEqual({ ).resolves.toEqual({
resolvedPythonVersion: '3.6.12', resolvedPythonVersion: '3.6.12',
resolvedPyPyVersion: '7.3.3' resolvedPyPyVersion: '7.3.3'
@ -371,7 +401,13 @@ describe('findPyPyVersion', () => {
spyChmodSync = jest.spyOn(fs, 'chmodSync'); spyChmodSync = jest.spyOn(fs, 'chmodSync');
spyChmodSync.mockImplementation(() => undefined); spyChmodSync.mockImplementation(() => undefined);
await expect( await expect(
finder.findPyPyVersion('pypy-3.7-v7.3.x', architecture, false, true) finder.findPyPyVersion(
'pypy-3.7-v7.3.x',
architecture,
false,
true,
false
)
).resolves.toEqual({ ).resolves.toEqual({
resolvedPythonVersion: '3.7.9', resolvedPythonVersion: '3.7.9',
resolvedPyPyVersion: '7.3.3' resolvedPyPyVersion: '7.3.3'
@ -391,7 +427,13 @@ describe('findPyPyVersion', () => {
return pypyPath; return pypyPath;
}); });
await expect( await expect(
finder.findPyPyVersion('pypy-3.8-v7.3.x', architecture, false, true) finder.findPyPyVersion(
'pypy-3.8-v7.3.x',
architecture,
false,
true,
false
)
).resolves.toEqual({ ).resolves.toEqual({
resolvedPythonVersion: '3.8.8', resolvedPythonVersion: '3.8.8',
resolvedPyPyVersion: '7.3.3' resolvedPyPyVersion: '7.3.3'
@ -401,4 +443,22 @@ describe('findPyPyVersion', () => {
'Failed to resolve PyPy v7.3.x with Python (3.8) from manifest' 'Failed to resolve PyPy v7.3.x with Python (3.8) from manifest'
); );
}); });
it('found and install successfully, pre-release fallback', async () => {
spyCacheDir = jest.spyOn(tc, 'cacheDir');
spyCacheDir.mockImplementation(() =>
path.join(toolDir, 'PyPy', '3.8.12', architecture)
);
spyChmodSync = jest.spyOn(fs, 'chmodSync');
spyChmodSync.mockImplementation(() => undefined);
await expect(
finder.findPyPyVersion('pypy3.8', architecture, false, false, false)
).rejects.toThrow();
await expect(
finder.findPyPyVersion('pypy3.8', architecture, false, false, true)
).resolves.toEqual({
resolvedPythonVersion: '3.8.12',
resolvedPyPyVersion: '7.3.8rc2'
});
});
}); });

View File

@ -24,7 +24,7 @@ import * as core from '@actions/core';
import * as finder from '../src/find-python'; import * as finder from '../src/find-python';
import * as installer from '../src/install-python'; import * as installer from '../src/install-python';
const manifestData = require('./data/versions-manifest.json'); import manifestData from './data/versions-manifest.json';
describe('Finder tests', () => { describe('Finder tests', () => {
let writeSpy: jest.SpyInstance; let writeSpy: jest.SpyInstance;
@ -56,7 +56,7 @@ describe('Finder tests', () => {
await io.mkdirP(pythonDir); await io.mkdirP(pythonDir);
fs.writeFileSync(`${pythonDir}.complete`, 'hello'); 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) // 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', true, false); await finder.useCpythonVersion('3.x', 'x64', true, false, false);
expect(spyCoreAddPath).toHaveBeenCalled(); expect(spyCoreAddPath).toHaveBeenCalled();
expect(spyCoreExportVariable).toHaveBeenCalledWith( expect(spyCoreExportVariable).toHaveBeenCalledWith(
'pythonLocation', 'pythonLocation',
@ -73,7 +73,7 @@ describe('Finder tests', () => {
await io.mkdirP(pythonDir); await io.mkdirP(pythonDir);
fs.writeFileSync(`${pythonDir}.complete`, 'hello'); 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) // 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, false); await finder.useCpythonVersion('3.x', 'x64', false, false, false);
expect(spyCoreAddPath).not.toHaveBeenCalled(); expect(spyCoreAddPath).not.toHaveBeenCalled();
expect(spyCoreExportVariable).not.toHaveBeenCalled(); expect(spyCoreExportVariable).not.toHaveBeenCalled();
}); });
@ -95,7 +95,12 @@ describe('Finder tests', () => {
fs.writeFileSync(`${pythonDir}.complete`, 'hello'); 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) // This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
await finder.useCpythonVersion('1.2.3', 'x64', true, false); await expect(
finder.useCpythonVersion('1.2.3', 'x64', true, false, false)
).resolves.toEqual({
impl: 'CPython',
version: '1.2.3'
});
expect(spyCoreAddPath).toHaveBeenCalled(); expect(spyCoreAddPath).toHaveBeenCalled();
expect(spyCoreExportVariable).toHaveBeenCalledWith( expect(spyCoreExportVariable).toHaveBeenCalledWith(
'pythonLocation', 'pythonLocation',
@ -122,14 +127,19 @@ describe('Finder tests', () => {
const pythonDir: string = path.join( const pythonDir: string = path.join(
toolDir, toolDir,
'Python', 'Python',
'1.2.3-beta.2', '1.2.4-beta.2',
'x64' 'x64'
); );
await io.mkdirP(pythonDir); await io.mkdirP(pythonDir);
fs.writeFileSync(`${pythonDir}.complete`, 'hello'); fs.writeFileSync(`${pythonDir}.complete`, 'hello');
}); });
// This will throw if it doesn't find it in the manifest (because no such version exists) // This will throw if it doesn't find it in the manifest (because no such version exists)
await finder.useCpythonVersion('1.2.3-beta.2', 'x64', false, false); await expect(
finder.useCpythonVersion('1.2.4-beta.2', 'x64', false, false, false)
).resolves.toEqual({
impl: 'CPython',
version: '1.2.4-beta.2'
});
}); });
it('Check-latest true, finds the latest version in the manifest', async () => { it('Check-latest true, finds the latest version in the manifest', async () => {
@ -176,18 +186,18 @@ describe('Finder tests', () => {
fs.writeFileSync(`${pythonDir}.complete`, 'hello'); 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) // This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
await finder.useCpythonVersion('1.2', 'x64', true, true); await finder.useCpythonVersion('1.2', 'x64', true, true, false);
expect(infoSpy).toHaveBeenCalledWith("Resolved as '1.2.3'"); expect(infoSpy).toHaveBeenCalledWith("Resolved as '1.2.3'");
expect(infoSpy).toHaveBeenCalledWith( expect(infoSpy).toHaveBeenCalledWith(
'Version 1.2.3 was not found in the local cache' 'Version 1.2.3 was not found in the local cache'
); );
expect(infoSpy).toBeCalledWith( expect(infoSpy).toHaveBeenCalledWith(
'Version 1.2.3 is available for downloading' 'Version 1.2.3 is available for downloading'
); );
expect(installSpy).toHaveBeenCalled(); expect(installSpy).toHaveBeenCalled();
expect(addPathSpy).toHaveBeenCalledWith(expPath); expect(addPathSpy).toHaveBeenCalledWith(expPath);
await finder.useCpythonVersion('1.2.3-beta.2', 'x64', false, true); await finder.useCpythonVersion('1.2.4-beta.2', 'x64', false, true, false);
expect(spyCoreAddPath).toHaveBeenCalled(); expect(spyCoreAddPath).toHaveBeenCalled();
expect(spyCoreExportVariable).toHaveBeenCalledWith( expect(spyCoreExportVariable).toHaveBeenCalledWith(
'pythonLocation', 'pythonLocation',
@ -199,11 +209,67 @@ describe('Finder tests', () => {
); );
}); });
it('Finds stable Python version if it is not installed, but exists in the manifest, skipping newer pre-release', async () => {
const findSpy: jest.SpyInstance = jest.spyOn(tc, 'getManifestFromRepo');
findSpy.mockImplementation(() => <tc.IToolRelease[]>manifestData);
const installSpy: jest.SpyInstance = jest.spyOn(
installer,
'installCpythonFromRelease'
);
installSpy.mockImplementation(async () => {
const pythonDir: string = path.join(toolDir, 'Python', '1.2.3', '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 expect(
finder.useCpythonVersion('1.2', 'x64', false, false, false)
).resolves.toEqual({
impl: 'CPython',
version: '1.2.3'
});
});
it('Finds Python version if it is not installed, but exists in the manifest, pre-release fallback', async () => {
const findSpy: jest.SpyInstance = jest.spyOn(tc, 'getManifestFromRepo');
findSpy.mockImplementation(() => <tc.IToolRelease[]>manifestData);
const installSpy: jest.SpyInstance = jest.spyOn(
installer,
'installCpythonFromRelease'
);
installSpy.mockImplementation(async () => {
const pythonDir: string = path.join(
toolDir,
'Python',
'1.1.0-beta.2',
'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 expect(
finder.useCpythonVersion('1.1', 'x64', false, false, false)
).rejects.toThrow();
await expect(
finder.useCpythonVersion('1.1', 'x64', false, false, true)
).resolves.toEqual({
impl: 'CPython',
version: '1.1.0-beta.2'
});
// Check 1.1.0 version specifier does not fallback to '1.1.0-beta.2'
await expect(
finder.useCpythonVersion('1.1.0', 'x64', false, false, true)
).rejects.toThrow();
});
it('Errors if Python is not installed', async () => { 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) // This will throw if it doesn't find it in the cache and in the manifest (because no such version exists)
let thrown = false; let thrown = false;
try { try {
await finder.useCpythonVersion('3.300000', 'x64', true, false); await finder.useCpythonVersion('3.300000', 'x64', true, false, false);
} catch { } catch {
thrown = true; thrown = true;
} }

View File

@ -14,7 +14,7 @@ import {
IS_WINDOWS IS_WINDOWS
} from '../src/utils'; } from '../src/utils';
const manifestData = require('./data/pypy.json'); import manifestData from './data/pypy.json';
let architecture: string; let architecture: string;
if (IS_WINDOWS) { if (IS_WINDOWS) {
@ -51,6 +51,12 @@ describe('findRelease', () => {
platform: process.platform, platform: process.platform,
download_url: `https://test.download.python.org/pypy/pypy3.6-v7.3.3-${extensionName}` download_url: `https://test.download.python.org/pypy/pypy3.6-v7.3.3-${extensionName}`
}; };
const filesRC1: IPyPyManifestAsset = {
filename: `pypy3.6-v7.4.0rc1-${extensionName}`,
arch: architecture,
platform: process.platform,
download_url: `https://test.download.python.org/pypy/pypy3.6-v7.4.0rc1-${extensionName}`
};
let getBooleanInputSpy: jest.SpyInstance; let getBooleanInputSpy: jest.SpyInstance;
let warningSpy: jest.SpyInstance; let warningSpy: jest.SpyInstance;
@ -72,7 +78,13 @@ describe('findRelease', () => {
const pythonVersion = '3.6'; const pythonVersion = '3.6';
const pypyVersion = '7.3.7'; const pypyVersion = '7.3.7';
expect( expect(
installer.findRelease(releases, pythonVersion, pypyVersion, architecture) installer.findRelease(
releases,
pythonVersion,
pypyVersion,
architecture,
false
)
).toEqual(null); ).toEqual(null);
}); });
@ -80,7 +92,13 @@ describe('findRelease', () => {
const pythonVersion = '3.6'; const pythonVersion = '3.6';
const pypyVersion = '7.3.3'; const pypyVersion = '7.3.3';
expect( expect(
installer.findRelease(releases, pythonVersion, pypyVersion, architecture) installer.findRelease(
releases,
pythonVersion,
pypyVersion,
architecture,
false
)
).toEqual({ ).toEqual({
foundAsset: files, foundAsset: files,
resolvedPythonVersion: '3.6.12', resolvedPythonVersion: '3.6.12',
@ -92,7 +110,13 @@ describe('findRelease', () => {
const pythonVersion = '3.6'; const pythonVersion = '3.6';
const pypyVersion = '7.x'; const pypyVersion = '7.x';
expect( expect(
installer.findRelease(releases, pythonVersion, pypyVersion, architecture) installer.findRelease(
releases,
pythonVersion,
pypyVersion,
architecture,
false
)
).toEqual({ ).toEqual({
foundAsset: files, foundAsset: files,
resolvedPythonVersion: '3.6.12', resolvedPythonVersion: '3.6.12',
@ -104,7 +128,13 @@ describe('findRelease', () => {
const pythonVersion = '3.7'; const pythonVersion = '3.7';
const pypyVersion = installer.pypyVersionToSemantic('7.3.3rc2'); const pypyVersion = installer.pypyVersionToSemantic('7.3.3rc2');
expect( expect(
installer.findRelease(releases, pythonVersion, pypyVersion, architecture) installer.findRelease(
releases,
pythonVersion,
pypyVersion,
architecture,
false
)
).toEqual({ ).toEqual({
foundAsset: { foundAsset: {
filename: `test${extension}`, filename: `test${extension}`,
@ -121,7 +151,13 @@ describe('findRelease', () => {
const pythonVersion = '3.6'; const pythonVersion = '3.6';
const pypyVersion = 'x'; const pypyVersion = 'x';
expect( expect(
installer.findRelease(releases, pythonVersion, pypyVersion, architecture) installer.findRelease(
releases,
pythonVersion,
pypyVersion,
architecture,
false
)
).toEqual({ ).toEqual({
foundAsset: files, foundAsset: files,
resolvedPythonVersion: '3.6.12', resolvedPythonVersion: '3.6.12',
@ -129,12 +165,45 @@ describe('findRelease', () => {
}); });
}); });
it('Python version and PyPy version matches semver (pre-release)', () => {
const pythonVersion = '3.6';
const pypyVersion = '7.4.x';
expect(
installer.findRelease(
releases,
pythonVersion,
pypyVersion,
architecture,
false
)
).toBeNull();
expect(
installer.findRelease(
releases,
pythonVersion,
pypyVersion,
architecture,
true
)
).toEqual({
foundAsset: filesRC1,
resolvedPythonVersion: '3.6.12',
resolvedPyPyVersion: '7.4.0rc1'
});
});
it('Nightly release is found', () => { it('Nightly release is found', () => {
const pythonVersion = '3.6'; const pythonVersion = '3.6';
const pypyVersion = 'nightly'; const pypyVersion = 'nightly';
const filename = IS_WINDOWS ? 'filename.zip' : 'filename.tar.bz2'; const filename = IS_WINDOWS ? 'filename.zip' : 'filename.tar.bz2';
expect( expect(
installer.findRelease(releases, pythonVersion, pypyVersion, architecture) installer.findRelease(
releases,
pythonVersion,
pypyVersion,
architecture,
false
)
).toEqual({ ).toEqual({
foundAsset: { foundAsset: {
filename: filename, filename: filename,
@ -224,8 +293,8 @@ describe('installPyPy', () => {
it('throw if release is not found', async () => { it('throw if release is not found', async () => {
await expect( await expect(
installer.installPyPy('7.3.3', '3.6.17', architecture, undefined) installer.installPyPy('7.3.3', '3.6.17', architecture, false, undefined)
).rejects.toThrowError( ).rejects.toThrow(
`PyPy version 3.6.17 (7.3.3) with arch ${architecture} not found` `PyPy version 3.6.17 (7.3.3) with arch ${architecture} not found`
); );
@ -244,7 +313,7 @@ describe('installPyPy', () => {
spyChmodSync.mockImplementation(() => undefined); spyChmodSync.mockImplementation(() => undefined);
await expect( await expect(
installer.installPyPy('7.3.x', '3.6.12', architecture, undefined) installer.installPyPy('7.x', '3.6.12', architecture, false, undefined)
).resolves.toEqual({ ).resolves.toEqual({
installDir: path.join(toolDir, 'PyPy', '3.6.12', architecture), installDir: path.join(toolDir, 'PyPy', '3.6.12', architecture),
resolvedPythonVersion: '3.6.12', resolvedPythonVersion: '3.6.12',
@ -257,4 +326,31 @@ describe('installPyPy', () => {
expect(spyCacheDir).toHaveBeenCalled(); expect(spyCacheDir).toHaveBeenCalled();
expect(spyExec).toHaveBeenCalled(); expect(spyExec).toHaveBeenCalled();
}); });
it('found and install PyPy, pre-release fallback', async () => {
spyCacheDir = jest.spyOn(tc, 'cacheDir');
spyCacheDir.mockImplementation(() =>
path.join(toolDir, 'PyPy', '3.6.12', architecture)
);
spyChmodSync = jest.spyOn(fs, 'chmodSync');
spyChmodSync.mockImplementation(() => undefined);
await expect(
installer.installPyPy('7.4.x', '3.6.12', architecture, false, undefined)
).rejects.toThrow();
await expect(
installer.installPyPy('7.4.x', '3.6.12', architecture, true, undefined)
).resolves.toEqual({
installDir: path.join(toolDir, 'PyPy', '3.6.12', architecture),
resolvedPythonVersion: '3.6.12',
resolvedPyPyVersion: '7.4.0rc1'
});
expect(spyHttpClient).toHaveBeenCalled();
expect(spyDownloadTool).toHaveBeenCalled();
expect(spyExistsSync).toHaveBeenCalled();
expect(spyCacheDir).toHaveBeenCalled();
expect(spyExec).toHaveBeenCalled();
});
}); });

7
__tests__/test-pipenv.py Normal file
View File

@ -0,0 +1,7 @@
import numpy as np
a = np.array([2, 3, 4])
print(type(a))
b = np.array([1.2, 3.5, 5.1])
print(type(b))

View File

@ -1,9 +1,17 @@
import * as cache from '@actions/cache'; import * as cache from '@actions/cache';
import * as core from '@actions/core'; import * as core from '@actions/core';
import * as io from '@actions/io';
import fs from 'fs';
import path from 'path';
import { import {
validateVersion, validateVersion,
validatePythonVersionFormatForPyPy, validatePythonVersionFormatForPyPy,
isCacheFeatureAvailable isCacheFeatureAvailable,
getVersionInputFromFile,
getVersionInputFromPlainFile,
getVersionInputFromTomlFile
} from '../src/utils'; } from '../src/utils';
jest.mock('@actions/cache'); jest.mock('@actions/cache');
@ -42,14 +50,13 @@ describe('validateVersion', () => {
describe('isCacheFeatureAvailable', () => { describe('isCacheFeatureAvailable', () => {
it('isCacheFeatureAvailable disabled on GHES', () => { it('isCacheFeatureAvailable disabled on GHES', () => {
jest.spyOn(cache, 'isFeatureAvailable').mockImplementation(() => false); jest.spyOn(cache, 'isFeatureAvailable').mockImplementation(() => false);
const infoMock = jest.spyOn(core, 'warning');
const 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.';
try { try {
process.env['GITHUB_SERVER_URL'] = 'http://example.com'; process.env['GITHUB_SERVER_URL'] = 'http://example.com';
isCacheFeatureAvailable(); expect(isCacheFeatureAvailable()).toBeFalsy();
} catch (error) { expect(infoMock).toHaveBeenCalledWith(message);
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 { } finally {
delete process.env['GITHUB_SERVER_URL']; delete process.env['GITHUB_SERVER_URL'];
} }
@ -74,3 +81,58 @@ describe('isCacheFeatureAvailable', () => {
expect(isCacheFeatureAvailable()).toBe(true); expect(isCacheFeatureAvailable()).toBe(true);
}); });
}); });
const tempDir = path.join(
__dirname,
'runner',
path.join(Math.random().toString(36).substring(7)),
'temp'
);
describe('Version from file test', () => {
it.each([getVersionInputFromPlainFile, getVersionInputFromFile])(
'Version from plain file test',
async _fn => {
await io.mkdirP(tempDir);
const pythonVersionFileName = 'python-version.file';
const pythonVersionFilePath = path.join(tempDir, pythonVersionFileName);
const pythonVersionFileContent = '3.7';
fs.writeFileSync(pythonVersionFilePath, pythonVersionFileContent);
expect(_fn(pythonVersionFilePath)).toEqual([pythonVersionFileContent]);
}
);
it.each([getVersionInputFromTomlFile, getVersionInputFromFile])(
'Version from standard pyproject.toml test',
async _fn => {
await io.mkdirP(tempDir);
const pythonVersionFileName = 'pyproject.toml';
const pythonVersionFilePath = path.join(tempDir, pythonVersionFileName);
const pythonVersion = '>=3.7';
const pythonVersionFileContent = `[project]\nrequires-python = "${pythonVersion}"`;
fs.writeFileSync(pythonVersionFilePath, pythonVersionFileContent);
expect(_fn(pythonVersionFilePath)).toEqual([pythonVersion]);
}
);
it.each([getVersionInputFromTomlFile, getVersionInputFromFile])(
'Version from poetry pyproject.toml test',
async _fn => {
await io.mkdirP(tempDir);
const pythonVersionFileName = 'pyproject.toml';
const pythonVersionFilePath = path.join(tempDir, pythonVersionFileName);
const pythonVersion = '>=3.7';
const pythonVersionFileContent = `[tool.poetry.dependencies]\npython = "${pythonVersion}"`;
fs.writeFileSync(pythonVersionFilePath, pythonVersionFileContent);
expect(_fn(pythonVersionFilePath)).toEqual([pythonVersion]);
}
);
it.each([getVersionInputFromTomlFile, getVersionInputFromFile])(
'Version undefined',
async _fn => {
await io.mkdirP(tempDir);
const pythonVersionFileName = 'pyproject.toml';
const pythonVersionFilePath = path.join(tempDir, pythonVersionFileName);
fs.writeFileSync(pythonVersionFilePath, ``);
expect(_fn(pythonVersionFilePath)).toEqual([]);
}
);
});

View File

@ -23,6 +23,9 @@ inputs:
update-environment: update-environment:
description: "Set this option if you want the action to update environment variables." description: "Set this option if you want the action to update environment variables."
default: true default: true
allow-prereleases:
description: "When 'true', a version range passed to 'python-version' input will match prerelease versions if no GA versions are found. Only 'x.y' version range is supported for CPython."
default: false
outputs: outputs:
python-version: python-version:
description: "The installed Python or PyPy version. Useful when given a version range as input." description: "The installed Python or PyPy version. Useful when given a version range as input."

9269
dist/cache-save/index.js vendored

File diff suppressed because one or more lines are too long

13735
dist/setup/index.js vendored

File diff suppressed because one or more lines are too long

View File

@ -2,6 +2,7 @@
- [Using the python-version input](advanced-usage.md#using-the-python-version-input) - [Using the python-version input](advanced-usage.md#using-the-python-version-input)
- [Specifying a Python version](advanced-usage.md#specifying-a-python-version) - [Specifying a Python version](advanced-usage.md#specifying-a-python-version)
- [Specifying a PyPy version](advanced-usage.md#specifying-a-pypy-version) - [Specifying a PyPy version](advanced-usage.md#specifying-a-pypy-version)
- [Specifying multiple Python and PyPy versions](advanced-usage.md#specifying-multiple-python/pypy-version)
- [Matrix Testing](advanced-usage.md#matrix-testing) - [Matrix Testing](advanced-usage.md#matrix-testing)
- [Using the python-version-file input](advanced-usage.md#using-the-python-version-file-input) - [Using the python-version-file input](advanced-usage.md#using-the-python-version-file-input)
- [Check latest version](advanced-usage.md#check-latest-version) - [Check latest version](advanced-usage.md#check-latest-version)
@ -19,6 +20,7 @@
- [Linux](advanced-usage.md#linux) - [Linux](advanced-usage.md#linux)
- [macOS](advanced-usage.md#macos) - [macOS](advanced-usage.md#macos)
- [Using `setup-python` on GHES](advanced-usage.md#using-setup-python-on-ghes) - [Using `setup-python` on GHES](advanced-usage.md#using-setup-python-on-ghes)
- [Allow pre-releases](advanced-usage.md#allow-pre-releases)
## Using the `python-version` input ## Using the `python-version` input
@ -59,7 +61,7 @@ steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-python@v4 - uses: actions/setup-python@v4
with: with:
python-version: '3.11.0-alpha.1' python-version: '3.12.0-alpha.1'
- run: python my_script.py - run: python my_script.py
``` ```
@ -70,12 +72,23 @@ steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-python@v4 - uses: actions/setup-python@v4
with: with:
python-version: '3.11-dev' python-version: '3.12-dev'
- run: python my_script.py - run: python my_script.py
``` ```
You can also use several types of ranges that are specified in [semver](https://github.com/npm/node-semver#ranges), for instance: You can also use several types of ranges that are specified in [semver](https://github.com/npm/node-semver#ranges), for instance:
- **[ranges](https://github.com/npm/node-semver#ranges)** to download and set up the latest available version of Python satisfying a range:
```yaml
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '>=3.9 <3.10'
- run: python my_script.py
```
- **[hyphen ranges](https://github.com/npm/node-semver#hyphen-ranges-xyz---abc)** to download and set up the latest available version of Python (includes both pre-release and stable versions): - **[hyphen ranges](https://github.com/npm/node-semver#hyphen-ranges-xyz---abc)** to download and set up the latest available version of Python (includes both pre-release and stable versions):
```yaml ```yaml
@ -83,7 +96,7 @@ steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-python@v4 - uses: actions/setup-python@v4
with: with:
python-version: '3.11.0-alpha - 3.11.0' python-version: '3.12.0-alpha - 3.12.0'
- run: python my_script.py - run: python my_script.py
``` ```
@ -132,6 +145,62 @@ jobs:
``` ```
More details on PyPy syntax can be found in the [Available versions of PyPy](#pypy) section. More details on PyPy syntax can be found in the [Available versions of PyPy](#pypy) section.
### Specifying multiple Python/PyPy version
The python-version input can get multiple python/pypy versions. The last specified version will be used as a default one.
Download and set up multiple Python versions:
```yaml
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: |
3.8
3.9
3.10
- run: python my_script.py
```
Download and set up multiple PyPy versions:
```yaml
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: |
pypy-3.7-v7.3.x
pypy3.9-nightly
pypy3.8
- run: python my_script.py
```
Download and set up multiple Python/PyPy versions:
```yaml
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: |
3.8
3.9
pypy3.9-nightly
pypy3.8
3.10
- run: python my_script.py
```
### Matrix Testing ### Matrix Testing
Using `setup-python` it's possible to use [matrix syntax](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix) to install several versions of Python or PyPy: Using `setup-python` it's possible to use [matrix syntax](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix) to install several versions of Python or PyPy:
@ -193,6 +262,16 @@ steps:
python-version-file: '.python-version' # Read python version from a file .python-version python-version-file: '.python-version' # Read python version from a file .python-version
- run: python my_script.py - run: python my_script.py
``` ```
```yaml
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version-file: 'pyproject.toml' # Read python version from a file pyproject.toml
- run: python my_script.py
```
## Check latest version ## Check latest version
The `check-latest` flag defaults to `false`. Use the default or set `check-latest` to `false` if you prefer stability and if you want to ensure a specific `Python or PyPy` version is always used. The `check-latest` flag defaults to `false`. Use the default or set `check-latest` to `false` if you prefer stability and if you want to ensure a specific `Python or PyPy` version is always used.
@ -202,7 +281,7 @@ If `check-latest` is set to `true`, the action first checks if the cached versio
```yaml ```yaml
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-python@v3 - uses: actions/setup-python@v4
with: with:
python-version: '3.7' python-version: '3.7'
check-latest: true check-latest: true
@ -281,6 +360,20 @@ steps:
- run: pip install -e . -r subdirectory/requirements-dev.txt - run: pip install -e . -r subdirectory/requirements-dev.txt
``` ```
**Caching projects that use setup.py:**
```yaml
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.11'
cache: 'pip'
cache-dependency-path: setup.py
- run: pip install -e .
# Or pip install -e '.[test]' to install test dependencies
```
# Outputs and environment variables # Outputs and environment variables
## Outputs ## Outputs
@ -333,7 +426,7 @@ jobs:
with: with:
python-version: "3.8.0" python-version: "3.8.0"
cache: "poetry" cache: "poetry"
- run: echo '${{ steps.cp310.outputs.cache-hit }}' # true if cache-hit occured on the primary key - run: echo '${{ steps.cp310.outputs.cache-hit }}' # true if cache-hit occurred on the primary key
``` ```
## Environment variables ## Environment variables
@ -345,7 +438,7 @@ These environment variables become available after setup-python action execution
| pythonLocation |Contains the absolute path to the folder where the requested version of Python or PyPy is installed| | pythonLocation |Contains the absolute path to the folder where the requested version of Python or PyPy is installed|
| Python_ROOT_DIR | https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython | | Python_ROOT_DIR | https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython |
| Python2_ROOT_DIR |https://cmake.org/cmake/help/latest/module/FindPython2.html#module:FindPython2| | Python2_ROOT_DIR |https://cmake.org/cmake/help/latest/module/FindPython2.html#module:FindPython2|
| Python3_ROOT_DIR |https://cmake.org/cmake/help/latest/module/FindPython2.html#module:FindPython3| | Python3_ROOT_DIR |https://cmake.org/cmake/help/latest/module/FindPython3.html#module:FindPython3|
## Using `update-environment` flag ## Using `update-environment` flag
@ -376,7 +469,7 @@ Such a requirement on side-effect could be because you don't want your composite
- For every minor version of Python, expect only the latest patch to be preinstalled. - 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 tool cache. - 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 tool cache.
- If the exact patch version doesn't matter to you, specifying just the major and minor versions 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. - If the exact patch version doesn't matter to you, specifying just the major and minor versions 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*. - Use `-dev` instead of a patch number (e.g., `3.12-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)). - 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. - 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 - If there is a specific version of Python that is not available, you can open an issue here
@ -471,15 +564,58 @@ One quick way to grant access is to change the user and group of `/Users/runner/
## Using `setup-python` on GHES ## Using `setup-python` on GHES
`setup-python` comes pre-installed on the appliance with GHES if Actions is enabled. When dynamically downloading Python distributions, `setup-python` downloads distributions from [`actions/python-versions`](https://github.com/actions/python-versions) on github.com (outside of the appliance). These calls to `actions/python-versions` are made via unauthenticated requests, which are limited to [60 requests per hour per IP](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting). If more requests are made within the time frame, then you will start to see rate-limit errors during downloading that looks like: `##[error]API rate limit exceeded for...`. ### Avoiding rate limit issues
To get a higher rate limit, you can [generate a personal access token on github.com](https://github.com/settings/tokens/new) and pass it as the `token` input for the action: `setup-python` comes pre-installed on the appliance with GHES if Actions is enabled. When dynamically downloading Python distributions, `setup-python` downloads distributions from [`actions/python-versions`](https://github.com/actions/python-versions) on github.com (outside of the appliance). These calls to `actions/python-versions` are by default made via unauthenticated requests, which are limited to [60 requests per hour per IP](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting). If more requests are made within the time frame, then you will start to see rate-limit errors during downloading that look like this:
##[error]API rate limit exceeded for YOUR_IP. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)
To get a higher rate limit, you can [generate a personal access token (PAT) on github.com](https://github.com/settings/tokens/new) and pass it as the `token` input for the action. It is important to understand that this needs to be a token from github.com and _not_ from your GHES instance. If you or your colleagues do not yet have a github.com account, you might need to create one.
Here are the steps you need to follow to avoid the rate limit:
1. Create a PAT on any github.com account by using [this link](https://github.com/settings/tokens/new) after logging into github.com (not your Enterprise instance). This PAT does _not_ need any rights, so make sure all the boxes are unchecked.
2. Store this PAT in the repository / organization where you run your workflow, e.g. as `GH_GITHUB_COM_TOKEN`. You can do this by navigating to your repository -> **Settings** -> **Secrets** -> **Actions** -> **New repository secret**.
3. To use this functionality, you need to use any version newer than `v4.3`. Also, change _python-version_ as needed.
```yml ```yml
uses: actions/setup-python@v4 - name: Set up Python
with: uses: actions/setup-python@v4
token: ${{ secrets.GH_DOTCOM_TOKEN }} with:
python-version: 3.11 python-version: 3.8
token: ${{ secrets.GH_GITHUB_COM_TOKEN }}
```
Requests should now be authenticated. To verify that you are getting the higher rate limit, you can call GitHub's [rate limit API](https://docs.github.com/en/rest/rate-limit) from within your workflow ([example](https://github.com/actions/setup-python/pull/443#issuecomment-1206776401)).
### No access to github.com
If the runner is not able to access github.com, any Python versions requested during a workflow run must come from the runner's tool cache. See "[Setting up the tool cache on self-hosted runners without internet access](https://docs.github.com/en/enterprise-server/admin/github-actions/managing-access-to-actions-from-githubcom/setting-up-the-tool-cache-on-self-hosted-runners-without-internet-access)" for more information.
## Allow pre-releases
The `allow-prereleases` flag defaults to `false`.
If `allow-prereleases` is set to `true`, the action will allow falling back to pre-release versions of Python when a matching GA version of Python is not available.
This allows for example to simplify reuse of `python-version` as an input of nox for pre-releases of Python by not requiring manipulation of the `3.y-dev` specifier.
For CPython, `allow-prereleases` will only have effect for `x.y` version range (e.g. `3.12`).
Let's say that python 3.12 is not generally available, the following workflow will fallback to the most recent pre-release of python 3.12:
```yaml
jobs:
test:
name: ${{ matrix.os }} / ${{ matrix.python_version }}
runs-on: ${{ matrix.os }}-latest
strategy:
fail-fast: false
matrix:
os: [Ubuntu, Windows, macOS]
python_version: ["3.11", "3.12"]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: "${{ matrix.python_version }}"
allow-prereleases: true
- run: pipx run nox --error-on-missing-interpreters -s tests-${{ matrix.python_version }}
``` ```
If the runner is not able to access github.com, any Python versions requested during a workflow run must come from the runner's tool cache. See "[Setting up the tool cache on self-hosted runners without internet access](https://docs.github.com/en/enterprise-server@3.2/admin/github-actions/managing-access-to-actions-from-githubcom/setting-up-the-tool-cache-on-self-hosted-runners-without-internet-access)" for more information.

View File

@ -60,6 +60,7 @@ Pull requests are the easiest way to contribute changes to git repos at GitHub.
- To implement new features or fix bugs, you need to make changes to the `.ts` files, which are located in the `src` folder - To implement new features or fix bugs, you need to make changes to the `.ts` files, which are located in the `src` folder
- To comply with the code style, **you need to run the `format` script** - To comply with the code style, **you need to run the `format` script**
- To lint the code, **you need to run the `lint:fix` script**
- To transpile source code to `javascript` we use [NCC](https://github.com/vercel/ncc). **It is very important to run the `build` script after making changes**, otherwise your changes will not get into the final `javascript` build - To transpile source code to `javascript` we use [NCC](https://github.com/vercel/ncc). **It is very important to run the `build` script after making changes**, otherwise your changes will not get into the final `javascript` build
**Learn more about how to implement tests:** **Learn more about how to implement tests:**

12864
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -6,8 +6,10 @@
"main": "dist/index.js", "main": "dist/index.js",
"scripts": { "scripts": {
"build": "ncc build -o dist/setup src/setup-python.ts && ncc build -o dist/cache-save src/cache-save.ts", "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": "prettier --no-error-on-unmatched-pattern --config ./.prettierrc.js --write \"**/*.{ts,yml,yaml}\"",
"format-check": "prettier --check \"{,!(node_modules)/**/}*.ts\"", "format-check": "prettier --no-error-on-unmatched-pattern --config ./.prettierrc.js --check \"**/*.{ts,yml,yaml}\"",
"lint": "eslint --config ./.eslintrc.js \"**/*.ts\"",
"lint:fix": "eslint --config ./.eslintrc.js \"**/*.ts\" --fix",
"release": "ncc build -o dist/setup src/setup-python.ts && ncc build -o dist/cache-save src/cache-save.ts && git add -f dist/", "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 --coverage" "test": "jest --coverage"
}, },
@ -27,19 +29,27 @@
"@actions/core": "^1.10.0", "@actions/core": "^1.10.0",
"@actions/exec": "^1.1.0", "@actions/exec": "^1.1.0",
"@actions/glob": "^0.2.0", "@actions/glob": "^0.2.0",
"@actions/http-client": "^1.0.11",
"@actions/io": "^1.0.2", "@actions/io": "^1.0.2",
"@actions/tool-cache": "^1.5.5", "@actions/tool-cache": "^1.5.5",
"semver": "^7.1.3" "@iarna/toml": "^2.2.5",
"semver": "^7.5.2"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^27.0.2", "@types/jest": "^27.0.2",
"@types/node": "^16.11.25", "@types/node": "^16.11.25",
"@types/semver": "^7.1.0", "@types/semver": "^7.1.0",
"@typescript-eslint/eslint-plugin": "^5.54.0",
"@typescript-eslint/parser": "^5.54.0",
"@vercel/ncc": "^0.33.4", "@vercel/ncc": "^0.33.4",
"eslint": "^8.35.0",
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-jest": "^27.2.1",
"eslint-plugin-node": "^11.1.0",
"husky": "^7.0.2", "husky": "^7.0.2",
"jest": "^27.2.5", "jest": "^27.2.5",
"jest-circus": "^27.2.5", "jest-circus": "^27.2.5",
"prettier": "^2.0.2", "prettier": "^2.8.4",
"ts-jest": "^27.0.5", "ts-jest": "^27.0.5",
"typescript": "^4.2.3" "typescript": "^4.2.3"
}, },

View File

@ -1,5 +1,6 @@
import * as cache from '@actions/cache'; import * as cache from '@actions/cache';
import * as core from '@actions/core'; import * as core from '@actions/core';
import {CACHE_DEPENDENCY_BACKUP_PATH} from './constants';
export enum State { export enum State {
STATE_CACHE_PRIMARY_KEY = 'cache-primary-key', STATE_CACHE_PRIMARY_KEY = 'cache-primary-key',
@ -19,27 +20,39 @@ abstract class CacheDistributor {
primaryKey: string; primaryKey: string;
restoreKey: string[] | undefined; restoreKey: string[] | undefined;
}>; }>;
protected async handleLoadedCache() {}
public async restoreCache() { public async restoreCache() {
const {primaryKey, restoreKey} = await this.computeKeys(); const {primaryKey, restoreKey} = await this.computeKeys();
if (primaryKey.endsWith('-')) { if (primaryKey.endsWith('-')) {
const file =
this.packageManager === 'pip'
? `${this.cacheDependencyPath
.split('\n')
.join(',')} or ${CACHE_DEPENDENCY_BACKUP_PATH}`
: this.cacheDependencyPath.split('\n').join(',');
throw new Error( throw new Error(
`No file in ${process.cwd()} matched to [${this.cacheDependencyPath `No file in ${process.cwd()} matched to [${file}], make sure you have checked out the target repository`
.split('\n')
.join(',')}], make sure you have checked out the target repository`
); );
} }
const cachePath = await this.getCacheGlobalDirectories(); const cachePath = await this.getCacheGlobalDirectories();
core.saveState(State.CACHE_PATHS, cachePath); core.saveState(State.CACHE_PATHS, cachePath);
let matchedKey: string | undefined;
try {
matchedKey = await cache.restoreCache(cachePath, primaryKey, restoreKey);
} catch (err) {
const message = (err as Error).message;
core.info(`[warning]${message}`);
core.setOutput('cache-hit', false);
return;
}
core.saveState(State.STATE_CACHE_PRIMARY_KEY, primaryKey); core.saveState(State.STATE_CACHE_PRIMARY_KEY, primaryKey);
const matchedKey = await cache.restoreCache( await this.handleLoadedCache();
cachePath,
primaryKey,
restoreKey
);
this.handleMatchResult(matchedKey, primaryKey); this.handleMatchResult(matchedKey, primaryKey);
} }

View File

@ -0,0 +1 @@
export const CACHE_DEPENDENCY_BACKUP_PATH = '**/pyproject.toml';

View File

@ -7,12 +7,15 @@ import * as path from 'path';
import os from 'os'; import os from 'os';
import CacheDistributor from './cache-distributor'; import CacheDistributor from './cache-distributor';
import {getLinuxOSReleaseInfo, IS_LINUX, IS_WINDOWS} from '../utils'; import {getLinuxInfo, IS_LINUX, IS_WINDOWS} from '../utils';
import {CACHE_DEPENDENCY_BACKUP_PATH} from './constants';
class PipCache extends CacheDistributor { class PipCache extends CacheDistributor {
private cacheDependencyBackupPath: string = CACHE_DEPENDENCY_BACKUP_PATH;
constructor( constructor(
private pythonVersion: string, private pythonVersion: string,
cacheDependencyPath: string = '**/requirements.txt' cacheDependencyPath = '**/requirements.txt'
) { ) {
super('pip', cacheDependencyPath); super('pip', cacheDependencyPath);
} }
@ -56,14 +59,16 @@ class PipCache extends CacheDistributor {
} }
protected async computeKeys() { protected async computeKeys() {
const hash = await glob.hashFiles(this.cacheDependencyPath); const hash =
(await glob.hashFiles(this.cacheDependencyPath)) ||
(await glob.hashFiles(this.cacheDependencyBackupPath));
let primaryKey = ''; let primaryKey = '';
let restoreKey = ''; let restoreKey = '';
if (IS_LINUX) { if (IS_LINUX) {
const osRelease = await getLinuxOSReleaseInfo(); const osInfo = await getLinuxInfo();
primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${osRelease}-python-${this.pythonVersion}-${this.packageManager}-${hash}`; primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${osInfo.osVersion}-${osInfo.osName}-python-${this.pythonVersion}-${this.packageManager}-${hash}`;
restoreKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${osRelease}-python-${this.pythonVersion}-${this.packageManager}`; restoreKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${osInfo.osVersion}-${osInfo.osName}-python-${this.pythonVersion}-${this.packageManager}`;
} else { } else {
primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}-${hash}`; primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}-${hash}`;
restoreKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}`; restoreKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}`;

View File

@ -10,52 +10,44 @@ import {logWarning} from '../utils';
class PoetryCache extends CacheDistributor { class PoetryCache extends CacheDistributor {
constructor( constructor(
private pythonVersion: string, private pythonVersion: string,
protected patterns: string = '**/poetry.lock' protected patterns: string = '**/poetry.lock',
protected poetryProjects: Set<string> = new Set<string>()
) { ) {
super('poetry', patterns); super('poetry', patterns);
} }
protected async getCacheGlobalDirectories() { protected async getCacheGlobalDirectories() {
const poetryConfig = await this.getPoetryConfiguration(); // Same virtualenvs path may appear for different projects, hence we use a Set
const paths = new Set<string>();
const globber = await glob.create(this.patterns);
const cacheDir = poetryConfig['cache-dir']; for await (const file of globber.globGenerator()) {
const virtualenvsPath = poetryConfig['virtualenvs.path'].replace( const basedir = path.dirname(file);
'{cache-dir}', core.debug(`Processing Poetry project at ${basedir}`);
cacheDir this.poetryProjects.add(basedir);
);
const paths = [virtualenvsPath]; const poetryConfig = await this.getPoetryConfiguration(basedir);
if (poetryConfig['virtualenvs.in-project'] === true) { const cacheDir = poetryConfig['cache-dir'];
paths.push(path.join(process.cwd(), '.venv')); const virtualenvsPath = poetryConfig['virtualenvs.path'].replace(
} '{cache-dir}',
cacheDir
const pythonLocation = await io.which('python');
if (pythonLocation) {
core.debug(`pythonLocation is ${pythonLocation}`);
const {
exitCode,
stderr
} = await exec.getExecOutput(
`poetry env use ${pythonLocation}`,
undefined,
{ignoreReturnCode: true}
); );
if (exitCode) { paths.add(virtualenvsPath);
logWarning(stderr);
if (poetryConfig['virtualenvs.in-project']) {
paths.add(path.join(basedir, '.venv'));
} }
} else {
logWarning('python binaries were not found in PATH');
} }
return paths; return [...paths];
} }
protected async computeKeys() { protected async computeKeys() {
const hash = await glob.hashFiles(this.patterns); const hash = await glob.hashFiles(this.patterns);
const primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}-${hash}`; // "v2" is here to invalidate old caches of this cache distributor, which were created broken:
const primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}-v2-${hash}`;
const restoreKey = undefined; const restoreKey = undefined;
return { return {
primaryKey, primaryKey,
@ -63,11 +55,39 @@ class PoetryCache extends CacheDistributor {
}; };
} }
private async getPoetryConfiguration() { protected async handleLoadedCache() {
const {stdout, stderr, exitCode} = await exec.getExecOutput('poetry', [ await super.handleLoadedCache();
'config',
'--list' // After the cache is loaded -- make sure virtualenvs use the correct Python version (the one that we have just installed).
]); // This will handle invalid caches, recreating virtualenvs if necessary.
const pythonLocation = await io.which('python');
if (pythonLocation) {
core.debug(`pythonLocation is ${pythonLocation}`);
} else {
logWarning('python binaries were not found in PATH');
return;
}
for (const poetryProject of this.poetryProjects) {
const {exitCode, stderr} = await exec.getExecOutput(
'poetry',
['env', 'use', pythonLocation],
{ignoreReturnCode: true, cwd: poetryProject}
);
if (exitCode) {
logWarning(stderr);
}
}
}
private async getPoetryConfiguration(basedir: string) {
const {stdout, stderr, exitCode} = await exec.getExecOutput(
'poetry',
['config', '--list'],
{cwd: basedir}
);
if (exitCode && stderr) { if (exitCode && stderr) {
throw new Error( throw new Error(

View File

@ -17,7 +17,16 @@ export async function run() {
} }
async function saveCache(packageManager: string) { async function saveCache(packageManager: string) {
const cachePaths = JSON.parse(core.getState(State.CACHE_PATHS)) as string[]; const cachePathState = core.getState(State.CACHE_PATHS);
if (!cachePathState) {
core.warning(
'Cache paths are empty. Please check the previous logs and make sure that the python version is specified'
);
return;
}
const cachePaths = JSON.parse(cachePathState) as string[];
core.debug(`paths for caching are ${cachePaths.join(', ')}`); core.debug(`paths for caching are ${cachePaths.join(', ')}`);
@ -43,7 +52,16 @@ async function saveCache(packageManager: string) {
return; return;
} }
const cacheId = await cache.saveCache(cachePaths, primaryKey); let cacheId = 0;
try {
cacheId = await cache.saveCache(cachePaths, primaryKey);
} catch (err) {
const message = (err as Error).message;
core.info(`[warning]${message}`);
return;
}
if (cacheId == -1) { if (cacheId == -1) {
return; return;
} }

View File

@ -23,7 +23,8 @@ export async function findPyPyVersion(
versionSpec: string, versionSpec: string,
architecture: string, architecture: string,
updateEnvironment: boolean, updateEnvironment: boolean,
checkLatest: boolean checkLatest: boolean,
allowPreReleases: boolean
): Promise<{resolvedPyPyVersion: string; resolvedPythonVersion: string}> { ): Promise<{resolvedPyPyVersion: string; resolvedPythonVersion: string}> {
let resolvedPyPyVersion = ''; let resolvedPyPyVersion = '';
let resolvedPythonVersion = ''; let resolvedPythonVersion = '';
@ -39,7 +40,8 @@ export async function findPyPyVersion(
releases, releases,
pypyVersionSpec.pythonVersion, pypyVersionSpec.pythonVersion,
pypyVersionSpec.pypyVersion, pypyVersionSpec.pypyVersion,
architecture architecture,
false
); );
if (releaseData) { if (releaseData) {
@ -63,16 +65,14 @@ export async function findPyPyVersion(
)); ));
if (!installDir) { if (!installDir) {
({ ({installDir, resolvedPythonVersion, resolvedPyPyVersion} =
installDir, await pypyInstall.installPyPy(
resolvedPythonVersion, pypyVersionSpec.pypyVersion,
resolvedPyPyVersion pypyVersionSpec.pythonVersion,
} = await pypyInstall.installPyPy( architecture,
pypyVersionSpec.pypyVersion, allowPreReleases,
pypyVersionSpec.pythonVersion, releases
architecture, ));
releases
));
} }
const pipDir = IS_WINDOWS ? 'Scripts' : 'bin'; const pipDir = IS_WINDOWS ? 'Scripts' : 'bin';
@ -95,7 +95,7 @@ export async function findPyPyVersion(
core.addPath(pythonLocation); core.addPath(pythonLocation);
core.addPath(_binDir); core.addPath(_binDir);
} }
core.setOutput('python-version', 'pypy' + resolvedPyPyVersion.trim()); core.setOutput('python-version', 'pypy' + resolvedPyPyVersion);
core.setOutput('python-path', pythonPath); core.setOutput('python-path', pythonPath);
return {resolvedPyPyVersion, resolvedPythonVersion}; return {resolvedPyPyVersion, resolvedPythonVersion};
@ -142,7 +142,7 @@ export function parsePyPyVersion(versionSpec: string): IPyPyVersionSpec {
const versions = versionSpec.split('-').filter(item => !!item); const versions = versionSpec.split('-').filter(item => !!item);
if (/^(pypy)(.+)/.test(versions[0])) { if (/^(pypy)(.+)/.test(versions[0])) {
let pythonVersion = versions[0].replace('pypy', ''); const pythonVersion = versions[0].replace('pypy', '');
versions.splice(0, 1, 'pypy', pythonVersion); versions.splice(0, 1, 'pypy', pythonVersion);
} }

View File

@ -1,6 +1,6 @@
import * as os from 'os'; import * as os from 'os';
import * as path from 'path'; import * as path from 'path';
import {IS_WINDOWS, IS_LINUX} from './utils'; import {IS_WINDOWS, IS_LINUX, getOSInfo} from './utils';
import * as semver from 'semver'; import * as semver from 'semver';
@ -11,7 +11,7 @@ import * as tc from '@actions/tool-cache';
// Python has "scripts" or "bin" directories where command-line tools that come with packages are installed. // Python has "scripts" or "bin" directories where command-line tools that come with packages are installed.
// This is where pip is, along with anything that pip installs. // This is where pip is, along with anything that pip installs.
// There is a seperate directory for `pip install --user`. // There is a separate directory for `pip install --user`.
// //
// For reference, these directories are as follows: // For reference, these directories are as follows:
// macOS / Linux: // macOS / Linux:
@ -34,11 +34,15 @@ export async function useCpythonVersion(
version: string, version: string,
architecture: string, architecture: string,
updateEnvironment: boolean, updateEnvironment: boolean,
checkLatest: boolean checkLatest: boolean,
allowPreReleases: boolean
): Promise<InstalledVersion> { ): Promise<InstalledVersion> {
let manifest: tc.IToolRelease[] | null = null; let manifest: tc.IToolRelease[] | null = null;
const desugaredVersionSpec = desugarDevVersion(version); const desugaredVersionSpec = desugarDevVersion(version);
let semanticVersionSpec = pythonVersionToSemantic(desugaredVersionSpec); let semanticVersionSpec = pythonVersionToSemantic(
desugaredVersionSpec,
allowPreReleases
);
core.debug(`Semantic version spec of ${version} is ${semanticVersionSpec}`); core.debug(`Semantic version spec of ${version} is ${semanticVersionSpec}`);
if (checkLatest) { if (checkLatest) {
@ -85,9 +89,14 @@ export async function useCpythonVersion(
} }
if (!installDir) { if (!installDir) {
const osInfo = await getOSInfo();
throw new Error( throw new Error(
[ [
`Version ${version} with arch ${architecture} not found`, `The version '${version}' with architecture '${architecture}' was not found for ${
osInfo
? `${osInfo.osName} ${osInfo.osVersion}`
: 'this operating system'
}.`,
`The list of all available versions can be found here: ${installer.MANIFEST_URL}` `The list of all available versions can be found here: ${installer.MANIFEST_URL}`
].join(os.EOL) ].join(os.EOL)
); );
@ -173,8 +182,18 @@ interface InstalledVersion {
* Python's prelease versions look like `3.7.0b2`. * Python's prelease versions look like `3.7.0b2`.
* This is the one part of Python versioning that does not look like semantic versioning, which specifies `3.7.0-b2`. * This is the one part of Python versioning that does not look like semantic versioning, which specifies `3.7.0-b2`.
* If the version spec contains prerelease versions, we need to convert them to the semantic version equivalent. * If the version spec contains prerelease versions, we need to convert them to the semantic version equivalent.
*
* For easier use of the action, we also map 'x.y' to allow pre-release before 'x.y.0' release if allowPreReleases is true
*/ */
export function pythonVersionToSemantic(versionSpec: string) { export function pythonVersionToSemantic(
versionSpec: string,
allowPreReleases: boolean
) {
const prereleaseVersion = /(\d+\.\d+\.\d+)((?:a|b|rc)\d*)/g; const prereleaseVersion = /(\d+\.\d+\.\d+)((?:a|b|rc)\d*)/g;
return versionSpec.replace(prereleaseVersion, '$1-$2'); const majorMinor = /^(\d+)\.(\d+)$/;
let result = versionSpec.replace(prereleaseVersion, '$1-$2');
if (allowPreReleases) {
result = result.replace(majorMinor, '~$1.$2.0-0');
}
return result;
} }

View File

@ -1,3 +1,4 @@
import * as os from 'os';
import * as path from 'path'; import * as path from 'path';
import * as core from '@actions/core'; import * as core from '@actions/core';
import * as tc from '@actions/tool-cache'; import * as tc from '@actions/tool-cache';
@ -8,7 +9,6 @@ import fs from 'fs';
import { import {
IS_WINDOWS, IS_WINDOWS,
WINDOWS_ARCHS,
WINDOWS_PLATFORMS, WINDOWS_PLATFORMS,
IPyPyManifestRelease, IPyPyManifestRelease,
createSymlinkInFolder, createSymlinkInFolder,
@ -20,6 +20,7 @@ export async function installPyPy(
pypyVersion: string, pypyVersion: string,
pythonVersion: string, pythonVersion: string,
architecture: string, architecture: string,
allowPreReleases: boolean,
releases: IPyPyManifestRelease[] | undefined releases: IPyPyManifestRelease[] | undefined
) { ) {
let downloadDir; let downloadDir;
@ -30,13 +31,31 @@ export async function installPyPy(
throw new Error('No release was found in PyPy version.json'); throw new Error('No release was found in PyPy version.json');
} }
const releaseData = findRelease( let releaseData = findRelease(
releases, releases,
pythonVersion, pythonVersion,
pypyVersion, pypyVersion,
architecture architecture,
false
); );
if (allowPreReleases && (!releaseData || !releaseData.foundAsset)) {
// check for pre-release
core.info(
[
`Stable PyPy version ${pythonVersion} (${pypyVersion}) with arch ${architecture} not found`,
`Trying pre-release versions`
].join(os.EOL)
);
releaseData = findRelease(
releases,
pythonVersion,
pypyVersion,
architecture,
true
);
}
if (!releaseData || !releaseData.foundAsset) { if (!releaseData || !releaseData.foundAsset) {
throw new Error( throw new Error(
`PyPy version ${pythonVersion} (${pypyVersion}) with arch ${architecture} not found` `PyPy version ${pythonVersion} (${pypyVersion}) with arch ${architecture} not found`
@ -44,40 +63,61 @@ export async function installPyPy(
} }
const {foundAsset, resolvedPythonVersion, resolvedPyPyVersion} = releaseData; const {foundAsset, resolvedPythonVersion, resolvedPyPyVersion} = releaseData;
let downloadUrl = `${foundAsset.download_url}`; const downloadUrl = `${foundAsset.download_url}`;
core.info(`Downloading PyPy from "${downloadUrl}" ...`); core.info(`Downloading PyPy from "${downloadUrl}" ...`);
const pypyPath = await tc.downloadTool(downloadUrl);
core.info('Extracting downloaded archive...'); try {
if (IS_WINDOWS) { const pypyPath = await tc.downloadTool(downloadUrl);
downloadDir = await tc.extractZip(pypyPath);
} else { core.info('Extracting downloaded archive...');
downloadDir = await tc.extractTar(pypyPath, undefined, 'x'); if (IS_WINDOWS) {
downloadDir = await tc.extractZip(pypyPath);
} else {
downloadDir = await tc.extractTar(pypyPath, undefined, 'x');
}
// root folder in archive can have unpredictable name so just take the first folder
// downloadDir is unique folder under TEMP and can't contain any other folders
const archiveName = fs.readdirSync(downloadDir)[0];
const toolDir = path.join(downloadDir, archiveName);
let installDir = toolDir;
if (!isNightlyKeyword(resolvedPyPyVersion)) {
installDir = await tc.cacheDir(
toolDir,
'PyPy',
resolvedPythonVersion,
architecture
);
}
writeExactPyPyVersionFile(installDir, resolvedPyPyVersion);
const binaryPath = getPyPyBinaryPath(installDir);
await createPyPySymlink(binaryPath, resolvedPythonVersion);
await installPip(binaryPath);
return {installDir, resolvedPythonVersion, resolvedPyPyVersion};
} catch (err) {
if (err instanceof Error) {
// Rate limit?
if (
err instanceof tc.HTTPError &&
(err.httpStatusCode === 403 || err.httpStatusCode === 429)
) {
core.info(
`Received HTTP status code ${err.httpStatusCode}. This usually indicates the rate limit has been exceeded`
);
} else {
core.info(err.message);
}
if (err.stack !== undefined) {
core.debug(err.stack);
}
}
throw err;
} }
// root folder in archive can have unpredictable name so just take the first folder
// downloadDir is unique folder under TEMP and can't contain any other folders
const archiveName = fs.readdirSync(downloadDir)[0];
const toolDir = path.join(downloadDir, archiveName);
let installDir = toolDir;
if (!isNightlyKeyword(resolvedPyPyVersion)) {
installDir = await tc.cacheDir(
toolDir,
'PyPy',
resolvedPythonVersion,
architecture
);
}
writeExactPyPyVersionFile(installDir, resolvedPyPyVersion);
const binaryPath = getPyPyBinaryPath(installDir);
await createPyPySymlink(binaryPath, resolvedPythonVersion);
await installPip(binaryPath);
return {installDir, resolvedPythonVersion, resolvedPyPyVersion};
} }
export async function getAvailablePyPyVersions() { export async function getAvailablePyPyVersions() {
@ -103,7 +143,7 @@ async function createPyPySymlink(
const pythonMinor = semver.minor(version); const pythonMinor = semver.minor(version);
const pypyBinaryPostfix = pythonBinaryPostfix === 2 ? '' : '3'; const pypyBinaryPostfix = pythonBinaryPostfix === 2 ? '' : '3';
const pypyMajorMinorBinaryPostfix = `${pythonBinaryPostfix}.${pythonMinor}`; const pypyMajorMinorBinaryPostfix = `${pythonBinaryPostfix}.${pythonMinor}`;
let binaryExtension = IS_WINDOWS ? '.exe' : ''; const binaryExtension = IS_WINDOWS ? '.exe' : '';
core.info('Creating symlinks...'); core.info('Creating symlinks...');
createSymlinkInFolder( createSymlinkInFolder(
@ -142,8 +182,10 @@ export function findRelease(
releases: IPyPyManifestRelease[], releases: IPyPyManifestRelease[],
pythonVersion: string, pythonVersion: string,
pypyVersion: string, pypyVersion: string,
architecture: string architecture: string,
includePrerelease: boolean
) { ) {
const options = {includePrerelease: includePrerelease};
const filterReleases = releases.filter(item => { const filterReleases = releases.filter(item => {
const isPythonVersionSatisfied = semver.satisfies( const isPythonVersionSatisfied = semver.satisfies(
semver.coerce(item.python_version)!, semver.coerce(item.python_version)!,
@ -153,11 +195,15 @@ export function findRelease(
isNightlyKeyword(pypyVersion) && isNightlyKeyword(item.pypy_version); isNightlyKeyword(pypyVersion) && isNightlyKeyword(item.pypy_version);
const isPyPyVersionSatisfied = const isPyPyVersionSatisfied =
isPyPyNightly || isPyPyNightly ||
semver.satisfies(pypyVersionToSemantic(item.pypy_version), pypyVersion); semver.satisfies(
pypyVersionToSemantic(item.pypy_version),
pypyVersion,
options
);
const isArchPresent = const isArchPresent =
item.files && item.files &&
(IS_WINDOWS (IS_WINDOWS
? isArchPresentForWindows(item) ? isArchPresentForWindows(item, architecture)
: isArchPresentForMacOrLinux(item, architecture, process.platform)); : isArchPresentForMacOrLinux(item, architecture, process.platform));
return isPythonVersionSatisfied && isPyPyVersionSatisfied && isArchPresent; return isPythonVersionSatisfied && isPyPyVersionSatisfied && isArchPresent;
}); });
@ -181,13 +227,13 @@ export function findRelease(
const foundRelease = sortedReleases[0]; const foundRelease = sortedReleases[0];
const foundAsset = IS_WINDOWS const foundAsset = IS_WINDOWS
? findAssetForWindows(foundRelease) ? findAssetForWindows(foundRelease, architecture)
: findAssetForMacOrLinux(foundRelease, architecture, process.platform); : findAssetForMacOrLinux(foundRelease, architecture, process.platform);
return { return {
foundAsset, foundAsset,
resolvedPythonVersion: foundRelease.python_version, resolvedPythonVersion: foundRelease.python_version,
resolvedPyPyVersion: foundRelease.pypy_version resolvedPyPyVersion: foundRelease.pypy_version.trim()
}; };
} }
@ -205,11 +251,11 @@ export function pypyVersionToSemantic(versionSpec: string) {
return versionSpec.replace(prereleaseVersion, '$1-$2.$3'); return versionSpec.replace(prereleaseVersion, '$1-$2.$3');
} }
export function isArchPresentForWindows(item: any) { export function isArchPresentForWindows(item: any, architecture: string) {
architecture = replaceX32toX86(architecture);
return item.files.some( return item.files.some(
(file: any) => (file: any) =>
WINDOWS_ARCHS.includes(file.arch) && WINDOWS_PLATFORMS.includes(file.platform) && file.arch === architecture
WINDOWS_PLATFORMS.includes(file.platform)
); );
} }
@ -223,11 +269,11 @@ export function isArchPresentForMacOrLinux(
); );
} }
export function findAssetForWindows(releases: any) { export function findAssetForWindows(releases: any, architecture: string) {
architecture = replaceX32toX86(architecture);
return releases.files.find( return releases.files.find(
(item: any) => (item: any) =>
WINDOWS_ARCHS.includes(item.arch) && WINDOWS_PLATFORMS.includes(item.platform) && item.arch === architecture
WINDOWS_PLATFORMS.includes(item.platform)
); );
} }
@ -240,3 +286,11 @@ export function findAssetForMacOrLinux(
(item: any) => item.arch === architecture && item.platform === platform (item: any) => item.arch === architecture && item.platform === platform
); );
} }
function replaceX32toX86(architecture: string): string {
// convert x32 to x86 because os.arch() returns x32 for 32-bit systems but PyPy releases json has x86 arch value.
if (architecture === 'x32') {
architecture = 'x86';
}
return architecture;
}

View File

@ -72,15 +72,33 @@ export async function installCpythonFromRelease(release: tc.IToolRelease) {
const downloadUrl = release.files[0].download_url; const downloadUrl = release.files[0].download_url;
core.info(`Download from "${downloadUrl}"`); core.info(`Download from "${downloadUrl}"`);
const pythonPath = await tc.downloadTool(downloadUrl, undefined, AUTH); let pythonPath = '';
core.info('Extract downloaded archive'); try {
let pythonExtractedFolder; pythonPath = await tc.downloadTool(downloadUrl, undefined, AUTH);
if (IS_WINDOWS) { core.info('Extract downloaded archive');
pythonExtractedFolder = await tc.extractZip(pythonPath); let pythonExtractedFolder;
} else { if (IS_WINDOWS) {
pythonExtractedFolder = await tc.extractTar(pythonPath); pythonExtractedFolder = await tc.extractZip(pythonPath);
} } else {
pythonExtractedFolder = await tc.extractTar(pythonPath);
}
core.info('Execute installation script'); core.info('Execute installation script');
await installPython(pythonExtractedFolder); await installPython(pythonExtractedFolder);
} catch (err) {
if (err instanceof tc.HTTPError) {
// Rate limit?
if (err.httpStatusCode === 403 || err.httpStatusCode === 429) {
core.info(
`Received HTTP status code ${err.httpStatusCode}. This usually indicates the rate limit has been exceeded`
);
} else {
core.info(err.message);
}
if (err.stack) {
core.debug(err.stack);
}
}
throw err;
}
} }

View File

@ -5,7 +5,13 @@ import * as path from 'path';
import * as os from 'os'; import * as os from 'os';
import fs from 'fs'; import fs from 'fs';
import {getCacheDistributor} from './cache-distributions/cache-factory'; import {getCacheDistributor} from './cache-distributions/cache-factory';
import {isCacheFeatureAvailable, logWarning, IS_MAC} from './utils'; import {
isCacheFeatureAvailable,
logWarning,
IS_MAC,
getVersionInputFromFile,
getVersionInputFromPlainFile
} from './utils';
function isPyPyVersion(versionSpec: string) { function isPyPyVersion(versionSpec: string) {
return versionSpec.startsWith('pypy'); return versionSpec.startsWith('pypy');
@ -22,44 +28,47 @@ async function cacheDependencies(cache: string, pythonVersion: string) {
await cacheDistributor.restoreCache(); await cacheDistributor.restoreCache();
} }
function resolveVersionInput(): string { function resolveVersionInputFromDefaultFile(): string[] {
let version = core.getInput('python-version'); const couples: [string, (versionFile: string) => string[]][] = [
let versionFile = core.getInput('python-version-file'); ['.python-version', getVersionInputFromPlainFile]
];
if (version && versionFile) { for (const [versionFile, _fn] of couples) {
core.warning( logWarning(
'Both python-version and python-version-file inputs are specified, only python-version will be used.' `Neither 'python-version' nor 'python-version-file' inputs were supplied. Attempting to find '${versionFile}' file.`
); );
if (fs.existsSync(versionFile)) {
return _fn(versionFile);
} else {
logWarning(`${versionFile} doesn't exist.`);
}
} }
return [];
}
if (version) { function resolveVersionInput() {
return version; let versions = core.getMultilineInput('python-version');
} const versionFile = core.getInput('python-version-file');
if (versionFile) { if (versions.length) {
if (!fs.existsSync(versionFile)) { if (versionFile) {
throw new Error( core.warning(
`The specified python version file at: ${versionFile} doesn't exist.` 'Both python-version and python-version-file inputs are specified, only python-version will be used.'
); );
} }
version = fs.readFileSync(versionFile, 'utf8'); } else {
core.info(`Resolved ${versionFile} as ${version}`); if (versionFile) {
return version; if (!fs.existsSync(versionFile)) {
throw new Error(
`The specified python version file at: ${versionFile} doesn't exist.`
);
}
versions = getVersionInputFromFile(versionFile);
} else {
versions = resolveVersionInputFromDefaultFile();
}
} }
logWarning( return versions;
"Neither 'python-version' nor 'python-version-file' inputs were supplied. Attempting to find '.python-version' file."
);
versionFile = '.python-version';
if (fs.existsSync(versionFile)) {
version = fs.readFileSync(versionFile, 'utf8');
core.info(`Resolved ${versionFile} as ${version}`);
return version;
}
logWarning(`${versionFile} doesn't exist.`);
return version;
} }
async function run() { async function run() {
@ -75,35 +84,46 @@ async function run() {
`Python is expected to be installed into ${process.env['RUNNER_TOOL_CACHE']}` `Python is expected to be installed into ${process.env['RUNNER_TOOL_CACHE']}`
); );
try { try {
const version = resolveVersionInput(); const versions = resolveVersionInput();
const checkLatest = core.getBooleanInput('check-latest'); const checkLatest = core.getBooleanInput('check-latest');
const allowPreReleases = core.getBooleanInput('allow-prereleases');
if (version) { if (versions.length) {
let pythonVersion: string; let pythonVersion = '';
const arch: string = core.getInput('architecture') || os.arch(); const arch: string = core.getInput('architecture') || os.arch();
const updateEnvironment = core.getBooleanInput('update-environment'); const updateEnvironment = core.getBooleanInput('update-environment');
if (isPyPyVersion(version)) { core.startGroup('Installed versions');
const installed = await finderPyPy.findPyPyVersion( for (const version of versions) {
version, if (isPyPyVersion(version)) {
arch, const installed = await finderPyPy.findPyPyVersion(
updateEnvironment, version,
checkLatest arch,
); updateEnvironment,
pythonVersion = `${installed.resolvedPyPyVersion}-${installed.resolvedPythonVersion}`; checkLatest,
core.info( allowPreReleases
`Successfully set up PyPy ${installed.resolvedPyPyVersion} with Python (${installed.resolvedPythonVersion})` );
); pythonVersion = `${installed.resolvedPyPyVersion}-${installed.resolvedPythonVersion}`;
} else { core.info(
const installed = await finder.useCpythonVersion( `Successfully set up PyPy ${installed.resolvedPyPyVersion} with Python (${installed.resolvedPythonVersion})`
version, );
arch, } else {
updateEnvironment, if (version.startsWith('2')) {
checkLatest core.warning(
); 'The support for python 2.7 will be removed on June 19. Related issue: https://github.com/actions/setup-python/issues/672'
pythonVersion = installed.version; );
core.info(`Successfully set up ${installed.impl} (${pythonVersion})`); }
const installed = await finder.useCpythonVersion(
version,
arch,
updateEnvironment,
checkLatest,
allowPreReleases
);
pythonVersion = installed.version;
core.info(`Successfully set up ${installed.impl} (${pythonVersion})`);
}
} }
core.endGroup();
const cache = core.getInput('cache'); const cache = core.getInput('cache');
if (cache && isCacheFeatureAvailable()) { if (cache && isCacheFeatureAvailable()) {
await cacheDependencies(cache, pythonVersion); await cacheDependencies(cache, pythonVersion);

View File

@ -1,8 +1,10 @@
/* eslint no-unsafe-finally: "off" */
import * as cache from '@actions/cache'; import * as cache from '@actions/cache';
import * as core from '@actions/core'; import * as core from '@actions/core';
import fs from 'fs'; import fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import * as semver from 'semver'; import * as semver from 'semver';
import * as toml from '@iarna/toml';
import * as exec from '@actions/exec'; import * as exec from '@actions/exec';
export const IS_WINDOWS = process.platform === 'win32'; export const IS_WINDOWS = process.platform === 'win32';
@ -71,9 +73,9 @@ export function getPyPyVersionFromPath(installDir: string) {
*/ */
export function readExactPyPyVersionFile(installDir: string) { export function readExactPyPyVersionFile(installDir: string) {
let pypyVersion = ''; let pypyVersion = '';
let fileVersion = path.join(installDir, PYPY_VERSION_FILE); const fileVersion = path.join(installDir, PYPY_VERSION_FILE);
if (fs.existsSync(fileVersion)) { if (fs.existsSync(fileVersion)) {
pypyVersion = fs.readFileSync(fileVersion).toString(); pypyVersion = fs.readFileSync(fileVersion).toString().trim();
} }
return pypyVersion; return pypyVersion;
@ -105,40 +107,148 @@ export function isGhes(): boolean {
} }
export function isCacheFeatureAvailable(): boolean { export function isCacheFeatureAvailable(): boolean {
if (!cache.isFeatureAvailable()) { if (cache.isFeatureAvailable()) {
if (isGhes()) { return true;
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'
);
}
if (isGhes()) {
core.warning(
'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.'
);
return false; return false;
} }
return true; core.warning(
} 'The runner was not able to contact the cache service. Caching will be skipped'
export async function getLinuxOSReleaseInfo() {
const {stdout, stderr, exitCode} = await exec.getExecOutput(
'lsb_release',
['-i', '-r', '-s'],
{
silent: true
}
); );
return false;
const [osRelease, osVersion] = stdout.trim().split('\n');
core.debug(`OS Release: ${osRelease}, Version: ${osVersion}`);
return `${osVersion}-${osRelease}`;
} }
export function logWarning(message: string): void { export function logWarning(message: string): void {
const warningPrefix = '[warning]'; const warningPrefix = '[warning]';
core.info(`${warningPrefix}${message}`); core.info(`${warningPrefix}${message}`);
} }
async function getWindowsInfo() {
const {stdout} = await exec.getExecOutput(
'powershell -command "(Get-CimInstance -ClassName Win32_OperatingSystem).Caption"',
undefined,
{
silent: true
}
);
const windowsVersion = stdout.trim().split(' ')[3];
return {osName: 'Windows', osVersion: windowsVersion};
}
async function getMacOSInfo() {
const {stdout} = await exec.getExecOutput('sw_vers', ['-productVersion'], {
silent: true
});
const macOSVersion = stdout.trim();
return {osName: 'macOS', osVersion: macOSVersion};
}
export async function getLinuxInfo() {
const {stdout} = await exec.getExecOutput('lsb_release', ['-i', '-r', '-s'], {
silent: true
});
const [osName, osVersion] = stdout.trim().split('\n');
core.debug(`OS Name: ${osName}, Version: ${osVersion}`);
return {osName: osName, osVersion: osVersion};
}
export async function getOSInfo() {
let osInfo;
try {
if (IS_WINDOWS) {
osInfo = await getWindowsInfo();
} else if (IS_LINUX) {
osInfo = await getLinuxInfo();
} else if (IS_MAC) {
osInfo = await getMacOSInfo();
}
} catch (err) {
const error = err as Error;
core.debug(error.message);
} finally {
return osInfo;
}
}
/**
* Extract a value from an object by following the keys path provided.
* If the value is present, it is returned. Otherwise undefined is returned.
*/
function extractValue(obj: any, keys: string[]): string | undefined {
if (keys.length > 0) {
const value = obj[keys[0]];
if (keys.length > 1 && value !== undefined) {
return extractValue(value, keys.slice(1));
} else {
return value;
}
} else {
return;
}
}
/**
* Python version extracted from the TOML file.
* If the `project` key is present at the root level, the version is assumed to
* be specified according to PEP 621 in `project.requires-python`.
* Otherwise, if the `tool` key is present at the root level, the version is
* assumed to be specified using poetry under `tool.poetry.dependencies.python`.
* If none is present, returns an empty list.
*/
export function getVersionInputFromTomlFile(versionFile: string): string[] {
core.debug(`Trying to resolve version form ${versionFile}`);
const pyprojectFile = fs.readFileSync(versionFile, 'utf8');
const pyprojectConfig = toml.parse(pyprojectFile);
let keys = [];
if ('project' in pyprojectConfig) {
// standard project metadata (PEP 621)
keys = ['project', 'requires-python'];
} else {
// python poetry
keys = ['tool', 'poetry', 'dependencies', 'python'];
}
const versions = [];
const version = extractValue(pyprojectConfig, keys);
if (version !== undefined) {
versions.push(version);
}
core.info(`Extracted ${versions} from ${versionFile}`);
return Array.from(versions, version => version.split(',').join(' '));
}
/**
* Python version extracted from a plain text file.
*/
export function getVersionInputFromPlainFile(versionFile: string): string[] {
core.debug(`Trying to resolve version form ${versionFile}`);
const version = fs.readFileSync(versionFile, 'utf8');
core.info(`Resolved ${versionFile} as ${version}`);
return [version];
}
/**
* Python version extracted from a plain or TOML file.
*/
export function getVersionInputFromFile(versionFile: string): string[] {
if (versionFile.endsWith('.toml')) {
return getVersionInputFromTomlFile(versionFile);
} else {
return getVersionInputFromPlainFile(versionFile);
}
}

View File

@ -45,7 +45,8 @@
// "typeRoots": [], /* List of folders to include type definitions from. */ // "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */ // "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
"resolveJsonModule": true, /* Allows importing modules with a '.json' extension, which is a common practice in node projects. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */

View File

@ -1,7 +0,0 @@
extends: default
rules:
# 120 chars should be enough, but don't fail if a line is longer
line-length:
max: 120
level: warning