mirror of
https://github.com/actions/setup-python.git
synced 2025-06-24 12:41:09 +02:00
Compare commits
13 Commits
v4.3.0
...
update-cod
Author | SHA1 | Date | |
---|---|---|---|
67fd444281 | |||
5ccb29d877 | |||
c3e033939c | |||
206e984b94 | |||
2c3dd9e7e2 | |||
76bbdfadd7 | |||
1aafadcfb9 | |||
b80efd6bc5 | |||
5cddb27885 | |||
47c4a7af1d | |||
af57b64994 | |||
4818a5a153 | |||
8bcd2560e2 |
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@ -1 +1,2 @@
|
||||
* @actions/actions-service
|
||||
* @actions/runner-images-team
|
||||
|
15
.github/workflows/basic-validation.yml
vendored
Normal file
15
.github/workflows/basic-validation.yml
vendored
Normal 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
|
41
.github/workflows/check-dist.yml
vendored
41
.github/workflows/check-dist.yml
vendored
@ -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/
|
||||
|
||||
on:
|
||||
@ -17,36 +12,6 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
check-dist:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
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/
|
||||
call-check-dist:
|
||||
name: Check dist/
|
||||
uses: actions/reusable-workflows/.github/workflows/check-dist.yml@main
|
44
.github/workflows/codeql-analysis.yml
vendored
44
.github/workflows/codeql-analysis.yml
vendored
@ -1,47 +1,13 @@
|
||||
name: "Code scanning - action"
|
||||
name: CodeQL analysis
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ 'main' ]
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '25 3 * * 5'
|
||||
- cron: '0 3 * * 0'
|
||||
|
||||
jobs:
|
||||
CodeQL-Build:
|
||||
|
||||
strategy:
|
||||
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
|
||||
call-codeQL-analysis:
|
||||
name: CodeQL analysis
|
||||
uses: actions/reusable-workflows/.github/workflows/codeql-analysis.yml@main
|
@ -1,4 +1,5 @@
|
||||
name: Main workflow
|
||||
name: e2e tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
@ -8,32 +9,18 @@ on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
|
||||
jobs:
|
||||
run:
|
||||
name: Run
|
||||
test-setup-python:
|
||||
name: Test setup-python
|
||||
runs-on: ${{ matrix.operating-system }}
|
||||
strategy:
|
||||
matrix:
|
||||
operating-system: [ubuntu-latest, windows-latest]
|
||||
operating-system: [ubuntu-20.04, 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:
|
21
.github/workflows/licensed.yml
vendored
21
.github/workflows/licensed.yml
vendored
@ -9,21 +9,6 @@ on:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
name: Check licenses
|
||||
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
|
||||
call-licensed:
|
||||
name: Licensed
|
||||
uses: actions/reusable-workflows/.github/workflows/licensed.yml@main
|
@ -1,4 +1,5 @@
|
||||
name: Release new action version
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [released]
|
||||
@ -21,7 +22,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Update the ${{ env.TAG_NAME }} tag
|
||||
uses: actions/publish-action@v0.2.0
|
||||
uses: actions/publish-action@v0.2.1
|
||||
with:
|
||||
source-tag: ${{ env.TAG_NAME }}
|
||||
slack-webhook: ${{ secrets.SLACK_WEBHOOK }}
|
43
.github/workflows/test-pypy.yml
vendored
43
.github/workflows/test-pypy.yml
vendored
@ -1,4 +1,5 @@
|
||||
name: Validate PyPy e2e
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
@ -124,3 +125,45 @@ jobs:
|
||||
EXECUTABLE=${EXECUTABLE%%-*} # remove any -* suffixe
|
||||
${EXECUTABLE} --version
|
||||
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
|
32
.github/workflows/test-python.yml
vendored
32
.github/workflows/test-python.yml
vendored
@ -1,4 +1,5 @@
|
||||
name: Validate Python e2e
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
@ -190,8 +191,35 @@ jobs:
|
||||
- name: Validate version
|
||||
run: |
|
||||
$pythonVersion = (python --version)
|
||||
if ("$pythonVersion" -NotMatch "${{ matrix.python }}"){
|
||||
Write-Host "The current version is $pythonVersion; expected version is ${{ matrix.python }}"
|
||||
if ("$pythonVersion" -NotMatch "${{ matrix.python-version }}"){
|
||||
Write-Host "The current version is $pythonVersion; expected version is ${{ matrix.python-version }}"
|
||||
exit 1
|
||||
}
|
||||
$pythonVersion
|
||||
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
|
||||
|
2
.licenses/npm/minimatch.dep.yml
generated
2
.licenses/npm/minimatch.dep.yml
generated
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: minimatch
|
||||
version: 3.0.4
|
||||
version: 3.1.2
|
||||
type: npm
|
||||
summary: a glob matcher in javascript
|
||||
homepage: https://github.com/isaacs/minimatch#readme
|
||||
|
@ -33,7 +33,7 @@ steps:
|
||||
python-version: 'pypy3.9'
|
||||
- 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/).
|
||||
|
||||
|
@ -30,7 +30,6 @@ virtualenvs.path = "{cache-dir}/virtualenvs" # /Users/patrick/Library/Caches/py
|
||||
let saveSatetSpy: jest.SpyInstance;
|
||||
let getStateSpy: jest.SpyInstance;
|
||||
let setOutputSpy: jest.SpyInstance;
|
||||
let getLinuxOSReleaseInfoSpy: jest.SpyInstance;
|
||||
|
||||
// cache spy
|
||||
let restoreCacheSpy: jest.SpyInstance;
|
||||
@ -67,6 +66,9 @@ virtualenvs.path = "{cache-dir}/virtualenvs" # /Users/patrick/Library/Caches/py
|
||||
if (input.includes('poetry')) {
|
||||
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};
|
||||
});
|
||||
@ -83,7 +85,6 @@ virtualenvs.path = "{cache-dir}/virtualenvs" # /Users/patrick/Library/Caches/py
|
||||
|
||||
whichSpy = jest.spyOn(io, 'which');
|
||||
whichSpy.mockImplementation(() => '/path/to/python');
|
||||
getLinuxOSReleaseInfoSpy = jest.spyOn(utils, 'getLinuxOSReleaseInfo');
|
||||
});
|
||||
|
||||
describe('Validate provided package manager', () => {
|
||||
@ -120,17 +121,11 @@ virtualenvs.path = "{cache-dir}/virtualenvs" # /Users/patrick/Library/Caches/py
|
||||
dependencyFile
|
||||
);
|
||||
|
||||
if (process.platform === 'linux') {
|
||||
getLinuxOSReleaseInfoSpy.mockImplementation(() =>
|
||||
Promise.resolve('Ubuntu-20.4')
|
||||
);
|
||||
}
|
||||
|
||||
await cacheDistributor.restoreCache();
|
||||
|
||||
if (process.platform === 'linux' && packageManager === 'pip') {
|
||||
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 {
|
||||
expect(infoSpy).toHaveBeenCalledWith(
|
||||
|
@ -42,14 +42,13 @@ describe('validateVersion', () => {
|
||||
describe('isCacheFeatureAvailable', () => {
|
||||
it('isCacheFeatureAvailable disabled on GHES', () => {
|
||||
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 {
|
||||
process.env['GITHUB_SERVER_URL'] = 'http://example.com';
|
||||
isCacheFeatureAvailable();
|
||||
} catch (error) {
|
||||
expect(error).toHaveProperty(
|
||||
'message',
|
||||
'Caching is only supported on GHES version >= 3.5. If you are on a version >= 3.5, please check with your GHES admin if the Actions cache service is enabled or not.'
|
||||
);
|
||||
expect(isCacheFeatureAvailable()).toBeFalsy();
|
||||
expect(infoMock).toHaveBeenCalledWith(message);
|
||||
} finally {
|
||||
delete process.env['GITHUB_SERVER_URL'];
|
||||
}
|
||||
|
126
dist/cache-save/index.js
vendored
126
dist/cache-save/index.js
vendored
@ -45304,10 +45304,10 @@ function populateMaps (extensions, types) {
|
||||
module.exports = minimatch
|
||||
minimatch.Minimatch = Minimatch
|
||||
|
||||
var path = { sep: '/' }
|
||||
try {
|
||||
path = __nccwpck_require__(1017)
|
||||
} catch (er) {}
|
||||
var path = (function () { try { return __nccwpck_require__(1017) } catch (e) {}}()) || {
|
||||
sep: '/'
|
||||
}
|
||||
minimatch.sep = path.sep
|
||||
|
||||
var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {}
|
||||
var expand = __nccwpck_require__(3717)
|
||||
@ -45359,43 +45359,64 @@ function filter (pattern, options) {
|
||||
}
|
||||
|
||||
function ext (a, b) {
|
||||
a = a || {}
|
||||
b = b || {}
|
||||
var t = {}
|
||||
Object.keys(b).forEach(function (k) {
|
||||
t[k] = b[k]
|
||||
})
|
||||
Object.keys(a).forEach(function (k) {
|
||||
t[k] = a[k]
|
||||
})
|
||||
Object.keys(b).forEach(function (k) {
|
||||
t[k] = b[k]
|
||||
})
|
||||
return t
|
||||
}
|
||||
|
||||
minimatch.defaults = function (def) {
|
||||
if (!def || !Object.keys(def).length) return minimatch
|
||||
if (!def || typeof def !== 'object' || !Object.keys(def).length) {
|
||||
return minimatch
|
||||
}
|
||||
|
||||
var orig = minimatch
|
||||
|
||||
var m = function minimatch (p, pattern, options) {
|
||||
return orig.minimatch(p, pattern, ext(def, options))
|
||||
return orig(p, pattern, ext(def, options))
|
||||
}
|
||||
|
||||
m.Minimatch = function Minimatch (pattern, options) {
|
||||
return new orig.Minimatch(pattern, ext(def, options))
|
||||
}
|
||||
m.Minimatch.defaults = function defaults (options) {
|
||||
return orig.defaults(ext(def, options)).Minimatch
|
||||
}
|
||||
|
||||
m.filter = function filter (pattern, options) {
|
||||
return orig.filter(pattern, ext(def, options))
|
||||
}
|
||||
|
||||
m.defaults = function defaults (options) {
|
||||
return orig.defaults(ext(def, options))
|
||||
}
|
||||
|
||||
m.makeRe = function makeRe (pattern, options) {
|
||||
return orig.makeRe(pattern, ext(def, options))
|
||||
}
|
||||
|
||||
m.braceExpand = function braceExpand (pattern, options) {
|
||||
return orig.braceExpand(pattern, ext(def, options))
|
||||
}
|
||||
|
||||
m.match = function (list, pattern, options) {
|
||||
return orig.match(list, pattern, ext(def, options))
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
Minimatch.defaults = function (def) {
|
||||
if (!def || !Object.keys(def).length) return Minimatch
|
||||
return minimatch.defaults(def).Minimatch
|
||||
}
|
||||
|
||||
function minimatch (p, pattern, options) {
|
||||
if (typeof pattern !== 'string') {
|
||||
throw new TypeError('glob pattern string required')
|
||||
}
|
||||
assertValidPattern(pattern)
|
||||
|
||||
if (!options) options = {}
|
||||
|
||||
@ -45404,9 +45425,6 @@ function minimatch (p, pattern, options) {
|
||||
return false
|
||||
}
|
||||
|
||||
// "" only matches ""
|
||||
if (pattern.trim() === '') return p === ''
|
||||
|
||||
return new Minimatch(pattern, options).match(p)
|
||||
}
|
||||
|
||||
@ -45415,15 +45433,14 @@ function Minimatch (pattern, options) {
|
||||
return new Minimatch(pattern, options)
|
||||
}
|
||||
|
||||
if (typeof pattern !== 'string') {
|
||||
throw new TypeError('glob pattern string required')
|
||||
}
|
||||
assertValidPattern(pattern)
|
||||
|
||||
if (!options) options = {}
|
||||
|
||||
pattern = pattern.trim()
|
||||
|
||||
// windows support: need to use /, not \
|
||||
if (path.sep !== '/') {
|
||||
if (!options.allowWindowsEscape && path.sep !== '/') {
|
||||
pattern = pattern.split(path.sep).join('/')
|
||||
}
|
||||
|
||||
@ -45434,6 +45451,7 @@ function Minimatch (pattern, options) {
|
||||
this.negate = false
|
||||
this.comment = false
|
||||
this.empty = false
|
||||
this.partial = !!options.partial
|
||||
|
||||
// make the set of regexps etc.
|
||||
this.make()
|
||||
@ -45443,9 +45461,6 @@ Minimatch.prototype.debug = function () {}
|
||||
|
||||
Minimatch.prototype.make = make
|
||||
function make () {
|
||||
// don't do it more than once.
|
||||
if (this._made) return
|
||||
|
||||
var pattern = this.pattern
|
||||
var options = this.options
|
||||
|
||||
@ -45465,7 +45480,7 @@ function make () {
|
||||
// step 2: expand braces
|
||||
var set = this.globSet = this.braceExpand()
|
||||
|
||||
if (options.debug) this.debug = console.error
|
||||
if (options.debug) this.debug = function debug() { console.error.apply(console, arguments) }
|
||||
|
||||
this.debug(this.pattern, set)
|
||||
|
||||
@ -45545,12 +45560,11 @@ function braceExpand (pattern, options) {
|
||||
pattern = typeof pattern === 'undefined'
|
||||
? this.pattern : pattern
|
||||
|
||||
if (typeof pattern === 'undefined') {
|
||||
throw new TypeError('undefined pattern')
|
||||
}
|
||||
assertValidPattern(pattern)
|
||||
|
||||
if (options.nobrace ||
|
||||
!pattern.match(/\{.*\}/)) {
|
||||
// Thanks to Yeting Li <https://github.com/yetingli> for
|
||||
// improving this regexp to avoid a ReDOS vulnerability.
|
||||
if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
|
||||
// shortcut. no need to expand.
|
||||
return [pattern]
|
||||
}
|
||||
@ -45558,6 +45572,17 @@ function braceExpand (pattern, options) {
|
||||
return expand(pattern)
|
||||
}
|
||||
|
||||
var MAX_PATTERN_LENGTH = 1024 * 64
|
||||
var assertValidPattern = function (pattern) {
|
||||
if (typeof pattern !== 'string') {
|
||||
throw new TypeError('invalid pattern')
|
||||
}
|
||||
|
||||
if (pattern.length > MAX_PATTERN_LENGTH) {
|
||||
throw new TypeError('pattern is too long')
|
||||
}
|
||||
}
|
||||
|
||||
// parse a component of the expanded set.
|
||||
// At this point, no pattern may contain "/" in it
|
||||
// so we're going to return a 2d array, where each entry is the full
|
||||
@ -45572,14 +45597,17 @@ function braceExpand (pattern, options) {
|
||||
Minimatch.prototype.parse = parse
|
||||
var SUBPARSE = {}
|
||||
function parse (pattern, isSub) {
|
||||
if (pattern.length > 1024 * 64) {
|
||||
throw new TypeError('pattern is too long')
|
||||
}
|
||||
assertValidPattern(pattern)
|
||||
|
||||
var options = this.options
|
||||
|
||||
// shortcuts
|
||||
if (!options.noglobstar && pattern === '**') return GLOBSTAR
|
||||
if (pattern === '**') {
|
||||
if (!options.noglobstar)
|
||||
return GLOBSTAR
|
||||
else
|
||||
pattern = '*'
|
||||
}
|
||||
if (pattern === '') return ''
|
||||
|
||||
var re = ''
|
||||
@ -45635,10 +45663,12 @@ function parse (pattern, isSub) {
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case '/':
|
||||
/* istanbul ignore next */
|
||||
case '/': {
|
||||
// completely not allowed, even escaped.
|
||||
// Should already be path-split by now.
|
||||
return false
|
||||
}
|
||||
|
||||
case '\\':
|
||||
clearStateChar()
|
||||
@ -45757,7 +45787,6 @@ function parse (pattern, isSub) {
|
||||
|
||||
// handle the case where we left a class open.
|
||||
// "[z-a]" is valid, equivalent to "\[z-a\]"
|
||||
if (inClass) {
|
||||
// split where the last [ was, make sure we don't have
|
||||
// an invalid re. if so, re-walk the contents of the
|
||||
// would-be class to re-translate any characters that
|
||||
@ -45776,7 +45805,6 @@ function parse (pattern, isSub) {
|
||||
inClass = false
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// finish up the class.
|
||||
hasMagic = true
|
||||
@ -45859,9 +45887,7 @@ function parse (pattern, isSub) {
|
||||
// something that could conceivably capture a dot
|
||||
var addPatternStart = false
|
||||
switch (re.charAt(0)) {
|
||||
case '.':
|
||||
case '[':
|
||||
case '(': addPatternStart = true
|
||||
case '[': case '.': case '(': addPatternStart = true
|
||||
}
|
||||
|
||||
// Hack to work around lack of negative lookbehind in JS
|
||||
@ -45923,7 +45949,7 @@ function parse (pattern, isSub) {
|
||||
var flags = options.nocase ? 'i' : ''
|
||||
try {
|
||||
var regExp = new RegExp('^' + re + '$', flags)
|
||||
} catch (er) {
|
||||
} catch (er) /* istanbul ignore next - should be impossible */ {
|
||||
// If it was an invalid regular expression, then it can't match
|
||||
// anything. This trick looks for a character after the end of
|
||||
// the string, which is of course impossible, except in multi-line
|
||||
@ -45981,7 +46007,7 @@ function makeRe () {
|
||||
|
||||
try {
|
||||
this.regexp = new RegExp(re, flags)
|
||||
} catch (ex) {
|
||||
} catch (ex) /* istanbul ignore next - should be impossible */ {
|
||||
this.regexp = false
|
||||
}
|
||||
return this.regexp
|
||||
@ -45999,8 +46025,8 @@ minimatch.match = function (list, pattern, options) {
|
||||
return list
|
||||
}
|
||||
|
||||
Minimatch.prototype.match = match
|
||||
function match (f, partial) {
|
||||
Minimatch.prototype.match = function match (f, partial) {
|
||||
if (typeof partial === 'undefined') partial = this.partial
|
||||
this.debug('match', f, this.pattern)
|
||||
// short-circuit in the case of busted things.
|
||||
// comments, etc.
|
||||
@ -46082,6 +46108,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
|
||||
|
||||
// should be impossible.
|
||||
// some invalid regexp stuff in the set.
|
||||
/* istanbul ignore if */
|
||||
if (p === false) return false
|
||||
|
||||
if (p === GLOBSTAR) {
|
||||
@ -46155,6 +46182,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
|
||||
// no match was found.
|
||||
// However, in partial mode, we can't say this is necessarily over.
|
||||
// If there's more *pattern* left, then
|
||||
/* istanbul ignore if */
|
||||
if (partial) {
|
||||
// ran out of file
|
||||
this.debug('\n>>> no match, partial?', file, fr, pattern, pr)
|
||||
@ -46168,11 +46196,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
|
||||
// patterns with magic have been turned into regexps.
|
||||
var hit
|
||||
if (typeof p === 'string') {
|
||||
if (options.nocase) {
|
||||
hit = f.toLowerCase() === p.toLowerCase()
|
||||
} else {
|
||||
hit = f === p
|
||||
}
|
||||
this.debug('string match', p, f, hit)
|
||||
} else {
|
||||
hit = f.match(p)
|
||||
@ -46203,16 +46227,16 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
|
||||
// this is ok if we're doing the match as part of
|
||||
// a glob fs traversal.
|
||||
return partial
|
||||
} else if (pi === pl) {
|
||||
} else /* istanbul ignore else */ if (pi === pl) {
|
||||
// ran out of pattern, still have file left.
|
||||
// this is only acceptable if we're on the very last
|
||||
// empty segment of a file with a trailing slash.
|
||||
// a/* should match a/b/
|
||||
var emptyFileEnd = (fi === fl - 1) && (file[fi] === '')
|
||||
return emptyFileEnd
|
||||
return (fi === fl - 1) && (file[fi] === '')
|
||||
}
|
||||
|
||||
// should be unreachable.
|
||||
/* istanbul ignore next */
|
||||
throw new Error('wtf?')
|
||||
}
|
||||
|
||||
|
309
dist/setup/index.js
vendored
309
dist/setup/index.js
vendored
@ -49469,10 +49469,10 @@ function populateMaps (extensions, types) {
|
||||
module.exports = minimatch
|
||||
minimatch.Minimatch = Minimatch
|
||||
|
||||
var path = { sep: '/' }
|
||||
try {
|
||||
path = __nccwpck_require__(1017)
|
||||
} catch (er) {}
|
||||
var path = (function () { try { return __nccwpck_require__(1017) } catch (e) {}}()) || {
|
||||
sep: '/'
|
||||
}
|
||||
minimatch.sep = path.sep
|
||||
|
||||
var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {}
|
||||
var expand = __nccwpck_require__(3717)
|
||||
@ -49524,43 +49524,64 @@ function filter (pattern, options) {
|
||||
}
|
||||
|
||||
function ext (a, b) {
|
||||
a = a || {}
|
||||
b = b || {}
|
||||
var t = {}
|
||||
Object.keys(b).forEach(function (k) {
|
||||
t[k] = b[k]
|
||||
})
|
||||
Object.keys(a).forEach(function (k) {
|
||||
t[k] = a[k]
|
||||
})
|
||||
Object.keys(b).forEach(function (k) {
|
||||
t[k] = b[k]
|
||||
})
|
||||
return t
|
||||
}
|
||||
|
||||
minimatch.defaults = function (def) {
|
||||
if (!def || !Object.keys(def).length) return minimatch
|
||||
if (!def || typeof def !== 'object' || !Object.keys(def).length) {
|
||||
return minimatch
|
||||
}
|
||||
|
||||
var orig = minimatch
|
||||
|
||||
var m = function minimatch (p, pattern, options) {
|
||||
return orig.minimatch(p, pattern, ext(def, options))
|
||||
return orig(p, pattern, ext(def, options))
|
||||
}
|
||||
|
||||
m.Minimatch = function Minimatch (pattern, options) {
|
||||
return new orig.Minimatch(pattern, ext(def, options))
|
||||
}
|
||||
m.Minimatch.defaults = function defaults (options) {
|
||||
return orig.defaults(ext(def, options)).Minimatch
|
||||
}
|
||||
|
||||
m.filter = function filter (pattern, options) {
|
||||
return orig.filter(pattern, ext(def, options))
|
||||
}
|
||||
|
||||
m.defaults = function defaults (options) {
|
||||
return orig.defaults(ext(def, options))
|
||||
}
|
||||
|
||||
m.makeRe = function makeRe (pattern, options) {
|
||||
return orig.makeRe(pattern, ext(def, options))
|
||||
}
|
||||
|
||||
m.braceExpand = function braceExpand (pattern, options) {
|
||||
return orig.braceExpand(pattern, ext(def, options))
|
||||
}
|
||||
|
||||
m.match = function (list, pattern, options) {
|
||||
return orig.match(list, pattern, ext(def, options))
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
Minimatch.defaults = function (def) {
|
||||
if (!def || !Object.keys(def).length) return Minimatch
|
||||
return minimatch.defaults(def).Minimatch
|
||||
}
|
||||
|
||||
function minimatch (p, pattern, options) {
|
||||
if (typeof pattern !== 'string') {
|
||||
throw new TypeError('glob pattern string required')
|
||||
}
|
||||
assertValidPattern(pattern)
|
||||
|
||||
if (!options) options = {}
|
||||
|
||||
@ -49569,9 +49590,6 @@ function minimatch (p, pattern, options) {
|
||||
return false
|
||||
}
|
||||
|
||||
// "" only matches ""
|
||||
if (pattern.trim() === '') return p === ''
|
||||
|
||||
return new Minimatch(pattern, options).match(p)
|
||||
}
|
||||
|
||||
@ -49580,15 +49598,14 @@ function Minimatch (pattern, options) {
|
||||
return new Minimatch(pattern, options)
|
||||
}
|
||||
|
||||
if (typeof pattern !== 'string') {
|
||||
throw new TypeError('glob pattern string required')
|
||||
}
|
||||
assertValidPattern(pattern)
|
||||
|
||||
if (!options) options = {}
|
||||
|
||||
pattern = pattern.trim()
|
||||
|
||||
// windows support: need to use /, not \
|
||||
if (path.sep !== '/') {
|
||||
if (!options.allowWindowsEscape && path.sep !== '/') {
|
||||
pattern = pattern.split(path.sep).join('/')
|
||||
}
|
||||
|
||||
@ -49599,6 +49616,7 @@ function Minimatch (pattern, options) {
|
||||
this.negate = false
|
||||
this.comment = false
|
||||
this.empty = false
|
||||
this.partial = !!options.partial
|
||||
|
||||
// make the set of regexps etc.
|
||||
this.make()
|
||||
@ -49608,9 +49626,6 @@ Minimatch.prototype.debug = function () {}
|
||||
|
||||
Minimatch.prototype.make = make
|
||||
function make () {
|
||||
// don't do it more than once.
|
||||
if (this._made) return
|
||||
|
||||
var pattern = this.pattern
|
||||
var options = this.options
|
||||
|
||||
@ -49630,7 +49645,7 @@ function make () {
|
||||
// step 2: expand braces
|
||||
var set = this.globSet = this.braceExpand()
|
||||
|
||||
if (options.debug) this.debug = console.error
|
||||
if (options.debug) this.debug = function debug() { console.error.apply(console, arguments) }
|
||||
|
||||
this.debug(this.pattern, set)
|
||||
|
||||
@ -49710,12 +49725,11 @@ function braceExpand (pattern, options) {
|
||||
pattern = typeof pattern === 'undefined'
|
||||
? this.pattern : pattern
|
||||
|
||||
if (typeof pattern === 'undefined') {
|
||||
throw new TypeError('undefined pattern')
|
||||
}
|
||||
assertValidPattern(pattern)
|
||||
|
||||
if (options.nobrace ||
|
||||
!pattern.match(/\{.*\}/)) {
|
||||
// Thanks to Yeting Li <https://github.com/yetingli> for
|
||||
// improving this regexp to avoid a ReDOS vulnerability.
|
||||
if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
|
||||
// shortcut. no need to expand.
|
||||
return [pattern]
|
||||
}
|
||||
@ -49723,6 +49737,17 @@ function braceExpand (pattern, options) {
|
||||
return expand(pattern)
|
||||
}
|
||||
|
||||
var MAX_PATTERN_LENGTH = 1024 * 64
|
||||
var assertValidPattern = function (pattern) {
|
||||
if (typeof pattern !== 'string') {
|
||||
throw new TypeError('invalid pattern')
|
||||
}
|
||||
|
||||
if (pattern.length > MAX_PATTERN_LENGTH) {
|
||||
throw new TypeError('pattern is too long')
|
||||
}
|
||||
}
|
||||
|
||||
// parse a component of the expanded set.
|
||||
// At this point, no pattern may contain "/" in it
|
||||
// so we're going to return a 2d array, where each entry is the full
|
||||
@ -49737,14 +49762,17 @@ function braceExpand (pattern, options) {
|
||||
Minimatch.prototype.parse = parse
|
||||
var SUBPARSE = {}
|
||||
function parse (pattern, isSub) {
|
||||
if (pattern.length > 1024 * 64) {
|
||||
throw new TypeError('pattern is too long')
|
||||
}
|
||||
assertValidPattern(pattern)
|
||||
|
||||
var options = this.options
|
||||
|
||||
// shortcuts
|
||||
if (!options.noglobstar && pattern === '**') return GLOBSTAR
|
||||
if (pattern === '**') {
|
||||
if (!options.noglobstar)
|
||||
return GLOBSTAR
|
||||
else
|
||||
pattern = '*'
|
||||
}
|
||||
if (pattern === '') return ''
|
||||
|
||||
var re = ''
|
||||
@ -49800,10 +49828,12 @@ function parse (pattern, isSub) {
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case '/':
|
||||
/* istanbul ignore next */
|
||||
case '/': {
|
||||
// completely not allowed, even escaped.
|
||||
// Should already be path-split by now.
|
||||
return false
|
||||
}
|
||||
|
||||
case '\\':
|
||||
clearStateChar()
|
||||
@ -49922,7 +49952,6 @@ function parse (pattern, isSub) {
|
||||
|
||||
// handle the case where we left a class open.
|
||||
// "[z-a]" is valid, equivalent to "\[z-a\]"
|
||||
if (inClass) {
|
||||
// split where the last [ was, make sure we don't have
|
||||
// an invalid re. if so, re-walk the contents of the
|
||||
// would-be class to re-translate any characters that
|
||||
@ -49941,7 +49970,6 @@ function parse (pattern, isSub) {
|
||||
inClass = false
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// finish up the class.
|
||||
hasMagic = true
|
||||
@ -50024,9 +50052,7 @@ function parse (pattern, isSub) {
|
||||
// something that could conceivably capture a dot
|
||||
var addPatternStart = false
|
||||
switch (re.charAt(0)) {
|
||||
case '.':
|
||||
case '[':
|
||||
case '(': addPatternStart = true
|
||||
case '[': case '.': case '(': addPatternStart = true
|
||||
}
|
||||
|
||||
// Hack to work around lack of negative lookbehind in JS
|
||||
@ -50088,7 +50114,7 @@ function parse (pattern, isSub) {
|
||||
var flags = options.nocase ? 'i' : ''
|
||||
try {
|
||||
var regExp = new RegExp('^' + re + '$', flags)
|
||||
} catch (er) {
|
||||
} catch (er) /* istanbul ignore next - should be impossible */ {
|
||||
// If it was an invalid regular expression, then it can't match
|
||||
// anything. This trick looks for a character after the end of
|
||||
// the string, which is of course impossible, except in multi-line
|
||||
@ -50146,7 +50172,7 @@ function makeRe () {
|
||||
|
||||
try {
|
||||
this.regexp = new RegExp(re, flags)
|
||||
} catch (ex) {
|
||||
} catch (ex) /* istanbul ignore next - should be impossible */ {
|
||||
this.regexp = false
|
||||
}
|
||||
return this.regexp
|
||||
@ -50164,8 +50190,8 @@ minimatch.match = function (list, pattern, options) {
|
||||
return list
|
||||
}
|
||||
|
||||
Minimatch.prototype.match = match
|
||||
function match (f, partial) {
|
||||
Minimatch.prototype.match = function match (f, partial) {
|
||||
if (typeof partial === 'undefined') partial = this.partial
|
||||
this.debug('match', f, this.pattern)
|
||||
// short-circuit in the case of busted things.
|
||||
// comments, etc.
|
||||
@ -50247,6 +50273,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
|
||||
|
||||
// should be impossible.
|
||||
// some invalid regexp stuff in the set.
|
||||
/* istanbul ignore if */
|
||||
if (p === false) return false
|
||||
|
||||
if (p === GLOBSTAR) {
|
||||
@ -50320,6 +50347,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
|
||||
// no match was found.
|
||||
// However, in partial mode, we can't say this is necessarily over.
|
||||
// If there's more *pattern* left, then
|
||||
/* istanbul ignore if */
|
||||
if (partial) {
|
||||
// ran out of file
|
||||
this.debug('\n>>> no match, partial?', file, fr, pattern, pr)
|
||||
@ -50333,11 +50361,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
|
||||
// patterns with magic have been turned into regexps.
|
||||
var hit
|
||||
if (typeof p === 'string') {
|
||||
if (options.nocase) {
|
||||
hit = f.toLowerCase() === p.toLowerCase()
|
||||
} else {
|
||||
hit = f === p
|
||||
}
|
||||
this.debug('string match', p, f, hit)
|
||||
} else {
|
||||
hit = f.match(p)
|
||||
@ -50368,16 +50392,16 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) {
|
||||
// this is ok if we're doing the match as part of
|
||||
// a glob fs traversal.
|
||||
return partial
|
||||
} else if (pi === pl) {
|
||||
} else /* istanbul ignore else */ if (pi === pl) {
|
||||
// ran out of pattern, still have file left.
|
||||
// this is only acceptable if we're on the very last
|
||||
// empty segment of a file with a trailing slash.
|
||||
// a/* should match a/b/
|
||||
var emptyFileEnd = (fi === fl - 1) && (file[fi] === '')
|
||||
return emptyFileEnd
|
||||
return (fi === fl - 1) && (file[fi] === '')
|
||||
}
|
||||
|
||||
// should be unreachable.
|
||||
/* istanbul ignore next */
|
||||
throw new Error('wtf?')
|
||||
}
|
||||
|
||||
@ -65919,9 +65943,9 @@ class PipCache extends cache_distributor_1.default {
|
||||
let primaryKey = '';
|
||||
let restoreKey = '';
|
||||
if (utils_1.IS_LINUX) {
|
||||
const osRelease = yield utils_1.getLinuxOSReleaseInfo();
|
||||
primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${osRelease}-python-${this.pythonVersion}-${this.packageManager}-${hash}`;
|
||||
restoreKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${osRelease}-python-${this.pythonVersion}-${this.packageManager}`;
|
||||
const osInfo = yield utils_1.getLinuxInfo();
|
||||
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']}-${osInfo.osVersion}-${osInfo.osName}-python-${this.pythonVersion}-${this.packageManager}`;
|
||||
}
|
||||
else {
|
||||
primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-python-${this.pythonVersion}-${this.packageManager}-${hash}`;
|
||||
@ -66377,8 +66401,11 @@ function useCpythonVersion(version, architecture, updateEnvironment, checkLatest
|
||||
}
|
||||
}
|
||||
if (!installDir) {
|
||||
const osInfo = yield utils_1.getOSInfo();
|
||||
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}`
|
||||
].join(os.EOL));
|
||||
}
|
||||
@ -66511,6 +66538,7 @@ function installPyPy(pypyVersion, pythonVersion, architecture, releases) {
|
||||
const { foundAsset, resolvedPythonVersion, resolvedPyPyVersion } = releaseData;
|
||||
let downloadUrl = `${foundAsset.download_url}`;
|
||||
core.info(`Downloading PyPy from "${downloadUrl}" ...`);
|
||||
try {
|
||||
const pypyPath = yield tc.downloadTool(downloadUrl);
|
||||
core.info('Extracting downloaded archive...');
|
||||
if (utils_1.IS_WINDOWS) {
|
||||
@ -66532,6 +66560,23 @@ function installPyPy(pypyVersion, pythonVersion, architecture, releases) {
|
||||
yield createPyPySymlink(binaryPath, resolvedPythonVersion);
|
||||
yield 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;
|
||||
}
|
||||
});
|
||||
}
|
||||
exports.installPyPy = installPyPy;
|
||||
@ -66577,7 +66622,7 @@ function findRelease(releases, pythonVersion, pypyVersion, architecture) {
|
||||
semver.satisfies(pypyVersionToSemantic(item.pypy_version), pypyVersion);
|
||||
const isArchPresent = item.files &&
|
||||
(utils_1.IS_WINDOWS
|
||||
? isArchPresentForWindows(item)
|
||||
? isArchPresentForWindows(item, architecture)
|
||||
: isArchPresentForMacOrLinux(item, architecture, process.platform));
|
||||
return isPythonVersionSatisfied && isPyPyVersionSatisfied && isArchPresent;
|
||||
});
|
||||
@ -66590,7 +66635,7 @@ function findRelease(releases, pythonVersion, pypyVersion, architecture) {
|
||||
});
|
||||
const foundRelease = sortedReleases[0];
|
||||
const foundAsset = utils_1.IS_WINDOWS
|
||||
? findAssetForWindows(foundRelease)
|
||||
? findAssetForWindows(foundRelease, architecture)
|
||||
: findAssetForMacOrLinux(foundRelease, architecture, process.platform);
|
||||
return {
|
||||
foundAsset,
|
||||
@ -66613,24 +66658,31 @@ function pypyVersionToSemantic(versionSpec) {
|
||||
return versionSpec.replace(prereleaseVersion, '$1-$2.$3');
|
||||
}
|
||||
exports.pypyVersionToSemantic = pypyVersionToSemantic;
|
||||
function isArchPresentForWindows(item) {
|
||||
return item.files.some((file) => utils_1.WINDOWS_ARCHS.includes(file.arch) &&
|
||||
utils_1.WINDOWS_PLATFORMS.includes(file.platform));
|
||||
function isArchPresentForWindows(item, architecture) {
|
||||
architecture = replaceX32toX86(architecture);
|
||||
return item.files.some((file) => utils_1.WINDOWS_PLATFORMS.includes(file.platform) && file.arch === architecture);
|
||||
}
|
||||
exports.isArchPresentForWindows = isArchPresentForWindows;
|
||||
function isArchPresentForMacOrLinux(item, architecture, platform) {
|
||||
return item.files.some((file) => file.arch === architecture && file.platform === platform);
|
||||
}
|
||||
exports.isArchPresentForMacOrLinux = isArchPresentForMacOrLinux;
|
||||
function findAssetForWindows(releases) {
|
||||
return releases.files.find((item) => utils_1.WINDOWS_ARCHS.includes(item.arch) &&
|
||||
utils_1.WINDOWS_PLATFORMS.includes(item.platform));
|
||||
function findAssetForWindows(releases, architecture) {
|
||||
architecture = replaceX32toX86(architecture);
|
||||
return releases.files.find((item) => utils_1.WINDOWS_PLATFORMS.includes(item.platform) && item.arch === architecture);
|
||||
}
|
||||
exports.findAssetForWindows = findAssetForWindows;
|
||||
function findAssetForMacOrLinux(releases, architecture, platform) {
|
||||
return releases.files.find((item) => item.arch === architecture && item.platform === platform);
|
||||
}
|
||||
exports.findAssetForMacOrLinux = findAssetForMacOrLinux;
|
||||
function replaceX32toX86(architecture) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
/***/ }),
|
||||
@ -66723,7 +66775,9 @@ function installCpythonFromRelease(release) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const downloadUrl = release.files[0].download_url;
|
||||
core.info(`Download from "${downloadUrl}"`);
|
||||
const pythonPath = yield tc.downloadTool(downloadUrl, undefined, AUTH);
|
||||
let pythonPath = '';
|
||||
try {
|
||||
pythonPath = yield tc.downloadTool(downloadUrl, undefined, AUTH);
|
||||
core.info('Extract downloaded archive');
|
||||
let pythonExtractedFolder;
|
||||
if (utils_1.IS_WINDOWS) {
|
||||
@ -66734,6 +66788,22 @@ function installCpythonFromRelease(release) {
|
||||
}
|
||||
core.info('Execute installation script');
|
||||
yield 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;
|
||||
}
|
||||
});
|
||||
}
|
||||
exports.installCpythonFromRelease = installCpythonFromRelease;
|
||||
@ -66797,31 +66867,31 @@ function cacheDependencies(cache, pythonVersion) {
|
||||
});
|
||||
}
|
||||
function resolveVersionInput() {
|
||||
let version = core.getInput('python-version');
|
||||
let versions = core.getMultilineInput('python-version');
|
||||
let versionFile = core.getInput('python-version-file');
|
||||
if (version && versionFile) {
|
||||
if (versions.length && versionFile) {
|
||||
core.warning('Both python-version and python-version-file inputs are specified, only python-version will be used.');
|
||||
}
|
||||
if (version) {
|
||||
return version;
|
||||
if (versions.length) {
|
||||
return versions;
|
||||
}
|
||||
if (versionFile) {
|
||||
if (!fs_1.default.existsSync(versionFile)) {
|
||||
throw new Error(`The specified python version file at: ${versionFile} doesn't exist.`);
|
||||
}
|
||||
version = fs_1.default.readFileSync(versionFile, 'utf8');
|
||||
const version = fs_1.default.readFileSync(versionFile, 'utf8');
|
||||
core.info(`Resolved ${versionFile} as ${version}`);
|
||||
return version;
|
||||
return [version];
|
||||
}
|
||||
utils_1.logWarning("Neither 'python-version' nor 'python-version-file' inputs were supplied. Attempting to find '.python-version' file.");
|
||||
versionFile = '.python-version';
|
||||
if (fs_1.default.existsSync(versionFile)) {
|
||||
version = fs_1.default.readFileSync(versionFile, 'utf8');
|
||||
const version = fs_1.default.readFileSync(versionFile, 'utf8');
|
||||
core.info(`Resolved ${versionFile} as ${version}`);
|
||||
return version;
|
||||
return [version];
|
||||
}
|
||||
utils_1.logWarning(`${versionFile} doesn't exist.`);
|
||||
return version;
|
||||
return versions;
|
||||
}
|
||||
function run() {
|
||||
var _a;
|
||||
@ -66834,12 +66904,14 @@ function run() {
|
||||
}
|
||||
core.debug(`Python is expected to be installed into ${process.env['RUNNER_TOOL_CACHE']}`);
|
||||
try {
|
||||
const version = resolveVersionInput();
|
||||
const versions = resolveVersionInput();
|
||||
const checkLatest = core.getBooleanInput('check-latest');
|
||||
if (version) {
|
||||
let pythonVersion;
|
||||
if (versions.length) {
|
||||
let pythonVersion = '';
|
||||
const arch = core.getInput('architecture') || os.arch();
|
||||
const updateEnvironment = core.getBooleanInput('update-environment');
|
||||
core.startGroup('Installed versions');
|
||||
for (const version of versions) {
|
||||
if (isPyPyVersion(version)) {
|
||||
const installed = yield finderPyPy.findPyPyVersion(version, arch, updateEnvironment, checkLatest);
|
||||
pythonVersion = `${installed.resolvedPyPyVersion}-${installed.resolvedPythonVersion}`;
|
||||
@ -66850,6 +66922,8 @@ function run() {
|
||||
pythonVersion = installed.version;
|
||||
core.info(`Successfully set up ${installed.impl} (${pythonVersion})`);
|
||||
}
|
||||
}
|
||||
core.endGroup();
|
||||
const cache = core.getInput('cache');
|
||||
if (cache && utils_1.isCacheFeatureAvailable()) {
|
||||
yield cacheDependencies(cache, pythonVersion);
|
||||
@ -66908,7 +66982,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.logWarning = exports.getLinuxOSReleaseInfo = exports.isCacheFeatureAvailable = exports.isGhes = exports.validatePythonVersionFormatForPyPy = exports.writeExactPyPyVersionFile = exports.readExactPyPyVersionFile = exports.getPyPyVersionFromPath = exports.isNightlyKeyword = exports.validateVersion = exports.createSymlinkInFolder = exports.WINDOWS_PLATFORMS = exports.WINDOWS_ARCHS = exports.IS_MAC = exports.IS_LINUX = exports.IS_WINDOWS = void 0;
|
||||
exports.getOSInfo = exports.getLinuxInfo = exports.logWarning = exports.isCacheFeatureAvailable = exports.isGhes = exports.validatePythonVersionFormatForPyPy = exports.writeExactPyPyVersionFile = exports.readExactPyPyVersionFile = exports.getPyPyVersionFromPath = exports.isNightlyKeyword = exports.validateVersion = exports.createSymlinkInFolder = exports.WINDOWS_PLATFORMS = exports.WINDOWS_ARCHS = exports.IS_MAC = exports.IS_LINUX = exports.IS_WINDOWS = void 0;
|
||||
const cache = __importStar(__nccwpck_require__(7799));
|
||||
const core = __importStar(__nccwpck_require__(2186));
|
||||
const fs_1 = __importDefault(__nccwpck_require__(7147));
|
||||
@ -66987,34 +67061,75 @@ function isGhes() {
|
||||
}
|
||||
exports.isGhes = isGhes;
|
||||
function isCacheFeatureAvailable() {
|
||||
if (!cache.isFeatureAvailable()) {
|
||||
if (isGhes()) {
|
||||
throw new Error('Caching is only supported on GHES version >= 3.5. If you are on a version >= 3.5, please check with your GHES admin if the Actions cache service is enabled or not.');
|
||||
}
|
||||
else {
|
||||
core.warning('The runner was not able to contact the cache service. Caching will be skipped');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (cache.isFeatureAvailable()) {
|
||||
return true;
|
||||
}
|
||||
exports.isCacheFeatureAvailable = isCacheFeatureAvailable;
|
||||
function getLinuxOSReleaseInfo() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const { stdout, stderr, exitCode } = yield exec.getExecOutput('lsb_release', ['-i', '-r', '-s'], {
|
||||
silent: true
|
||||
});
|
||||
const [osRelease, osVersion] = stdout.trim().split('\n');
|
||||
core.debug(`OS Release: ${osRelease}, Version: ${osVersion}`);
|
||||
return `${osVersion}-${osRelease}`;
|
||||
});
|
||||
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;
|
||||
}
|
||||
exports.getLinuxOSReleaseInfo = getLinuxOSReleaseInfo;
|
||||
core.warning('The runner was not able to contact the cache service. Caching will be skipped');
|
||||
return false;
|
||||
}
|
||||
exports.isCacheFeatureAvailable = isCacheFeatureAvailable;
|
||||
function logWarning(message) {
|
||||
const warningPrefix = '[warning]';
|
||||
core.info(`${warningPrefix}${message}`);
|
||||
}
|
||||
exports.logWarning = logWarning;
|
||||
function getWindowsInfo() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const { stdout } = yield exec.getExecOutput('powershell -command "(Get-CimInstance -ClassName Win32_OperatingSystem).Caption"', undefined, {
|
||||
silent: true
|
||||
});
|
||||
const windowsVersion = stdout.trim().split(' ')[3];
|
||||
return { osName: 'Windows', osVersion: windowsVersion };
|
||||
});
|
||||
}
|
||||
function getMacOSInfo() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const { stdout } = yield exec.getExecOutput('sw_vers', ['-productVersion'], {
|
||||
silent: true
|
||||
});
|
||||
const macOSVersion = stdout.trim();
|
||||
return { osName: 'macOS', osVersion: macOSVersion };
|
||||
});
|
||||
}
|
||||
function getLinuxInfo() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const { stdout } = yield 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 };
|
||||
});
|
||||
}
|
||||
exports.getLinuxInfo = getLinuxInfo;
|
||||
function getOSInfo() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let osInfo;
|
||||
try {
|
||||
if (exports.IS_WINDOWS) {
|
||||
osInfo = yield getWindowsInfo();
|
||||
}
|
||||
else if (exports.IS_LINUX) {
|
||||
osInfo = yield getLinuxInfo();
|
||||
}
|
||||
else if (exports.IS_MAC) {
|
||||
osInfo = yield getMacOSInfo();
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
const error = err;
|
||||
core.debug(error.message);
|
||||
}
|
||||
finally {
|
||||
return osInfo;
|
||||
}
|
||||
});
|
||||
}
|
||||
exports.getOSInfo = getOSInfo;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
@ -2,6 +2,7 @@
|
||||
- [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 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)
|
||||
- [Using the python-version-file input](advanced-usage.md#using-the-python-version-file-input)
|
||||
- [Check latest version](advanced-usage.md#check-latest-version)
|
||||
@ -132,6 +133,62 @@ jobs:
|
||||
```
|
||||
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
|
||||
|
||||
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:
|
||||
@ -281,6 +338,20 @@ steps:
|
||||
- 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
|
||||
@ -471,15 +542,29 @@ One quick way to grant access is to change the user and group of `/Users/runner/
|
||||
|
||||
## 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
|
||||
uses: actions/setup-python@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@4
|
||||
with:
|
||||
token: ${{ secrets.GH_DOTCOM_TOKEN }}
|
||||
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@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.
|
||||
|
12
package-lock.json
generated
12
package-lock.json
generated
@ -10177,9 +10177,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
@ -19490,9 +19490,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
"build": "ncc build -o dist/setup src/setup-python.ts && ncc build -o dist/cache-save src/cache-save.ts",
|
||||
"format": "prettier --write \"{,!(node_modules)/**/}*.ts\"",
|
||||
"format-check": "prettier --check \"{,!(node_modules)/**/}*.ts\"",
|
||||
"lint": "echo \"Fake command that does nothing. It is used in reusable workflows\"",
|
||||
"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"
|
||||
},
|
||||
|
@ -7,7 +7,7 @@ import * as path from 'path';
|
||||
import os from 'os';
|
||||
|
||||
import CacheDistributor from './cache-distributor';
|
||||
import {getLinuxOSReleaseInfo, IS_LINUX, IS_WINDOWS} from '../utils';
|
||||
import {getLinuxInfo, IS_LINUX, IS_WINDOWS} from '../utils';
|
||||
|
||||
class PipCache extends CacheDistributor {
|
||||
constructor(
|
||||
@ -61,9 +61,9 @@ class PipCache extends CacheDistributor {
|
||||
let restoreKey = '';
|
||||
|
||||
if (IS_LINUX) {
|
||||
const osRelease = await getLinuxOSReleaseInfo();
|
||||
primaryKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${osRelease}-python-${this.pythonVersion}-${this.packageManager}-${hash}`;
|
||||
restoreKey = `${this.CACHE_KEY_PREFIX}-${process.env['RUNNER_OS']}-${osRelease}-python-${this.pythonVersion}-${this.packageManager}`;
|
||||
const osInfo = await getLinuxInfo();
|
||||
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']}-${osInfo.osVersion}-${osInfo.osName}-python-${this.pythonVersion}-${this.packageManager}`;
|
||||
} else {
|
||||
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}`;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import * as os from 'os';
|
||||
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';
|
||||
|
||||
@ -85,9 +85,14 @@ export async function useCpythonVersion(
|
||||
}
|
||||
|
||||
if (!installDir) {
|
||||
const osInfo = await getOSInfo();
|
||||
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}`
|
||||
].join(os.EOL)
|
||||
);
|
||||
|
@ -8,7 +8,6 @@ import fs from 'fs';
|
||||
|
||||
import {
|
||||
IS_WINDOWS,
|
||||
WINDOWS_ARCHS,
|
||||
WINDOWS_PLATFORMS,
|
||||
IPyPyManifestRelease,
|
||||
createSymlinkInFolder,
|
||||
@ -47,6 +46,8 @@ export async function installPyPy(
|
||||
let downloadUrl = `${foundAsset.download_url}`;
|
||||
|
||||
core.info(`Downloading PyPy from "${downloadUrl}" ...`);
|
||||
|
||||
try {
|
||||
const pypyPath = await tc.downloadTool(downloadUrl);
|
||||
|
||||
core.info('Extracting downloaded archive...');
|
||||
@ -78,6 +79,25 @@ export async function installPyPy(
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getAvailablePyPyVersions() {
|
||||
@ -157,7 +177,7 @@ export function findRelease(
|
||||
const isArchPresent =
|
||||
item.files &&
|
||||
(IS_WINDOWS
|
||||
? isArchPresentForWindows(item)
|
||||
? isArchPresentForWindows(item, architecture)
|
||||
: isArchPresentForMacOrLinux(item, architecture, process.platform));
|
||||
return isPythonVersionSatisfied && isPyPyVersionSatisfied && isArchPresent;
|
||||
});
|
||||
@ -181,7 +201,7 @@ export function findRelease(
|
||||
|
||||
const foundRelease = sortedReleases[0];
|
||||
const foundAsset = IS_WINDOWS
|
||||
? findAssetForWindows(foundRelease)
|
||||
? findAssetForWindows(foundRelease, architecture)
|
||||
: findAssetForMacOrLinux(foundRelease, architecture, process.platform);
|
||||
|
||||
return {
|
||||
@ -205,11 +225,11 @@ export function pypyVersionToSemantic(versionSpec: string) {
|
||||
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(
|
||||
(file: any) =>
|
||||
WINDOWS_ARCHS.includes(file.arch) &&
|
||||
WINDOWS_PLATFORMS.includes(file.platform)
|
||||
WINDOWS_PLATFORMS.includes(file.platform) && file.arch === architecture
|
||||
);
|
||||
}
|
||||
|
||||
@ -223,11 +243,11 @@ export function isArchPresentForMacOrLinux(
|
||||
);
|
||||
}
|
||||
|
||||
export function findAssetForWindows(releases: any) {
|
||||
export function findAssetForWindows(releases: any, architecture: string) {
|
||||
architecture = replaceX32toX86(architecture);
|
||||
return releases.files.find(
|
||||
(item: any) =>
|
||||
WINDOWS_ARCHS.includes(item.arch) &&
|
||||
WINDOWS_PLATFORMS.includes(item.platform)
|
||||
WINDOWS_PLATFORMS.includes(item.platform) && item.arch === architecture
|
||||
);
|
||||
}
|
||||
|
||||
@ -240,3 +260,11 @@ export function findAssetForMacOrLinux(
|
||||
(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;
|
||||
}
|
||||
|
@ -72,7 +72,9 @@ export async function installCpythonFromRelease(release: tc.IToolRelease) {
|
||||
const downloadUrl = release.files[0].download_url;
|
||||
|
||||
core.info(`Download from "${downloadUrl}"`);
|
||||
const pythonPath = await tc.downloadTool(downloadUrl, undefined, AUTH);
|
||||
let pythonPath = '';
|
||||
try {
|
||||
pythonPath = await tc.downloadTool(downloadUrl, undefined, AUTH);
|
||||
core.info('Extract downloaded archive');
|
||||
let pythonExtractedFolder;
|
||||
if (IS_WINDOWS) {
|
||||
@ -83,4 +85,20 @@ export async function installCpythonFromRelease(release: tc.IToolRelease) {
|
||||
|
||||
core.info('Execute installation script');
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -22,18 +22,18 @@ async function cacheDependencies(cache: string, pythonVersion: string) {
|
||||
await cacheDistributor.restoreCache();
|
||||
}
|
||||
|
||||
function resolveVersionInput(): string {
|
||||
let version = core.getInput('python-version');
|
||||
function resolveVersionInput() {
|
||||
let versions = core.getMultilineInput('python-version');
|
||||
let versionFile = core.getInput('python-version-file');
|
||||
|
||||
if (version && versionFile) {
|
||||
if (versions.length && versionFile) {
|
||||
core.warning(
|
||||
'Both python-version and python-version-file inputs are specified, only python-version will be used.'
|
||||
);
|
||||
}
|
||||
|
||||
if (version) {
|
||||
return version;
|
||||
if (versions.length) {
|
||||
return versions;
|
||||
}
|
||||
|
||||
if (versionFile) {
|
||||
@ -42,9 +42,9 @@ function resolveVersionInput(): string {
|
||||
`The specified python version file at: ${versionFile} doesn't exist.`
|
||||
);
|
||||
}
|
||||
version = fs.readFileSync(versionFile, 'utf8');
|
||||
const version = fs.readFileSync(versionFile, 'utf8');
|
||||
core.info(`Resolved ${versionFile} as ${version}`);
|
||||
return version;
|
||||
return [version];
|
||||
}
|
||||
|
||||
logWarning(
|
||||
@ -52,14 +52,14 @@ function resolveVersionInput(): string {
|
||||
);
|
||||
versionFile = '.python-version';
|
||||
if (fs.existsSync(versionFile)) {
|
||||
version = fs.readFileSync(versionFile, 'utf8');
|
||||
const version = fs.readFileSync(versionFile, 'utf8');
|
||||
core.info(`Resolved ${versionFile} as ${version}`);
|
||||
return version;
|
||||
return [version];
|
||||
}
|
||||
|
||||
logWarning(`${versionFile} doesn't exist.`);
|
||||
|
||||
return version;
|
||||
return versions;
|
||||
}
|
||||
|
||||
async function run() {
|
||||
@ -75,13 +75,15 @@ async function run() {
|
||||
`Python is expected to be installed into ${process.env['RUNNER_TOOL_CACHE']}`
|
||||
);
|
||||
try {
|
||||
const version = resolveVersionInput();
|
||||
const versions = resolveVersionInput();
|
||||
const checkLatest = core.getBooleanInput('check-latest');
|
||||
|
||||
if (version) {
|
||||
let pythonVersion: string;
|
||||
if (versions.length) {
|
||||
let pythonVersion = '';
|
||||
const arch: string = core.getInput('architecture') || os.arch();
|
||||
const updateEnvironment = core.getBooleanInput('update-environment');
|
||||
core.startGroup('Installed versions');
|
||||
for (const version of versions) {
|
||||
if (isPyPyVersion(version)) {
|
||||
const installed = await finderPyPy.findPyPyVersion(
|
||||
version,
|
||||
@ -103,7 +105,8 @@ async function run() {
|
||||
pythonVersion = installed.version;
|
||||
core.info(`Successfully set up ${installed.impl} (${pythonVersion})`);
|
||||
}
|
||||
|
||||
}
|
||||
core.endGroup();
|
||||
const cache = core.getInput('cache');
|
||||
if (cache && isCacheFeatureAvailable()) {
|
||||
await cacheDependencies(cache, pythonVersion);
|
||||
|
90
src/utils.ts
90
src/utils.ts
@ -105,40 +105,78 @@ export function isGhes(): boolean {
|
||||
}
|
||||
|
||||
export function isCacheFeatureAvailable(): boolean {
|
||||
if (!cache.isFeatureAvailable()) {
|
||||
if (isGhes()) {
|
||||
throw new Error(
|
||||
'Caching is only supported on GHES version >= 3.5. If you are on a version >= 3.5, please check with your GHES admin if the Actions cache service is enabled or not.'
|
||||
);
|
||||
} else {
|
||||
core.warning(
|
||||
'The runner was not able to contact the cache service. Caching will be skipped'
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cache.isFeatureAvailable()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
export async function getLinuxOSReleaseInfo() {
|
||||
const {stdout, stderr, exitCode} = await exec.getExecOutput(
|
||||
'lsb_release',
|
||||
['-i', '-r', '-s'],
|
||||
{
|
||||
silent: true
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
const [osRelease, osVersion] = stdout.trim().split('\n');
|
||||
|
||||
core.debug(`OS Release: ${osRelease}, Version: ${osVersion}`);
|
||||
|
||||
return `${osVersion}-${osRelease}`;
|
||||
core.warning(
|
||||
'The runner was not able to contact the cache service. Caching will be skipped'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
export function logWarning(message: string): void {
|
||||
const warningPrefix = '[warning]';
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user