mirror of
https://github.com/actions/setup-python.git
synced 2025-06-23 20:27:58 +02:00
Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
2c3dd9e7e2 | |||
76bbdfadd7 | |||
1aafadcfb9 | |||
b80efd6bc5 | |||
5cddb27885 | |||
47c4a7af1d | |||
af57b64994 | |||
4818a5a153 | |||
8bcd2560e2 |
@ -21,7 +21,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 }}
|
||||
|
4
.github/workflows/workflow.yml
vendored
4
.github/workflows/workflow.yml
vendored
@ -14,7 +14,7 @@ jobs:
|
||||
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
|
||||
@ -68,7 +68,7 @@ jobs:
|
||||
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:
|
||||
|
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(
|
||||
|
162
dist/cache-save/index.js
vendored
162
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,25 +45787,23 @@ 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
|
||||
// were passed through as-is
|
||||
// TODO: It would probably be faster to determine this
|
||||
// without a try/catch and a new RegExp, but it's tricky
|
||||
// to do safely. For now, this is safe and works.
|
||||
var cs = pattern.substring(classStart + 1, i)
|
||||
try {
|
||||
RegExp('[' + cs + ']')
|
||||
} catch (er) {
|
||||
// not a valid class!
|
||||
var sp = this.parse(cs, SUBPARSE)
|
||||
re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]'
|
||||
hasMagic = hasMagic || sp[1]
|
||||
inClass = false
|
||||
continue
|
||||
}
|
||||
// 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
|
||||
// were passed through as-is
|
||||
// TODO: It would probably be faster to determine this
|
||||
// without a try/catch and a new RegExp, but it's tricky
|
||||
// to do safely. For now, this is safe and works.
|
||||
var cs = pattern.substring(classStart + 1, i)
|
||||
try {
|
||||
RegExp('[' + cs + ']')
|
||||
} catch (er) {
|
||||
// not a valid class!
|
||||
var sp = this.parse(cs, SUBPARSE)
|
||||
re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]'
|
||||
hasMagic = hasMagic || sp[1]
|
||||
inClass = false
|
||||
continue
|
||||
}
|
||||
|
||||
// finish up the class.
|
||||
@ -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
|
||||
}
|
||||
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?')
|
||||
}
|
||||
|
||||
|
354
dist/setup/index.js
vendored
354
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,25 +49952,23 @@ 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
|
||||
// were passed through as-is
|
||||
// TODO: It would probably be faster to determine this
|
||||
// without a try/catch and a new RegExp, but it's tricky
|
||||
// to do safely. For now, this is safe and works.
|
||||
var cs = pattern.substring(classStart + 1, i)
|
||||
try {
|
||||
RegExp('[' + cs + ']')
|
||||
} catch (er) {
|
||||
// not a valid class!
|
||||
var sp = this.parse(cs, SUBPARSE)
|
||||
re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]'
|
||||
hasMagic = hasMagic || sp[1]
|
||||
inClass = false
|
||||
continue
|
||||
}
|
||||
// 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
|
||||
// were passed through as-is
|
||||
// TODO: It would probably be faster to determine this
|
||||
// without a try/catch and a new RegExp, but it's tricky
|
||||
// to do safely. For now, this is safe and works.
|
||||
var cs = pattern.substring(classStart + 1, i)
|
||||
try {
|
||||
RegExp('[' + cs + ']')
|
||||
} catch (er) {
|
||||
// not a valid class!
|
||||
var sp = this.parse(cs, SUBPARSE)
|
||||
re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]'
|
||||
hasMagic = hasMagic || sp[1]
|
||||
inClass = false
|
||||
continue
|
||||
}
|
||||
|
||||
// finish up the class.
|
||||
@ -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
|
||||
}
|
||||
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,27 +66538,45 @@ function installPyPy(pypyVersion, pythonVersion, architecture, releases) {
|
||||
const { foundAsset, resolvedPythonVersion, resolvedPyPyVersion } = releaseData;
|
||||
let downloadUrl = `${foundAsset.download_url}`;
|
||||
core.info(`Downloading PyPy from "${downloadUrl}" ...`);
|
||||
const pypyPath = yield tc.downloadTool(downloadUrl);
|
||||
core.info('Extracting downloaded archive...');
|
||||
if (utils_1.IS_WINDOWS) {
|
||||
downloadDir = yield tc.extractZip(pypyPath);
|
||||
try {
|
||||
const pypyPath = yield tc.downloadTool(downloadUrl);
|
||||
core.info('Extracting downloaded archive...');
|
||||
if (utils_1.IS_WINDOWS) {
|
||||
downloadDir = yield tc.extractZip(pypyPath);
|
||||
}
|
||||
else {
|
||||
downloadDir = yield 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_1.default.readdirSync(downloadDir)[0];
|
||||
const toolDir = path.join(downloadDir, archiveName);
|
||||
let installDir = toolDir;
|
||||
if (!utils_1.isNightlyKeyword(resolvedPyPyVersion)) {
|
||||
installDir = yield tc.cacheDir(toolDir, 'PyPy', resolvedPythonVersion, architecture);
|
||||
}
|
||||
utils_1.writeExactPyPyVersionFile(installDir, resolvedPyPyVersion);
|
||||
const binaryPath = getPyPyBinaryPath(installDir);
|
||||
yield createPyPySymlink(binaryPath, resolvedPythonVersion);
|
||||
yield installPip(binaryPath);
|
||||
return { installDir, resolvedPythonVersion, resolvedPyPyVersion };
|
||||
}
|
||||
else {
|
||||
downloadDir = yield tc.extractTar(pypyPath, undefined, 'x');
|
||||
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_1.default.readdirSync(downloadDir)[0];
|
||||
const toolDir = path.join(downloadDir, archiveName);
|
||||
let installDir = toolDir;
|
||||
if (!utils_1.isNightlyKeyword(resolvedPyPyVersion)) {
|
||||
installDir = yield tc.cacheDir(toolDir, 'PyPy', resolvedPythonVersion, architecture);
|
||||
}
|
||||
utils_1.writeExactPyPyVersionFile(installDir, resolvedPyPyVersion);
|
||||
const binaryPath = getPyPyBinaryPath(installDir);
|
||||
yield createPyPySymlink(binaryPath, resolvedPythonVersion);
|
||||
yield installPip(binaryPath);
|
||||
return { installDir, resolvedPythonVersion, resolvedPyPyVersion };
|
||||
});
|
||||
}
|
||||
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,17 +66775,35 @@ 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);
|
||||
core.info('Extract downloaded archive');
|
||||
let pythonExtractedFolder;
|
||||
if (utils_1.IS_WINDOWS) {
|
||||
pythonExtractedFolder = yield tc.extractZip(pythonPath);
|
||||
let pythonPath = '';
|
||||
try {
|
||||
pythonPath = yield tc.downloadTool(downloadUrl, undefined, AUTH);
|
||||
core.info('Extract downloaded archive');
|
||||
let pythonExtractedFolder;
|
||||
if (utils_1.IS_WINDOWS) {
|
||||
pythonExtractedFolder = yield tc.extractZip(pythonPath);
|
||||
}
|
||||
else {
|
||||
pythonExtractedFolder = yield tc.extractTar(pythonPath);
|
||||
}
|
||||
core.info('Execute installation script');
|
||||
yield installPython(pythonExtractedFolder);
|
||||
}
|
||||
else {
|
||||
pythonExtractedFolder = yield tc.extractTar(pythonPath);
|
||||
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;
|
||||
}
|
||||
core.info('Execute installation script');
|
||||
yield installPython(pythonExtractedFolder);
|
||||
});
|
||||
}
|
||||
exports.installCpythonFromRelease = installCpythonFromRelease;
|
||||
@ -66908,7 +66978,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));
|
||||
@ -66999,22 +67069,64 @@ function isCacheFeatureAvailable() {
|
||||
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}`;
|
||||
});
|
||||
}
|
||||
exports.getLinuxOSReleaseInfo = getLinuxOSReleaseInfo;
|
||||
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;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
@ -281,6 +281,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 +485,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
|
||||
with:
|
||||
token: ${{ secrets.GH_DOTCOM_TOKEN }}
|
||||
python-version: 3.11
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@4
|
||||
with:
|
||||
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"
|
||||
}
|
||||
|
@ -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,37 +46,58 @@ export async function installPyPy(
|
||||
let downloadUrl = `${foundAsset.download_url}`;
|
||||
|
||||
core.info(`Downloading PyPy from "${downloadUrl}" ...`);
|
||||
const pypyPath = await tc.downloadTool(downloadUrl);
|
||||
|
||||
core.info('Extracting downloaded archive...');
|
||||
if (IS_WINDOWS) {
|
||||
downloadDir = await tc.extractZip(pypyPath);
|
||||
} else {
|
||||
downloadDir = await tc.extractTar(pypyPath, undefined, 'x');
|
||||
try {
|
||||
const pypyPath = await tc.downloadTool(downloadUrl);
|
||||
|
||||
core.info('Extracting downloaded archive...');
|
||||
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() {
|
||||
@ -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,15 +72,33 @@ 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);
|
||||
core.info('Extract downloaded archive');
|
||||
let pythonExtractedFolder;
|
||||
if (IS_WINDOWS) {
|
||||
pythonExtractedFolder = await tc.extractZip(pythonPath);
|
||||
} else {
|
||||
pythonExtractedFolder = await tc.extractTar(pythonPath);
|
||||
}
|
||||
let pythonPath = '';
|
||||
try {
|
||||
pythonPath = await tc.downloadTool(downloadUrl, undefined, AUTH);
|
||||
core.info('Extract downloaded archive');
|
||||
let pythonExtractedFolder;
|
||||
if (IS_WINDOWS) {
|
||||
pythonExtractedFolder = await tc.extractZip(pythonPath);
|
||||
} else {
|
||||
pythonExtractedFolder = await tc.extractTar(pythonPath);
|
||||
}
|
||||
|
||||
core.info('Execute installation script');
|
||||
await installPython(pythonExtractedFolder);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
60
src/utils.ts
60
src/utils.ts
@ -122,23 +122,61 @@ export function isCacheFeatureAvailable(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
export async function getLinuxOSReleaseInfo() {
|
||||
const {stdout, stderr, exitCode} = await exec.getExecOutput(
|
||||
'lsb_release',
|
||||
['-i', '-r', '-s'],
|
||||
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 [osRelease, osVersion] = stdout.trim().split('\n');
|
||||
const windowsVersion = stdout.trim().split(' ')[3];
|
||||
|
||||
core.debug(`OS Release: ${osRelease}, Version: ${osVersion}`);
|
||||
|
||||
return `${osVersion}-${osRelease}`;
|
||||
return {osName: 'Windows', osVersion: windowsVersion};
|
||||
}
|
||||
|
||||
export function logWarning(message: string): void {
|
||||
const warningPrefix = '[warning]';
|
||||
core.info(`${warningPrefix}${message}`);
|
||||
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