mirror of
https://github.com/erlef/setup-beam.git
synced 2026-07-23 07:06:07 +00:00
Rework our version matching algorithm (#217)
* Update some dependencies' versions (also, get rid of husky) * Introduce branch dependency execution We want the most important things to fail first and prevent the other ones from executing e.g. if your dist/ is not updated, there's no point seeing the tests fail * Rid ourselves of bloat * Introduce expectations for upcoming version * Tweak whitespace * Tweak our calls to getVersionFromSpec (increase code consistency) * Remove non-used variable * Start coercing on input, stop sorting/maybe prepending 'v' on input We'll deal with all this in a centralized place to make it easier to reason on the code * Revamp our getVersionFromSpec 1. stop accepting maybePrependWithV0, since this is only used in specialized cases 2. sort versions internally (don't expect it to come sorted) 3. compare rc/strict and .includes in a single go (don't separate these) 4. don't expect already coerced version arrays, coerce them when required (the maybeCoerced version had changed already, which means we're smarter at putting stuff inside the version array) 5. raise an exception if a semver-invalid version is not flagged as strict * Reduce our expectations, but still be appropriate to our mission * Update our tests for our new expectations (start the TDD bit) * Execute npm run build-dist and keep results * Increase inter-job dependency * Don't expect markdownlint to be installed remotely * Revert "Increase inter-job dependency" This reverts commit 500b0fe7e9eec1c4f258b4d16b40719ee1d0a1ad. * Revert "Introduce branch dependency execution" This reverts commit fbe1317a800d7722f4e8b668c073218263d0ab17. * Have all the CI workflows run under the same conditions * Fix as per CI results * Re-establish the possibility to match versions like 22.3.4.2.1.0 We cheat on the semver matching: 1. we keep an ordered list of versions that respect e.g. 22.3.4 2. if we match 22.3.4 when fetching a version, we get the last value from the list of versions that respect it, e.g. 22.3.4.2.1.0 (since this is ordered, it should work as previously expected) This increases code complexity for getVersionFromSpec, but hopefully not by much... We also remove throw-based test cases (non-versions will fail later, with null), and add some tests to prove our need code. * Trim out linting practices But still keep them useful
This commit is contained in:
committed by
GitHub
parent
efc884ac2f
commit
f6a73a7bf1
+5
-8
@@ -1,19 +1,16 @@
|
|||||||
---
|
---
|
||||||
env:
|
env:
|
||||||
node: true
|
node: true
|
||||||
es2021: true
|
es2022: true
|
||||||
extends:
|
extends:
|
||||||
- airbnb
|
- eslint:recommended
|
||||||
parserOptions:
|
parserOptions:
|
||||||
ecmaVersion: 12
|
ecmaVersion: 2022
|
||||||
rules:
|
rules:
|
||||||
indent: ["warn", 2]
|
indent: [warn, 2]
|
||||||
max-len: ["warn", 100]
|
max-len: [warn, 100]
|
||||||
no-undef: "error"
|
|
||||||
no-unused-vars: ["error", {"varsIgnorePattern": "^_"}]
|
|
||||||
no-use-before-define: 0
|
no-use-before-define: 0
|
||||||
operator-linebreak: 0
|
operator-linebreak: 0
|
||||||
require-jsdoc: 0
|
|
||||||
semi: 0
|
semi: 0
|
||||||
|
|
||||||
settings:
|
settings:
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [opened, synchronize]
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||||
@@ -19,16 +20,8 @@ jobs:
|
|||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '14'
|
node-version: '16'
|
||||||
- run: npm install -g npm
|
- run: npm run build-dist
|
||||||
- run: npm install
|
|
||||||
- run: npm run build
|
|
||||||
- run: npm run format
|
|
||||||
- run: npm install -g markdownlint-cli
|
|
||||||
- run: npm run markdownlint
|
|
||||||
- run: npm run shellcheck
|
|
||||||
- run: npm run yamllint
|
|
||||||
- run: npm run jslint
|
|
||||||
- name: Check if build left artifacts
|
- name: Check if build left artifacts
|
||||||
run: git diff --exit-code --ignore-space-at-eol
|
run: git diff --exit-code --ignore-space-at-eol
|
||||||
|
|
||||||
@@ -39,7 +32,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '14'
|
node-version: '16'
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: npm test
|
- run: npm test
|
||||||
- name: .tool-versions test
|
- name: .tool-versions test
|
||||||
@@ -56,6 +49,6 @@ jobs:
|
|||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '14'
|
node-version: '16'
|
||||||
- run: npm install --production
|
- run: npm install --production
|
||||||
- run: npm test
|
- run: npm test
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [opened, synchronize]
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
integration_test:
|
integration_test:
|
||||||
@@ -111,12 +112,10 @@ jobs:
|
|||||||
otp-version: '22.3.4.1'
|
otp-version: '22.3.4.1'
|
||||||
os: 'ubuntu-20.04'
|
os: 'ubuntu-20.04'
|
||||||
version-type: 'strict'
|
version-type: 'strict'
|
||||||
- elixir-version: '1.10.3'
|
|
||||||
otp-version: '22.3.4.1'
|
|
||||||
os: 'ubuntu-20.04'
|
|
||||||
- elixir-version: 'main'
|
- elixir-version: 'main'
|
||||||
otp-version: '23.1'
|
otp-version: '23.1'
|
||||||
os: 'ubuntu-20.04'
|
os: 'ubuntu-20.04'
|
||||||
|
version-type: 'strict'
|
||||||
- elixir-version: 'main'
|
- elixir-version: 'main'
|
||||||
otp-version: '25'
|
otp-version: '25'
|
||||||
os: 'ubuntu-20.04'
|
os: 'ubuntu-20.04'
|
||||||
|
|||||||
@@ -12,9 +12,6 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: '14'
|
|
||||||
- run:
|
- run:
|
||||||
./.github/workflows/update_3rd_party_licenses.sh
|
./.github/workflows/update_3rd_party_licenses.sh
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [opened, synchronize]
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
integration_test:
|
integration_test:
|
||||||
|
|||||||
Vendored
+179
-96
@@ -6221,15 +6221,18 @@ class Range {
|
|||||||
const hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE]
|
const hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE]
|
||||||
range = range.replace(hr, hyphenReplace(this.options.includePrerelease))
|
range = range.replace(hr, hyphenReplace(this.options.includePrerelease))
|
||||||
debug('hyphen replace', range)
|
debug('hyphen replace', range)
|
||||||
|
|
||||||
// `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
|
// `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
|
||||||
range = range.replace(re[t.COMPARATORTRIM], comparatorTrimReplace)
|
range = range.replace(re[t.COMPARATORTRIM], comparatorTrimReplace)
|
||||||
debug('comparator trim', range)
|
debug('comparator trim', range)
|
||||||
|
|
||||||
// `~ 1.2.3` => `~1.2.3`
|
// `~ 1.2.3` => `~1.2.3`
|
||||||
range = range.replace(re[t.TILDETRIM], tildeTrimReplace)
|
range = range.replace(re[t.TILDETRIM], tildeTrimReplace)
|
||||||
|
debug('tilde trim', range)
|
||||||
|
|
||||||
// `^ 1.2.3` => `^1.2.3`
|
// `^ 1.2.3` => `^1.2.3`
|
||||||
range = range.replace(re[t.CARETTRIM], caretTrimReplace)
|
range = range.replace(re[t.CARETTRIM], caretTrimReplace)
|
||||||
|
debug('caret trim', range)
|
||||||
|
|
||||||
// At this point, the range is completely trimmed and
|
// At this point, the range is completely trimmed and
|
||||||
// ready to be split into comparators.
|
// ready to be split into comparators.
|
||||||
@@ -7531,6 +7534,10 @@ const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER ||
|
|||||||
// Max safe segment length for coercion.
|
// Max safe segment length for coercion.
|
||||||
const MAX_SAFE_COMPONENT_LENGTH = 16
|
const MAX_SAFE_COMPONENT_LENGTH = 16
|
||||||
|
|
||||||
|
// Max safe length for a build identifier. The max length minus 6 characters for
|
||||||
|
// the shortest version with a build 0.0.0+BUILD.
|
||||||
|
const MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6
|
||||||
|
|
||||||
const RELEASE_TYPES = [
|
const RELEASE_TYPES = [
|
||||||
'major',
|
'major',
|
||||||
'premajor',
|
'premajor',
|
||||||
@@ -7544,6 +7551,7 @@ const RELEASE_TYPES = [
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
MAX_LENGTH,
|
MAX_LENGTH,
|
||||||
MAX_SAFE_COMPONENT_LENGTH,
|
MAX_SAFE_COMPONENT_LENGTH,
|
||||||
|
MAX_SAFE_BUILD_LENGTH,
|
||||||
MAX_SAFE_INTEGER,
|
MAX_SAFE_INTEGER,
|
||||||
RELEASE_TYPES,
|
RELEASE_TYPES,
|
||||||
SEMVER_SPEC_VERSION,
|
SEMVER_SPEC_VERSION,
|
||||||
@@ -7625,7 +7633,7 @@ module.exports = parseOptions
|
|||||||
/***/ 9523:
|
/***/ 9523:
|
||||||
/***/ ((module, exports, __nccwpck_require__) => {
|
/***/ ((module, exports, __nccwpck_require__) => {
|
||||||
|
|
||||||
const { MAX_SAFE_COMPONENT_LENGTH } = __nccwpck_require__(2293)
|
const { MAX_SAFE_COMPONENT_LENGTH, MAX_SAFE_BUILD_LENGTH } = __nccwpck_require__(2293)
|
||||||
const debug = __nccwpck_require__(427)
|
const debug = __nccwpck_require__(427)
|
||||||
exports = module.exports = {}
|
exports = module.exports = {}
|
||||||
|
|
||||||
@@ -7636,16 +7644,31 @@ const src = exports.src = []
|
|||||||
const t = exports.t = {}
|
const t = exports.t = {}
|
||||||
let R = 0
|
let R = 0
|
||||||
|
|
||||||
|
const LETTERDASHNUMBER = '[a-zA-Z0-9-]'
|
||||||
|
|
||||||
|
// Replace some greedy regex tokens to prevent regex dos issues. These regex are
|
||||||
|
// used internally via the safeRe object since all inputs in this library get
|
||||||
|
// normalized first to trim and collapse all extra whitespace. The original
|
||||||
|
// regexes are exported for userland consumption and lower level usage. A
|
||||||
|
// future breaking change could export the safer regex only with a note that
|
||||||
|
// all input should have extra whitespace removed.
|
||||||
|
const safeRegexReplacements = [
|
||||||
|
['\\s', 1],
|
||||||
|
['\\d', MAX_SAFE_COMPONENT_LENGTH],
|
||||||
|
[LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH],
|
||||||
|
]
|
||||||
|
|
||||||
|
const makeSafeRegex = (value) => {
|
||||||
|
for (const [token, max] of safeRegexReplacements) {
|
||||||
|
value = value
|
||||||
|
.split(`${token}*`).join(`${token}{0,${max}}`)
|
||||||
|
.split(`${token}+`).join(`${token}{1,${max}}`)
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
const createToken = (name, value, isGlobal) => {
|
const createToken = (name, value, isGlobal) => {
|
||||||
// Replace all greedy whitespace to prevent regex dos issues. These regex are
|
const safe = makeSafeRegex(value)
|
||||||
// used internally via the safeRe object since all inputs in this library get
|
|
||||||
// normalized first to trim and collapse all extra whitespace. The original
|
|
||||||
// regexes are exported for userland consumption and lower level usage. A
|
|
||||||
// future breaking change could export the safer regex only with a note that
|
|
||||||
// all input should have extra whitespace removed.
|
|
||||||
const safe = value
|
|
||||||
.split('\\s*').join('\\s{0,1}')
|
|
||||||
.split('\\s+').join('\\s')
|
|
||||||
const index = R++
|
const index = R++
|
||||||
debug(name, index, value)
|
debug(name, index, value)
|
||||||
t[name] = index
|
t[name] = index
|
||||||
@@ -7661,13 +7684,13 @@ const createToken = (name, value, isGlobal) => {
|
|||||||
// A single `0`, or a non-zero digit followed by zero or more digits.
|
// A single `0`, or a non-zero digit followed by zero or more digits.
|
||||||
|
|
||||||
createToken('NUMERICIDENTIFIER', '0|[1-9]\\d*')
|
createToken('NUMERICIDENTIFIER', '0|[1-9]\\d*')
|
||||||
createToken('NUMERICIDENTIFIERLOOSE', '[0-9]+')
|
createToken('NUMERICIDENTIFIERLOOSE', '\\d+')
|
||||||
|
|
||||||
// ## Non-numeric Identifier
|
// ## Non-numeric Identifier
|
||||||
// Zero or more digits, followed by a letter or hyphen, and then zero or
|
// Zero or more digits, followed by a letter or hyphen, and then zero or
|
||||||
// more letters, digits, or hyphens.
|
// more letters, digits, or hyphens.
|
||||||
|
|
||||||
createToken('NONNUMERICIDENTIFIER', '\\d*[a-zA-Z-][a-zA-Z0-9-]*')
|
createToken('NONNUMERICIDENTIFIER', `\\d*[a-zA-Z-]${LETTERDASHNUMBER}*`)
|
||||||
|
|
||||||
// ## Main Version
|
// ## Main Version
|
||||||
// Three dot-separated numeric identifiers.
|
// Three dot-separated numeric identifiers.
|
||||||
@@ -7702,7 +7725,7 @@ createToken('PRERELEASELOOSE', `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE]
|
|||||||
// ## Build Metadata Identifier
|
// ## Build Metadata Identifier
|
||||||
// Any combination of digits, letters, or hyphens.
|
// Any combination of digits, letters, or hyphens.
|
||||||
|
|
||||||
createToken('BUILDIDENTIFIER', '[0-9A-Za-z-]+')
|
createToken('BUILDIDENTIFIER', `${LETTERDASHNUMBER}+`)
|
||||||
|
|
||||||
// ## Build Metadata
|
// ## Build Metadata
|
||||||
// Plus sign, followed by one or more period-separated build metadata
|
// Plus sign, followed by one or more period-separated build metadata
|
||||||
@@ -10052,15 +10075,16 @@ async function main() {
|
|||||||
|
|
||||||
if (otpSpec !== 'false') {
|
if (otpSpec !== 'false') {
|
||||||
await installOTP(otpSpec, osVersion, hexMirrors)
|
await installOTP(otpSpec, osVersion, hexMirrors)
|
||||||
|
|
||||||
const elixirInstalled = await maybeInstallElixir(
|
const elixirInstalled = await maybeInstallElixir(
|
||||||
elixirSpec,
|
elixirSpec,
|
||||||
otpSpec,
|
otpSpec,
|
||||||
hexMirrors,
|
hexMirrors,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (elixirInstalled === true) {
|
if (elixirInstalled === true) {
|
||||||
const shouldMixRebar = getInput('install-rebar', false)
|
const shouldMixRebar = getInput('install-rebar', false)
|
||||||
await mix(shouldMixRebar, 'rebar', hexMirrors)
|
await mix(shouldMixRebar, 'rebar', hexMirrors)
|
||||||
|
|
||||||
const shouldMixHex = getInput('install-hex', false)
|
const shouldMixHex = getInput('install-hex', false)
|
||||||
await mix(shouldMixHex, 'hex', hexMirrors)
|
await mix(shouldMixHex, 'hex', hexMirrors)
|
||||||
}
|
}
|
||||||
@@ -10084,7 +10108,6 @@ async function installOTP(otpSpec, osVersion, hexMirrors) {
|
|||||||
|
|
||||||
async function maybeInstallElixir(elixirSpec, otpSpec, hexMirrors) {
|
async function maybeInstallElixir(elixirSpec, otpSpec, hexMirrors) {
|
||||||
let installed = false
|
let installed = false
|
||||||
|
|
||||||
if (elixirSpec) {
|
if (elixirSpec) {
|
||||||
const elixirVersion = await getElixirVersion(
|
const elixirVersion = await getElixirVersion(
|
||||||
elixirSpec,
|
elixirSpec,
|
||||||
@@ -10094,6 +10117,7 @@ async function maybeInstallElixir(elixirSpec, otpSpec, hexMirrors) {
|
|||||||
core.startGroup(`Installing Elixir ${elixirVersion}`)
|
core.startGroup(`Installing Elixir ${elixirVersion}`)
|
||||||
await installer.installElixir(elixirVersion, hexMirrors)
|
await installer.installElixir(elixirVersion, hexMirrors)
|
||||||
core.setOutput('elixir-version', elixirVersion)
|
core.setOutput('elixir-version', elixirVersion)
|
||||||
|
|
||||||
const disableProblemMatchers = getInput('disable_problem_matchers', false)
|
const disableProblemMatchers = getInput('disable_problem_matchers', false)
|
||||||
if (disableProblemMatchers === 'false') {
|
if (disableProblemMatchers === 'false') {
|
||||||
const elixirMatchers = __nccwpck_require__.ab + "elixir-matchers.json"
|
const elixirMatchers = __nccwpck_require__.ab + "elixir-matchers.json"
|
||||||
@@ -10111,6 +10135,7 @@ async function mixWithMirrors(cmd, args, hexMirrors) {
|
|||||||
if (hexMirrors.length === 0) {
|
if (hexMirrors.length === 0) {
|
||||||
throw new Error('mix failed with every mirror')
|
throw new Error('mix failed with every mirror')
|
||||||
}
|
}
|
||||||
|
|
||||||
const [hexMirror, ...hexMirrorsT] = hexMirrors
|
const [hexMirror, ...hexMirrorsT] = hexMirrors
|
||||||
process.env.HEX_MIRROR = hexMirror
|
process.env.HEX_MIRROR = hexMirror
|
||||||
try {
|
try {
|
||||||
@@ -10120,6 +10145,7 @@ async function mixWithMirrors(cmd, args, hexMirrors) {
|
|||||||
`mix failed with mirror ${process.env.HEX_MIRROR} with message ${err.message})`,
|
`mix failed with mirror ${process.env.HEX_MIRROR} with message ${err.message})`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return mixWithMirrors(cmd, args, hexMirrorsT)
|
return mixWithMirrors(cmd, args, hexMirrorsT)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10135,7 +10161,6 @@ async function mix(shouldMix, what, hexMirrors) {
|
|||||||
|
|
||||||
async function maybeInstallGleam(gleamSpec) {
|
async function maybeInstallGleam(gleamSpec) {
|
||||||
let installed = false
|
let installed = false
|
||||||
|
|
||||||
if (gleamSpec) {
|
if (gleamSpec) {
|
||||||
const gleamVersion = await getGleamVersion(gleamSpec)
|
const gleamVersion = await getGleamVersion(gleamSpec)
|
||||||
core.startGroup(`Installing Gleam ${gleamVersion}`)
|
core.startGroup(`Installing Gleam ${gleamVersion}`)
|
||||||
@@ -10153,7 +10178,6 @@ async function maybeInstallGleam(gleamSpec) {
|
|||||||
async function maybeInstallRebar3(rebar3Spec) {
|
async function maybeInstallRebar3(rebar3Spec) {
|
||||||
let installed = false
|
let installed = false
|
||||||
let rebar3Version
|
let rebar3Version
|
||||||
|
|
||||||
if (rebar3Spec) {
|
if (rebar3Spec) {
|
||||||
if (rebar3Spec === 'nightly') {
|
if (rebar3Spec === 'nightly') {
|
||||||
rebar3Version = 'nightly'
|
rebar3Version = 'nightly'
|
||||||
@@ -10174,14 +10198,9 @@ async function maybeInstallRebar3(rebar3Spec) {
|
|||||||
|
|
||||||
async function getOTPVersion(otpSpec0, osVersion, hexMirrors) {
|
async function getOTPVersion(otpSpec0, osVersion, hexMirrors) {
|
||||||
const otpVersions = await getOTPVersions(osVersion, hexMirrors)
|
const otpVersions = await getOTPVersions(osVersion, hexMirrors)
|
||||||
let otpSpec = otpSpec0 // might be a branch (?)
|
const spec = otpSpec0.replace(/^OTP-/, '')
|
||||||
const otpVersion = getVersionFromSpec(
|
const versions = otpVersions
|
||||||
otpSpec,
|
const otpVersion = getVersionFromSpec(spec, versions)
|
||||||
Array.from(otpVersions.keys()).sort(),
|
|
||||||
)
|
|
||||||
if (isVersion(otpSpec0)) {
|
|
||||||
otpSpec = `OTP-${otpSpec0}` // ... it's a version!
|
|
||||||
}
|
|
||||||
if (otpVersion === null) {
|
if (otpVersion === null) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Requested Erlang/OTP version (${otpSpec0}) not found in version list ` +
|
`Requested Erlang/OTP version (${otpSpec0}) not found in version list ` +
|
||||||
@@ -10189,20 +10208,18 @@ async function getOTPVersion(otpSpec0, osVersion, hexMirrors) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return otpVersions.get(otpVersion) // from the reference, for download
|
return otpVersion // from the reference, for download
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getElixirVersion(exSpec0, otpVersion0, hexMirrors) {
|
async function getElixirVersion(exSpec0, otpVersion0, hexMirrors) {
|
||||||
const otpVersion = otpVersion0.match(/^([^-]+-)?(.+)$/)[2]
|
const otpVersion = otpVersion0.match(/^([^-]+-)?(.+)$/)[2]
|
||||||
const otpVersionMajor = otpVersion.match(/^([^.]+).*$/)[1]
|
const otpVersionMajor = otpVersion.match(/^([^.]+).*$/)[1]
|
||||||
const elixirVersions = await getElixirVersions(hexMirrors)
|
const [otpVersionsForElixirMap, elixirVersions] = await getElixirVersions(
|
||||||
const semverVersions = Array.from(elixirVersions.keys()).sort()
|
hexMirrors,
|
||||||
const exSpec = exSpec0.replace(/-otp-.*$/, '')
|
)
|
||||||
const elixirVersionFromSpec = getVersionFromSpec(exSpec, semverVersions, true)
|
const spec = exSpec0.replace(/-otp-.*$/, '')
|
||||||
let elixirVersionForDownload = elixirVersionFromSpec
|
const versions = elixirVersions
|
||||||
if (isVersion(otpVersionMajor)) {
|
const elixirVersionFromSpec = getVersionFromSpec(spec, versions)
|
||||||
elixirVersionForDownload = `${elixirVersionFromSpec}-otp-${otpVersionMajor}`
|
|
||||||
}
|
|
||||||
if (elixirVersionFromSpec === null) {
|
if (elixirVersionFromSpec === null) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Requested Elixir version (${exSpec0}) not found in version list ` +
|
`Requested Elixir version (${exSpec0}) not found in version list ` +
|
||||||
@@ -10210,7 +10227,7 @@ async function getElixirVersion(exSpec0, otpVersion0, hexMirrors) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const elixirVersionComp = elixirVersions.get(elixirVersionFromSpec)
|
const elixirVersionComp = otpVersionsForElixirMap[elixirVersionFromSpec]
|
||||||
if (
|
if (
|
||||||
(elixirVersionComp && elixirVersionComp.includes(otpVersionMajor)) ||
|
(elixirVersionComp && elixirVersionComp.includes(otpVersionMajor)) ||
|
||||||
!isVersion(otpVersionMajor)
|
!isVersion(otpVersionMajor)
|
||||||
@@ -10227,13 +10244,20 @@ async function getElixirVersion(exSpec0, otpVersion0, hexMirrors) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let elixirVersionForDownload = elixirVersionFromSpec
|
||||||
|
|
||||||
|
if (isVersion(otpVersionMajor)) {
|
||||||
|
elixirVersionForDownload = `${elixirVersionFromSpec}-otp-${otpVersionMajor}`
|
||||||
|
}
|
||||||
|
|
||||||
return maybePrependWithV(elixirVersionForDownload)
|
return maybePrependWithV(elixirVersionForDownload)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getGleamVersion(gleamSpec0) {
|
async function getGleamVersion(gleamSpec0) {
|
||||||
const gleamSpec = gleamSpec0.match(/^v?(.+)$/)
|
|
||||||
const gleamVersions = await getGleamVersions()
|
const gleamVersions = await getGleamVersions()
|
||||||
const gleamVersion = getVersionFromSpec(gleamSpec[1], gleamVersions, true)
|
const spec = gleamSpec0
|
||||||
|
const versions = gleamVersions
|
||||||
|
const gleamVersion = getVersionFromSpec(spec, versions)
|
||||||
if (gleamVersion === null) {
|
if (gleamVersion === null) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Requested Gleam version (${gleamSpec0}) not found in version list ` +
|
`Requested Gleam version (${gleamSpec0}) not found in version list ` +
|
||||||
@@ -10241,12 +10265,14 @@ async function getGleamVersion(gleamSpec0) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return maybePrependWithV(gleamVersion, gleamVersion)
|
return maybePrependWithV(gleamVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getRebar3Version(r3Spec) {
|
async function getRebar3Version(r3Spec) {
|
||||||
const rebar3Versions = await getRebar3Versions()
|
const rebar3Versions = await getRebar3Versions()
|
||||||
const rebar3Version = getVersionFromSpec(r3Spec, rebar3Versions)
|
const spec = r3Spec
|
||||||
|
const versions = rebar3Versions
|
||||||
|
const rebar3Version = getVersionFromSpec(spec, versions)
|
||||||
if (rebar3Version === null) {
|
if (rebar3Version === null) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Requested rebar3 version (${r3Spec}) not found in version list ` +
|
`Requested rebar3 version (${r3Spec}) not found in version list ` +
|
||||||
@@ -10269,8 +10295,9 @@ async function getOTPVersions(osVersion, hexMirrors) {
|
|||||||
otpVersionsListings = await get(originListing, [1, 2, 3])
|
otpVersionsListings = await get(originListing, [1, 2, 3])
|
||||||
}
|
}
|
||||||
|
|
||||||
const otpVersions = new Map()
|
debugLog(`OTP versions listings from ${originListing}`, otpVersionsListings)
|
||||||
|
|
||||||
|
const otpVersions = {}
|
||||||
if (process.platform === 'linux') {
|
if (process.platform === 'linux') {
|
||||||
otpVersionsListings
|
otpVersionsListings
|
||||||
.trim()
|
.trim()
|
||||||
@@ -10280,8 +10307,9 @@ async function getOTPVersions(osVersion, hexMirrors) {
|
|||||||
.match(/^([^ ]+)?( .+)/)[1]
|
.match(/^([^ ]+)?( .+)/)[1]
|
||||||
.match(/^([^-]+-)?(.+)$/)
|
.match(/^([^-]+-)?(.+)$/)
|
||||||
const otpVersion = otpMatch[2]
|
const otpVersion = otpMatch[2]
|
||||||
|
const otpVersionOrig = otpMatch[0]
|
||||||
debugLog('OTP line and parsing', [line, otpVersion, otpMatch])
|
debugLog('OTP line and parsing', [line, otpVersion, otpMatch])
|
||||||
otpVersions.set(otpVersion, otpMatch[0]) // we keep the original for later reference
|
otpVersions[otpVersion] = otpVersionOrig // we keep the original for later reference
|
||||||
})
|
})
|
||||||
} else if (process.platform === 'win32') {
|
} else if (process.platform === 'win32') {
|
||||||
otpVersionsListings.forEach((otpVersionsListing) => {
|
otpVersionsListings.forEach((otpVersionsListing) => {
|
||||||
@@ -10293,15 +10321,12 @@ async function getOTPVersions(osVersion, hexMirrors) {
|
|||||||
const otpMatch = x.name.match(/^otp_win64_(.*).exe$/)
|
const otpMatch = x.name.match(/^otp_win64_(.*).exe$/)
|
||||||
const otpVersion = otpMatch[1]
|
const otpVersion = otpMatch[1]
|
||||||
debugLog('OTP line and parsing', [otpMatch, otpVersion])
|
debugLog('OTP line and parsing', [otpMatch, otpVersion])
|
||||||
otpVersions.set(otpVersion, otpVersion)
|
otpVersions[otpVersion] = otpVersion
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
debugLog(
|
debugLog(`OTP versions from ${originListing}`, JSON.stringify(otpVersions))
|
||||||
`OTP versions from ${originListing}`,
|
|
||||||
JSON.stringify([...otpVersions.entries()]),
|
|
||||||
)
|
|
||||||
|
|
||||||
return otpVersions
|
return otpVersions
|
||||||
}
|
}
|
||||||
@@ -10311,7 +10336,8 @@ async function getElixirVersions(hexMirrors) {
|
|||||||
'/builds/elixir/builds.txt',
|
'/builds/elixir/builds.txt',
|
||||||
hexMirrors,
|
hexMirrors,
|
||||||
)
|
)
|
||||||
const otpVersionsForElixirMap = new Map()
|
const otpVersionsForElixirMap = {}
|
||||||
|
const elixirVersions = {}
|
||||||
|
|
||||||
elixirVersionsListings
|
elixirVersionsListings
|
||||||
.trim()
|
.trim()
|
||||||
@@ -10319,17 +10345,18 @@ async function getElixirVersions(hexMirrors) {
|
|||||||
.forEach((line) => {
|
.forEach((line) => {
|
||||||
const elixirMatch =
|
const elixirMatch =
|
||||||
line.match(/^v?(.+)-otp-([^ ]+)/) || line.match(/^v?([^ ]+)/)
|
line.match(/^v?(.+)-otp-([^ ]+)/) || line.match(/^v?([^ ]+)/)
|
||||||
const elixirVersion = maybePrependWithV(elixirMatch[1])
|
const elixirVersion = elixirMatch[1]
|
||||||
const otpVersion = elixirMatch[2]
|
const otpVersion = elixirMatch[2]
|
||||||
const otpVersions = otpVersionsForElixirMap.get(elixirVersion) || []
|
const otpVersions = otpVersionsForElixirMap[elixirVersion] || []
|
||||||
if (otpVersion) {
|
if (otpVersion) {
|
||||||
// -otp- present (special case)
|
// -otp- present (special case)
|
||||||
otpVersions.push(otpVersion)
|
otpVersions.push(otpVersion)
|
||||||
}
|
}
|
||||||
otpVersionsForElixirMap.set(elixirVersion, otpVersions)
|
otpVersionsForElixirMap[elixirVersion] = otpVersions
|
||||||
|
elixirVersions[elixirVersion] = elixirVersion
|
||||||
})
|
})
|
||||||
|
|
||||||
return otpVersionsForElixirMap
|
return [otpVersionsForElixirMap, elixirVersions]
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getGleamVersions() {
|
async function getGleamVersions() {
|
||||||
@@ -10337,13 +10364,17 @@ async function getGleamVersions() {
|
|||||||
'https://api.github.com/repos/gleam-lang/gleam/releases?per_page=100',
|
'https://api.github.com/repos/gleam-lang/gleam/releases?per_page=100',
|
||||||
[1, 2, 3],
|
[1, 2, 3],
|
||||||
)
|
)
|
||||||
const gleamVersionsListing = []
|
const gleamVersionsListing = {}
|
||||||
resultJSONs.forEach((resultJSON) => {
|
resultJSONs.forEach((resultJSON) => {
|
||||||
jsonParseAsList(resultJSON)
|
jsonParseAsList(resultJSON)
|
||||||
.map((x) => x.tag_name)
|
.map((x) => x.tag_name)
|
||||||
.sort()
|
.forEach((ver) => {
|
||||||
.forEach((v) => gleamVersionsListing.push(v))
|
const gleamMatch = ver.match(/^v?([^ ]+)/)
|
||||||
|
const gleamVersion = gleamMatch[1]
|
||||||
|
gleamVersionsListing[gleamVersion] = gleamVersion
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return gleamVersionsListing
|
return gleamVersionsListing
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10352,13 +10383,15 @@ async function getRebar3Versions() {
|
|||||||
'https://api.github.com/repos/erlang/rebar3/releases?per_page=100',
|
'https://api.github.com/repos/erlang/rebar3/releases?per_page=100',
|
||||||
[1, 2, 3],
|
[1, 2, 3],
|
||||||
)
|
)
|
||||||
const rebar3VersionsListing = []
|
const rebar3VersionsListing = {}
|
||||||
resultJSONs.forEach((resultJSON) => {
|
resultJSONs.forEach((resultJSON) => {
|
||||||
jsonParseAsList(resultJSON)
|
jsonParseAsList(resultJSON)
|
||||||
.map((x) => x.tag_name)
|
.map((x) => x.tag_name)
|
||||||
.sort()
|
.forEach((ver) => {
|
||||||
.forEach((v) => rebar3VersionsListing.push(v))
|
rebar3VersionsListing[ver] = ver
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return rebar3VersionsListing
|
return rebar3VersionsListing
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10366,48 +10399,68 @@ function isStrictVersion() {
|
|||||||
return getInput('version-type', false) === 'strict'
|
return getInput('version-type', false) === 'strict'
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVersionFromSpec(spec, versions, maybePrependWithV0) {
|
function getVersionFromSpec(spec0, versions0) {
|
||||||
|
const spec = maybeRemoveVPrefix(spec0)
|
||||||
|
|
||||||
|
const altVersions = {}
|
||||||
|
Object.entries(versions0).forEach(([version, altVersion]) => {
|
||||||
|
let coerced
|
||||||
|
if (isStrictVersion() || isRC(version)) {
|
||||||
|
// If `version-type: strict` or version is RC, we just try to remove a potential initial v
|
||||||
|
coerced = maybeRemoveVPrefix(version)
|
||||||
|
} else {
|
||||||
|
// Otherwise, we place the version into a version bucket
|
||||||
|
coerced = maybeCoerced(version)
|
||||||
|
}
|
||||||
|
const alt = (altVersions[coerced] || []).concat(altVersion)
|
||||||
|
alt.sort(sortVersions)
|
||||||
|
altVersions[coerced] = alt
|
||||||
|
})
|
||||||
|
|
||||||
|
let versions = Object.keys(altVersions)
|
||||||
|
|
||||||
|
const rangeForMax = semver.validRange(spec0) || maybeCoerced(spec)
|
||||||
|
const rangeMax = semver.maxSatisfying(versions, rangeForMax)
|
||||||
let version = null
|
let version = null
|
||||||
|
|
||||||
if (spec.match(/rc/) || isStrictVersion()) {
|
if (isStrictVersion() || isRC(spec0)) {
|
||||||
version = spec
|
if (versions0[spec]) {
|
||||||
}
|
// If `version-type: strict` or version is RC, we obtain it directly
|
||||||
|
version = versions0[spec]
|
||||||
|
}
|
||||||
|
} else if (rangeMax !== null) {
|
||||||
|
// Otherwise, we compare alt. versions' semver ranges to this version, from highest to lowest
|
||||||
|
const thatVersion = spec
|
||||||
|
const thatVersionAbc = versionAbc(thatVersion)
|
||||||
|
const thatVersionAbcRange = semver.validRange(thatVersionAbc)
|
||||||
|
|
||||||
if (version === null) {
|
versions = altVersions[rangeMax]
|
||||||
// We keep a map of semver => "spec" in order to use semver ranges to find appropriate versions
|
for (let i = versions.length - 1; i >= 0; i -= 1) {
|
||||||
const versionsMap = versions.sort(sortVersions).reduce((acc, v) => {
|
const thisVersion = versions[i]
|
||||||
if (!v.match(/rc/)) {
|
const thisVersionAbc = versionAbc(thisVersion)
|
||||||
// release candidates are opt-in
|
const thisVersionAbcRange = semver.validRange(thisVersionAbc)
|
||||||
acc[maybeCoerced(v)] = v
|
|
||||||
|
if (
|
||||||
|
thatVersionAbcRange &&
|
||||||
|
semver.intersects(thatVersionAbcRange, thisVersionAbcRange)
|
||||||
|
) {
|
||||||
|
version = thisVersion
|
||||||
|
break
|
||||||
}
|
}
|
||||||
return acc
|
|
||||||
}, {})
|
|
||||||
const rangeForMax = semver.validRange(spec)
|
|
||||||
if (rangeForMax) {
|
|
||||||
version =
|
|
||||||
versionsMap[semver.maxSatisfying(Object.keys(versionsMap), rangeForMax)]
|
|
||||||
} else {
|
|
||||||
version = versionsMap[maybeCoerced(spec)]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let v = version === null || version === undefined ? null : version
|
return version || null
|
||||||
if (maybePrependWithV0 && v != null) {
|
|
||||||
v = maybePrependWithV(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!versions.includes(v)) {
|
|
||||||
v = null
|
|
||||||
}
|
|
||||||
|
|
||||||
return v
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function maybeCoerced(v) {
|
function maybeCoerced(v) {
|
||||||
let ret
|
let ret = null
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ret = semver.coerce(v).version
|
if (!isRC(v)) {
|
||||||
|
ret = semver.coerce(v).version
|
||||||
|
} else {
|
||||||
|
ret = maybeRemoveVPrefix(v)
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// some stuff can't be coerced, like 'main'
|
// some stuff can't be coerced, like 'main'
|
||||||
ret = v
|
ret = v
|
||||||
@@ -10420,11 +10473,11 @@ function sortVersions(left, right) {
|
|||||||
let ret = 0
|
let ret = 0
|
||||||
const newL = verAsComparableStr(left)
|
const newL = verAsComparableStr(left)
|
||||||
const newR = verAsComparableStr(right)
|
const newR = verAsComparableStr(right)
|
||||||
|
|
||||||
function verAsComparableStr(ver) {
|
function verAsComparableStr(ver) {
|
||||||
const matchGroups = 5
|
const matchGroups = 6
|
||||||
const verSpec = /([^.]+)?\.?([^.]+)?\.?([^.]+)?\.?([^.]+)?\.?([^.]+)?/
|
const verSpec = xyzAbcVersion('', '')
|
||||||
const matches = ver.match(verSpec).splice(1, matchGroups)
|
const matches = ver.match(verSpec).splice(1, matchGroups)
|
||||||
|
|
||||||
return matches.reduce((acc, v) => acc + (v || '0').padStart(3, '0'), '')
|
return matches.reduce((acc, v) => acc + (v || '0').padStart(3, '0'), '')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10437,6 +10490,10 @@ function sortVersions(left, right) {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isRC(ver) {
|
||||||
|
return ver.match(xyzAbcVersion('^', '(?:-rc\\.?\\d+)'))
|
||||||
|
}
|
||||||
|
|
||||||
function getRunnerOSVersion() {
|
function getRunnerOSVersion() {
|
||||||
const ImageOSToContainer = {
|
const ImageOSToContainer = {
|
||||||
ubuntu18: 'ubuntu-18.04',
|
ubuntu18: 'ubuntu-18.04',
|
||||||
@@ -10446,7 +10503,6 @@ function getRunnerOSVersion() {
|
|||||||
win22: 'windows-2022',
|
win22: 'windows-2022',
|
||||||
}
|
}
|
||||||
const containerFromEnvImageOS = ImageOSToContainer[process.env.ImageOS]
|
const containerFromEnvImageOS = ImageOSToContainer[process.env.ImageOS]
|
||||||
|
|
||||||
if (!containerFromEnvImageOS) {
|
if (!containerFromEnvImageOS) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Tried to map a target OS from env. variable 'ImageOS' (got " +
|
"Tried to map a target OS from env. variable 'ImageOS' (got " +
|
||||||
@@ -10467,7 +10523,6 @@ async function get(url0, pageIdxs) {
|
|||||||
const url = new URL(url0)
|
const url = new URL(url0)
|
||||||
const headers = {}
|
const headers = {}
|
||||||
const GithubToken = getInput('github-token', false)
|
const GithubToken = getInput('github-token', false)
|
||||||
|
|
||||||
if (GithubToken && url.host === 'api.github.com') {
|
if (GithubToken && url.host === 'api.github.com') {
|
||||||
headers.authorization = `Bearer ${GithubToken}`
|
headers.authorization = `Bearer ${GithubToken}`
|
||||||
}
|
}
|
||||||
@@ -10480,9 +10535,7 @@ async function get(url0, pageIdxs) {
|
|||||||
allowRetries: true,
|
allowRetries: true,
|
||||||
maxRetries: 3,
|
maxRetries: 3,
|
||||||
})
|
})
|
||||||
|
|
||||||
const response = await httpClient.get(url, headers)
|
const response = await httpClient.get(url, headers)
|
||||||
|
|
||||||
if (response.statusCode >= 400 && response.statusCode <= 599) {
|
if (response.statusCode >= 400 && response.statusCode <= 599) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Got ${response.statusCode} from ${url}. Exiting with error`,
|
`Got ${response.statusCode} from ${url}. Exiting with error`,
|
||||||
@@ -10495,6 +10548,7 @@ async function get(url0, pageIdxs) {
|
|||||||
if (pageIdxs[0] === null) {
|
if (pageIdxs[0] === null) {
|
||||||
return getPage(null)
|
return getPage(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all(pageIdxs.map(getPage))
|
return Promise.all(pageIdxs.map(getPage))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10502,12 +10556,14 @@ async function getWithMirrors(resourcePath, hexMirrors) {
|
|||||||
if (hexMirrors.length === 0) {
|
if (hexMirrors.length === 0) {
|
||||||
throw new Error(`Could not fetch ${resourcePath} from any hex.pm mirror`)
|
throw new Error(`Could not fetch ${resourcePath} from any hex.pm mirror`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const [hexMirror, ...hexMirrorsT] = hexMirrors
|
const [hexMirror, ...hexMirrorsT] = hexMirrors
|
||||||
try {
|
try {
|
||||||
return await get(`${hexMirror}${resourcePath}`, [null])
|
return await get(`${hexMirror}${resourcePath}`, [null])
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
core.info(`get failed for URL ${hexMirror}${resourcePath}`)
|
core.info(`get failed for URL ${hexMirror}${resourcePath}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
return getWithMirrors(resourcePath, hexMirrorsT)
|
return getWithMirrors(resourcePath, hexMirrorsT)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10515,11 +10571,35 @@ function maybePrependWithV(v) {
|
|||||||
if (isVersion(v)) {
|
if (isVersion(v)) {
|
||||||
return `v${v.replace('v', '')}`
|
return `v${v.replace('v', '')}`
|
||||||
}
|
}
|
||||||
|
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function maybeRemoveVPrefix(ver) {
|
||||||
|
let ret = ver
|
||||||
|
if (isVersion(ver)) {
|
||||||
|
ret = ver.replace('v', '')
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
function xyzAbcVersion(pref, suf) {
|
||||||
|
// This accounts for stuff like 6.0.2.0.1.0, as proposed by Erlang's
|
||||||
|
// https://www.erlang.org/doc/system_principles/versions.html
|
||||||
|
const dd = '\\.?(\\d+)?'
|
||||||
|
return new RegExp(
|
||||||
|
`${pref}v?(\\d+)${dd}${dd}${dd}${dd}${dd}(?:-rc\\.?\\d+)?(?:-otp-\\d+)?${suf}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function versionAbc(ver) {
|
||||||
|
// For a version like 6.0.2.0.1.0, return 0.1.0
|
||||||
|
return ver.match(/\d+(?:\.[^.]+)?(?:\.[^.]+)?(?:\.)?(.*)/)[1]
|
||||||
|
}
|
||||||
|
|
||||||
function isVersion(v) {
|
function isVersion(v) {
|
||||||
return /^v?\d+/.test(v)
|
return v.match(xyzAbcVersion('^', '$')) !== null
|
||||||
}
|
}
|
||||||
|
|
||||||
function getInput(inputName, required, alternativeName, alternatives) {
|
function getInput(inputName, required, alternativeName, alternatives) {
|
||||||
@@ -10537,6 +10617,7 @@ alongside ${alternativeName}=${alternativeValue} \
|
|||||||
} else if (!input) {
|
} else if (!input) {
|
||||||
input = alternativeValue
|
input = alternativeValue
|
||||||
}
|
}
|
||||||
|
|
||||||
return input
|
return input
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10550,6 +10631,7 @@ function parseVersionFile(versionFilePath0) {
|
|||||||
`The specified version file, ${versionFilePath0}, does not exist`,
|
`The specified version file, ${versionFilePath0}, does not exist`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
core.startGroup(`Parsing version file at ${versionFilePath0}`)
|
core.startGroup(`Parsing version file at ${versionFilePath0}`)
|
||||||
const appVersions = new Map()
|
const appVersions = new Map()
|
||||||
const versions = fs.readFileSync(versionFilePath, 'utf8')
|
const versions = fs.readFileSync(versionFilePath, 'utf8')
|
||||||
@@ -10583,6 +10665,7 @@ function jsonParseAsList(maybeJson) {
|
|||||||
if (!Array.isArray(obj)) {
|
if (!Array.isArray(obj)) {
|
||||||
throw new Error('expected a list!')
|
throw new Error('expected a list!')
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj
|
return obj
|
||||||
} catch (exc) {
|
} catch (exc) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|||||||
Generated
+972
-3415
File diff suppressed because it is too large
Load Diff
+7
-17
@@ -13,29 +13,19 @@
|
|||||||
"yamllint": "yamllint .github/workflows/**.yml && yamllint .*.yml && yamllint *.yml",
|
"yamllint": "yamllint .github/workflows/**.yml && yamllint .*.yml && yamllint *.yml",
|
||||||
"build-dist": "npm install && npm run build && npm run format && npm run markdownlint && npm run shellcheck && npm run yamllint && npm run jslint"
|
"build-dist": "npm install && npm run build && npm run format && npm run markdownlint && npm run shellcheck && npm run yamllint && npm run jslint"
|
||||||
},
|
},
|
||||||
"husky": {
|
|
||||||
"hooks": {
|
|
||||||
"pre-commit": "npm run format -- --check && npm run build && git add dist/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "1.10.0",
|
"@actions/core": "1.10.0",
|
||||||
"@actions/exec": "1.1.1",
|
"@actions/exec": "1.1.1",
|
||||||
"@actions/http-client": "2.1.0",
|
"@actions/http-client": "2.1.0",
|
||||||
"@actions/tool-cache": "^2.0.1",
|
"@actions/tool-cache": "2.0.1",
|
||||||
"semver": "7.5.2"
|
"semver": "7.5.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vercel/ncc": "0.34.0",
|
"@vercel/ncc": "0.36.1",
|
||||||
"eslint": "8.25.0",
|
"eslint": "8.43.0",
|
||||||
"eslint-config-airbnb": "19.0.4",
|
"markdownlint-cli": "0.35.0",
|
||||||
"eslint-plugin-import": "2.26.0",
|
"prettier": "2.8.8",
|
||||||
"eslint-plugin-jsx-a11y": "6.6.1",
|
"shellcheck": "2.2.0",
|
||||||
"eslint-plugin-react": "7.31.10",
|
|
||||||
"husky": "8.0.1",
|
|
||||||
"markdownlint": "0.26.2",
|
|
||||||
"prettier": "2.7.1",
|
|
||||||
"shellcheck": "1.1.0",
|
|
||||||
"yaml-lint": "1.7.0",
|
"yaml-lint": "1.7.0",
|
||||||
"yarn": "1.22.19"
|
"yarn": "1.22.19"
|
||||||
},
|
},
|
||||||
|
|||||||
+143
-83
@@ -35,15 +35,16 @@ async function main() {
|
|||||||
|
|
||||||
if (otpSpec !== 'false') {
|
if (otpSpec !== 'false') {
|
||||||
await installOTP(otpSpec, osVersion, hexMirrors)
|
await installOTP(otpSpec, osVersion, hexMirrors)
|
||||||
|
|
||||||
const elixirInstalled = await maybeInstallElixir(
|
const elixirInstalled = await maybeInstallElixir(
|
||||||
elixirSpec,
|
elixirSpec,
|
||||||
otpSpec,
|
otpSpec,
|
||||||
hexMirrors,
|
hexMirrors,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (elixirInstalled === true) {
|
if (elixirInstalled === true) {
|
||||||
const shouldMixRebar = getInput('install-rebar', false)
|
const shouldMixRebar = getInput('install-rebar', false)
|
||||||
await mix(shouldMixRebar, 'rebar', hexMirrors)
|
await mix(shouldMixRebar, 'rebar', hexMirrors)
|
||||||
|
|
||||||
const shouldMixHex = getInput('install-hex', false)
|
const shouldMixHex = getInput('install-hex', false)
|
||||||
await mix(shouldMixHex, 'hex', hexMirrors)
|
await mix(shouldMixHex, 'hex', hexMirrors)
|
||||||
}
|
}
|
||||||
@@ -67,7 +68,6 @@ async function installOTP(otpSpec, osVersion, hexMirrors) {
|
|||||||
|
|
||||||
async function maybeInstallElixir(elixirSpec, otpSpec, hexMirrors) {
|
async function maybeInstallElixir(elixirSpec, otpSpec, hexMirrors) {
|
||||||
let installed = false
|
let installed = false
|
||||||
|
|
||||||
if (elixirSpec) {
|
if (elixirSpec) {
|
||||||
const elixirVersion = await getElixirVersion(
|
const elixirVersion = await getElixirVersion(
|
||||||
elixirSpec,
|
elixirSpec,
|
||||||
@@ -77,6 +77,7 @@ async function maybeInstallElixir(elixirSpec, otpSpec, hexMirrors) {
|
|||||||
core.startGroup(`Installing Elixir ${elixirVersion}`)
|
core.startGroup(`Installing Elixir ${elixirVersion}`)
|
||||||
await installer.installElixir(elixirVersion, hexMirrors)
|
await installer.installElixir(elixirVersion, hexMirrors)
|
||||||
core.setOutput('elixir-version', elixirVersion)
|
core.setOutput('elixir-version', elixirVersion)
|
||||||
|
|
||||||
const disableProblemMatchers = getInput('disable_problem_matchers', false)
|
const disableProblemMatchers = getInput('disable_problem_matchers', false)
|
||||||
if (disableProblemMatchers === 'false') {
|
if (disableProblemMatchers === 'false') {
|
||||||
const elixirMatchers = path.join(
|
const elixirMatchers = path.join(
|
||||||
@@ -99,6 +100,7 @@ async function mixWithMirrors(cmd, args, hexMirrors) {
|
|||||||
if (hexMirrors.length === 0) {
|
if (hexMirrors.length === 0) {
|
||||||
throw new Error('mix failed with every mirror')
|
throw new Error('mix failed with every mirror')
|
||||||
}
|
}
|
||||||
|
|
||||||
const [hexMirror, ...hexMirrorsT] = hexMirrors
|
const [hexMirror, ...hexMirrorsT] = hexMirrors
|
||||||
process.env.HEX_MIRROR = hexMirror
|
process.env.HEX_MIRROR = hexMirror
|
||||||
try {
|
try {
|
||||||
@@ -108,6 +110,7 @@ async function mixWithMirrors(cmd, args, hexMirrors) {
|
|||||||
`mix failed with mirror ${process.env.HEX_MIRROR} with message ${err.message})`,
|
`mix failed with mirror ${process.env.HEX_MIRROR} with message ${err.message})`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return mixWithMirrors(cmd, args, hexMirrorsT)
|
return mixWithMirrors(cmd, args, hexMirrorsT)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +126,6 @@ async function mix(shouldMix, what, hexMirrors) {
|
|||||||
|
|
||||||
async function maybeInstallGleam(gleamSpec) {
|
async function maybeInstallGleam(gleamSpec) {
|
||||||
let installed = false
|
let installed = false
|
||||||
|
|
||||||
if (gleamSpec) {
|
if (gleamSpec) {
|
||||||
const gleamVersion = await getGleamVersion(gleamSpec)
|
const gleamVersion = await getGleamVersion(gleamSpec)
|
||||||
core.startGroup(`Installing Gleam ${gleamVersion}`)
|
core.startGroup(`Installing Gleam ${gleamVersion}`)
|
||||||
@@ -141,7 +143,6 @@ async function maybeInstallGleam(gleamSpec) {
|
|||||||
async function maybeInstallRebar3(rebar3Spec) {
|
async function maybeInstallRebar3(rebar3Spec) {
|
||||||
let installed = false
|
let installed = false
|
||||||
let rebar3Version
|
let rebar3Version
|
||||||
|
|
||||||
if (rebar3Spec) {
|
if (rebar3Spec) {
|
||||||
if (rebar3Spec === 'nightly') {
|
if (rebar3Spec === 'nightly') {
|
||||||
rebar3Version = 'nightly'
|
rebar3Version = 'nightly'
|
||||||
@@ -162,14 +163,9 @@ async function maybeInstallRebar3(rebar3Spec) {
|
|||||||
|
|
||||||
async function getOTPVersion(otpSpec0, osVersion, hexMirrors) {
|
async function getOTPVersion(otpSpec0, osVersion, hexMirrors) {
|
||||||
const otpVersions = await getOTPVersions(osVersion, hexMirrors)
|
const otpVersions = await getOTPVersions(osVersion, hexMirrors)
|
||||||
let otpSpec = otpSpec0 // might be a branch (?)
|
const spec = otpSpec0.replace(/^OTP-/, '')
|
||||||
const otpVersion = getVersionFromSpec(
|
const versions = otpVersions
|
||||||
otpSpec,
|
const otpVersion = getVersionFromSpec(spec, versions)
|
||||||
Array.from(otpVersions.keys()).sort(),
|
|
||||||
)
|
|
||||||
if (isVersion(otpSpec0)) {
|
|
||||||
otpSpec = `OTP-${otpSpec0}` // ... it's a version!
|
|
||||||
}
|
|
||||||
if (otpVersion === null) {
|
if (otpVersion === null) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Requested Erlang/OTP version (${otpSpec0}) not found in version list ` +
|
`Requested Erlang/OTP version (${otpSpec0}) not found in version list ` +
|
||||||
@@ -177,20 +173,18 @@ async function getOTPVersion(otpSpec0, osVersion, hexMirrors) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return otpVersions.get(otpVersion) // from the reference, for download
|
return otpVersion // from the reference, for download
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getElixirVersion(exSpec0, otpVersion0, hexMirrors) {
|
async function getElixirVersion(exSpec0, otpVersion0, hexMirrors) {
|
||||||
const otpVersion = otpVersion0.match(/^([^-]+-)?(.+)$/)[2]
|
const otpVersion = otpVersion0.match(/^([^-]+-)?(.+)$/)[2]
|
||||||
const otpVersionMajor = otpVersion.match(/^([^.]+).*$/)[1]
|
const otpVersionMajor = otpVersion.match(/^([^.]+).*$/)[1]
|
||||||
const elixirVersions = await getElixirVersions(hexMirrors)
|
const [otpVersionsForElixirMap, elixirVersions] = await getElixirVersions(
|
||||||
const semverVersions = Array.from(elixirVersions.keys()).sort()
|
hexMirrors,
|
||||||
const exSpec = exSpec0.replace(/-otp-.*$/, '')
|
)
|
||||||
const elixirVersionFromSpec = getVersionFromSpec(exSpec, semverVersions, true)
|
const spec = exSpec0.replace(/-otp-.*$/, '')
|
||||||
let elixirVersionForDownload = elixirVersionFromSpec
|
const versions = elixirVersions
|
||||||
if (isVersion(otpVersionMajor)) {
|
const elixirVersionFromSpec = getVersionFromSpec(spec, versions)
|
||||||
elixirVersionForDownload = `${elixirVersionFromSpec}-otp-${otpVersionMajor}`
|
|
||||||
}
|
|
||||||
if (elixirVersionFromSpec === null) {
|
if (elixirVersionFromSpec === null) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Requested Elixir version (${exSpec0}) not found in version list ` +
|
`Requested Elixir version (${exSpec0}) not found in version list ` +
|
||||||
@@ -198,7 +192,7 @@ async function getElixirVersion(exSpec0, otpVersion0, hexMirrors) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const elixirVersionComp = elixirVersions.get(elixirVersionFromSpec)
|
const elixirVersionComp = otpVersionsForElixirMap[elixirVersionFromSpec]
|
||||||
if (
|
if (
|
||||||
(elixirVersionComp && elixirVersionComp.includes(otpVersionMajor)) ||
|
(elixirVersionComp && elixirVersionComp.includes(otpVersionMajor)) ||
|
||||||
!isVersion(otpVersionMajor)
|
!isVersion(otpVersionMajor)
|
||||||
@@ -215,13 +209,20 @@ async function getElixirVersion(exSpec0, otpVersion0, hexMirrors) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let elixirVersionForDownload = elixirVersionFromSpec
|
||||||
|
|
||||||
|
if (isVersion(otpVersionMajor)) {
|
||||||
|
elixirVersionForDownload = `${elixirVersionFromSpec}-otp-${otpVersionMajor}`
|
||||||
|
}
|
||||||
|
|
||||||
return maybePrependWithV(elixirVersionForDownload)
|
return maybePrependWithV(elixirVersionForDownload)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getGleamVersion(gleamSpec0) {
|
async function getGleamVersion(gleamSpec0) {
|
||||||
const gleamSpec = gleamSpec0.match(/^v?(.+)$/)
|
|
||||||
const gleamVersions = await getGleamVersions()
|
const gleamVersions = await getGleamVersions()
|
||||||
const gleamVersion = getVersionFromSpec(gleamSpec[1], gleamVersions, true)
|
const spec = gleamSpec0
|
||||||
|
const versions = gleamVersions
|
||||||
|
const gleamVersion = getVersionFromSpec(spec, versions)
|
||||||
if (gleamVersion === null) {
|
if (gleamVersion === null) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Requested Gleam version (${gleamSpec0}) not found in version list ` +
|
`Requested Gleam version (${gleamSpec0}) not found in version list ` +
|
||||||
@@ -229,12 +230,14 @@ async function getGleamVersion(gleamSpec0) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return maybePrependWithV(gleamVersion, gleamVersion)
|
return maybePrependWithV(gleamVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getRebar3Version(r3Spec) {
|
async function getRebar3Version(r3Spec) {
|
||||||
const rebar3Versions = await getRebar3Versions()
|
const rebar3Versions = await getRebar3Versions()
|
||||||
const rebar3Version = getVersionFromSpec(r3Spec, rebar3Versions)
|
const spec = r3Spec
|
||||||
|
const versions = rebar3Versions
|
||||||
|
const rebar3Version = getVersionFromSpec(spec, versions)
|
||||||
if (rebar3Version === null) {
|
if (rebar3Version === null) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Requested rebar3 version (${r3Spec}) not found in version list ` +
|
`Requested rebar3 version (${r3Spec}) not found in version list ` +
|
||||||
@@ -257,8 +260,9 @@ async function getOTPVersions(osVersion, hexMirrors) {
|
|||||||
otpVersionsListings = await get(originListing, [1, 2, 3])
|
otpVersionsListings = await get(originListing, [1, 2, 3])
|
||||||
}
|
}
|
||||||
|
|
||||||
const otpVersions = new Map()
|
debugLog(`OTP versions listings from ${originListing}`, otpVersionsListings)
|
||||||
|
|
||||||
|
const otpVersions = {}
|
||||||
if (process.platform === 'linux') {
|
if (process.platform === 'linux') {
|
||||||
otpVersionsListings
|
otpVersionsListings
|
||||||
.trim()
|
.trim()
|
||||||
@@ -268,8 +272,9 @@ async function getOTPVersions(osVersion, hexMirrors) {
|
|||||||
.match(/^([^ ]+)?( .+)/)[1]
|
.match(/^([^ ]+)?( .+)/)[1]
|
||||||
.match(/^([^-]+-)?(.+)$/)
|
.match(/^([^-]+-)?(.+)$/)
|
||||||
const otpVersion = otpMatch[2]
|
const otpVersion = otpMatch[2]
|
||||||
|
const otpVersionOrig = otpMatch[0]
|
||||||
debugLog('OTP line and parsing', [line, otpVersion, otpMatch])
|
debugLog('OTP line and parsing', [line, otpVersion, otpMatch])
|
||||||
otpVersions.set(otpVersion, otpMatch[0]) // we keep the original for later reference
|
otpVersions[otpVersion] = otpVersionOrig // we keep the original for later reference
|
||||||
})
|
})
|
||||||
} else if (process.platform === 'win32') {
|
} else if (process.platform === 'win32') {
|
||||||
otpVersionsListings.forEach((otpVersionsListing) => {
|
otpVersionsListings.forEach((otpVersionsListing) => {
|
||||||
@@ -281,15 +286,12 @@ async function getOTPVersions(osVersion, hexMirrors) {
|
|||||||
const otpMatch = x.name.match(/^otp_win64_(.*).exe$/)
|
const otpMatch = x.name.match(/^otp_win64_(.*).exe$/)
|
||||||
const otpVersion = otpMatch[1]
|
const otpVersion = otpMatch[1]
|
||||||
debugLog('OTP line and parsing', [otpMatch, otpVersion])
|
debugLog('OTP line and parsing', [otpMatch, otpVersion])
|
||||||
otpVersions.set(otpVersion, otpVersion)
|
otpVersions[otpVersion] = otpVersion
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
debugLog(
|
debugLog(`OTP versions from ${originListing}`, JSON.stringify(otpVersions))
|
||||||
`OTP versions from ${originListing}`,
|
|
||||||
JSON.stringify([...otpVersions.entries()]),
|
|
||||||
)
|
|
||||||
|
|
||||||
return otpVersions
|
return otpVersions
|
||||||
}
|
}
|
||||||
@@ -299,7 +301,8 @@ async function getElixirVersions(hexMirrors) {
|
|||||||
'/builds/elixir/builds.txt',
|
'/builds/elixir/builds.txt',
|
||||||
hexMirrors,
|
hexMirrors,
|
||||||
)
|
)
|
||||||
const otpVersionsForElixirMap = new Map()
|
const otpVersionsForElixirMap = {}
|
||||||
|
const elixirVersions = {}
|
||||||
|
|
||||||
elixirVersionsListings
|
elixirVersionsListings
|
||||||
.trim()
|
.trim()
|
||||||
@@ -307,17 +310,18 @@ async function getElixirVersions(hexMirrors) {
|
|||||||
.forEach((line) => {
|
.forEach((line) => {
|
||||||
const elixirMatch =
|
const elixirMatch =
|
||||||
line.match(/^v?(.+)-otp-([^ ]+)/) || line.match(/^v?([^ ]+)/)
|
line.match(/^v?(.+)-otp-([^ ]+)/) || line.match(/^v?([^ ]+)/)
|
||||||
const elixirVersion = maybePrependWithV(elixirMatch[1])
|
const elixirVersion = elixirMatch[1]
|
||||||
const otpVersion = elixirMatch[2]
|
const otpVersion = elixirMatch[2]
|
||||||
const otpVersions = otpVersionsForElixirMap.get(elixirVersion) || []
|
const otpVersions = otpVersionsForElixirMap[elixirVersion] || []
|
||||||
if (otpVersion) {
|
if (otpVersion) {
|
||||||
// -otp- present (special case)
|
// -otp- present (special case)
|
||||||
otpVersions.push(otpVersion)
|
otpVersions.push(otpVersion)
|
||||||
}
|
}
|
||||||
otpVersionsForElixirMap.set(elixirVersion, otpVersions)
|
otpVersionsForElixirMap[elixirVersion] = otpVersions
|
||||||
|
elixirVersions[elixirVersion] = elixirVersion
|
||||||
})
|
})
|
||||||
|
|
||||||
return otpVersionsForElixirMap
|
return [otpVersionsForElixirMap, elixirVersions]
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getGleamVersions() {
|
async function getGleamVersions() {
|
||||||
@@ -325,13 +329,17 @@ async function getGleamVersions() {
|
|||||||
'https://api.github.com/repos/gleam-lang/gleam/releases?per_page=100',
|
'https://api.github.com/repos/gleam-lang/gleam/releases?per_page=100',
|
||||||
[1, 2, 3],
|
[1, 2, 3],
|
||||||
)
|
)
|
||||||
const gleamVersionsListing = []
|
const gleamVersionsListing = {}
|
||||||
resultJSONs.forEach((resultJSON) => {
|
resultJSONs.forEach((resultJSON) => {
|
||||||
jsonParseAsList(resultJSON)
|
jsonParseAsList(resultJSON)
|
||||||
.map((x) => x.tag_name)
|
.map((x) => x.tag_name)
|
||||||
.sort()
|
.forEach((ver) => {
|
||||||
.forEach((v) => gleamVersionsListing.push(v))
|
const gleamMatch = ver.match(/^v?([^ ]+)/)
|
||||||
|
const gleamVersion = gleamMatch[1]
|
||||||
|
gleamVersionsListing[gleamVersion] = gleamVersion
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return gleamVersionsListing
|
return gleamVersionsListing
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,13 +348,15 @@ async function getRebar3Versions() {
|
|||||||
'https://api.github.com/repos/erlang/rebar3/releases?per_page=100',
|
'https://api.github.com/repos/erlang/rebar3/releases?per_page=100',
|
||||||
[1, 2, 3],
|
[1, 2, 3],
|
||||||
)
|
)
|
||||||
const rebar3VersionsListing = []
|
const rebar3VersionsListing = {}
|
||||||
resultJSONs.forEach((resultJSON) => {
|
resultJSONs.forEach((resultJSON) => {
|
||||||
jsonParseAsList(resultJSON)
|
jsonParseAsList(resultJSON)
|
||||||
.map((x) => x.tag_name)
|
.map((x) => x.tag_name)
|
||||||
.sort()
|
.forEach((ver) => {
|
||||||
.forEach((v) => rebar3VersionsListing.push(v))
|
rebar3VersionsListing[ver] = ver
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return rebar3VersionsListing
|
return rebar3VersionsListing
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,48 +364,68 @@ function isStrictVersion() {
|
|||||||
return getInput('version-type', false) === 'strict'
|
return getInput('version-type', false) === 'strict'
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVersionFromSpec(spec, versions, maybePrependWithV0) {
|
function getVersionFromSpec(spec0, versions0) {
|
||||||
|
const spec = maybeRemoveVPrefix(spec0)
|
||||||
|
|
||||||
|
const altVersions = {}
|
||||||
|
Object.entries(versions0).forEach(([version, altVersion]) => {
|
||||||
|
let coerced
|
||||||
|
if (isStrictVersion() || isRC(version)) {
|
||||||
|
// If `version-type: strict` or version is RC, we just try to remove a potential initial v
|
||||||
|
coerced = maybeRemoveVPrefix(version)
|
||||||
|
} else {
|
||||||
|
// Otherwise, we place the version into a version bucket
|
||||||
|
coerced = maybeCoerced(version)
|
||||||
|
}
|
||||||
|
const alt = (altVersions[coerced] || []).concat(altVersion)
|
||||||
|
alt.sort(sortVersions)
|
||||||
|
altVersions[coerced] = alt
|
||||||
|
})
|
||||||
|
|
||||||
|
let versions = Object.keys(altVersions)
|
||||||
|
|
||||||
|
const rangeForMax = semver.validRange(spec0) || maybeCoerced(spec)
|
||||||
|
const rangeMax = semver.maxSatisfying(versions, rangeForMax)
|
||||||
let version = null
|
let version = null
|
||||||
|
|
||||||
if (spec.match(/rc/) || isStrictVersion()) {
|
if (isStrictVersion() || isRC(spec0)) {
|
||||||
version = spec
|
if (versions0[spec]) {
|
||||||
}
|
// If `version-type: strict` or version is RC, we obtain it directly
|
||||||
|
version = versions0[spec]
|
||||||
|
}
|
||||||
|
} else if (rangeMax !== null) {
|
||||||
|
// Otherwise, we compare alt. versions' semver ranges to this version, from highest to lowest
|
||||||
|
const thatVersion = spec
|
||||||
|
const thatVersionAbc = versionAbc(thatVersion)
|
||||||
|
const thatVersionAbcRange = semver.validRange(thatVersionAbc)
|
||||||
|
|
||||||
if (version === null) {
|
versions = altVersions[rangeMax]
|
||||||
// We keep a map of semver => "spec" in order to use semver ranges to find appropriate versions
|
for (let i = versions.length - 1; i >= 0; i -= 1) {
|
||||||
const versionsMap = versions.sort(sortVersions).reduce((acc, v) => {
|
const thisVersion = versions[i]
|
||||||
if (!v.match(/rc/)) {
|
const thisVersionAbc = versionAbc(thisVersion)
|
||||||
// release candidates are opt-in
|
const thisVersionAbcRange = semver.validRange(thisVersionAbc)
|
||||||
acc[maybeCoerced(v)] = v
|
|
||||||
|
if (
|
||||||
|
thatVersionAbcRange &&
|
||||||
|
semver.intersects(thatVersionAbcRange, thisVersionAbcRange)
|
||||||
|
) {
|
||||||
|
version = thisVersion
|
||||||
|
break
|
||||||
}
|
}
|
||||||
return acc
|
|
||||||
}, {})
|
|
||||||
const rangeForMax = semver.validRange(spec)
|
|
||||||
if (rangeForMax) {
|
|
||||||
version =
|
|
||||||
versionsMap[semver.maxSatisfying(Object.keys(versionsMap), rangeForMax)]
|
|
||||||
} else {
|
|
||||||
version = versionsMap[maybeCoerced(spec)]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let v = version === null || version === undefined ? null : version
|
return version || null
|
||||||
if (maybePrependWithV0 && v != null) {
|
|
||||||
v = maybePrependWithV(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!versions.includes(v)) {
|
|
||||||
v = null
|
|
||||||
}
|
|
||||||
|
|
||||||
return v
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function maybeCoerced(v) {
|
function maybeCoerced(v) {
|
||||||
let ret
|
let ret = null
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ret = semver.coerce(v).version
|
if (!isRC(v)) {
|
||||||
|
ret = semver.coerce(v).version
|
||||||
|
} else {
|
||||||
|
ret = maybeRemoveVPrefix(v)
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// some stuff can't be coerced, like 'main'
|
// some stuff can't be coerced, like 'main'
|
||||||
ret = v
|
ret = v
|
||||||
@@ -408,11 +438,11 @@ function sortVersions(left, right) {
|
|||||||
let ret = 0
|
let ret = 0
|
||||||
const newL = verAsComparableStr(left)
|
const newL = verAsComparableStr(left)
|
||||||
const newR = verAsComparableStr(right)
|
const newR = verAsComparableStr(right)
|
||||||
|
|
||||||
function verAsComparableStr(ver) {
|
function verAsComparableStr(ver) {
|
||||||
const matchGroups = 5
|
const matchGroups = 6
|
||||||
const verSpec = /([^.]+)?\.?([^.]+)?\.?([^.]+)?\.?([^.]+)?\.?([^.]+)?/
|
const verSpec = xyzAbcVersion('', '')
|
||||||
const matches = ver.match(verSpec).splice(1, matchGroups)
|
const matches = ver.match(verSpec).splice(1, matchGroups)
|
||||||
|
|
||||||
return matches.reduce((acc, v) => acc + (v || '0').padStart(3, '0'), '')
|
return matches.reduce((acc, v) => acc + (v || '0').padStart(3, '0'), '')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,6 +455,10 @@ function sortVersions(left, right) {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isRC(ver) {
|
||||||
|
return ver.match(xyzAbcVersion('^', '(?:-rc\\.?\\d+)'))
|
||||||
|
}
|
||||||
|
|
||||||
function getRunnerOSVersion() {
|
function getRunnerOSVersion() {
|
||||||
const ImageOSToContainer = {
|
const ImageOSToContainer = {
|
||||||
ubuntu18: 'ubuntu-18.04',
|
ubuntu18: 'ubuntu-18.04',
|
||||||
@@ -434,7 +468,6 @@ function getRunnerOSVersion() {
|
|||||||
win22: 'windows-2022',
|
win22: 'windows-2022',
|
||||||
}
|
}
|
||||||
const containerFromEnvImageOS = ImageOSToContainer[process.env.ImageOS]
|
const containerFromEnvImageOS = ImageOSToContainer[process.env.ImageOS]
|
||||||
|
|
||||||
if (!containerFromEnvImageOS) {
|
if (!containerFromEnvImageOS) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Tried to map a target OS from env. variable 'ImageOS' (got " +
|
"Tried to map a target OS from env. variable 'ImageOS' (got " +
|
||||||
@@ -455,7 +488,6 @@ async function get(url0, pageIdxs) {
|
|||||||
const url = new URL(url0)
|
const url = new URL(url0)
|
||||||
const headers = {}
|
const headers = {}
|
||||||
const GithubToken = getInput('github-token', false)
|
const GithubToken = getInput('github-token', false)
|
||||||
|
|
||||||
if (GithubToken && url.host === 'api.github.com') {
|
if (GithubToken && url.host === 'api.github.com') {
|
||||||
headers.authorization = `Bearer ${GithubToken}`
|
headers.authorization = `Bearer ${GithubToken}`
|
||||||
}
|
}
|
||||||
@@ -468,9 +500,7 @@ async function get(url0, pageIdxs) {
|
|||||||
allowRetries: true,
|
allowRetries: true,
|
||||||
maxRetries: 3,
|
maxRetries: 3,
|
||||||
})
|
})
|
||||||
|
|
||||||
const response = await httpClient.get(url, headers)
|
const response = await httpClient.get(url, headers)
|
||||||
|
|
||||||
if (response.statusCode >= 400 && response.statusCode <= 599) {
|
if (response.statusCode >= 400 && response.statusCode <= 599) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Got ${response.statusCode} from ${url}. Exiting with error`,
|
`Got ${response.statusCode} from ${url}. Exiting with error`,
|
||||||
@@ -483,6 +513,7 @@ async function get(url0, pageIdxs) {
|
|||||||
if (pageIdxs[0] === null) {
|
if (pageIdxs[0] === null) {
|
||||||
return getPage(null)
|
return getPage(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all(pageIdxs.map(getPage))
|
return Promise.all(pageIdxs.map(getPage))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -490,12 +521,14 @@ async function getWithMirrors(resourcePath, hexMirrors) {
|
|||||||
if (hexMirrors.length === 0) {
|
if (hexMirrors.length === 0) {
|
||||||
throw new Error(`Could not fetch ${resourcePath} from any hex.pm mirror`)
|
throw new Error(`Could not fetch ${resourcePath} from any hex.pm mirror`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const [hexMirror, ...hexMirrorsT] = hexMirrors
|
const [hexMirror, ...hexMirrorsT] = hexMirrors
|
||||||
try {
|
try {
|
||||||
return await get(`${hexMirror}${resourcePath}`, [null])
|
return await get(`${hexMirror}${resourcePath}`, [null])
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
core.info(`get failed for URL ${hexMirror}${resourcePath}`)
|
core.info(`get failed for URL ${hexMirror}${resourcePath}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
return getWithMirrors(resourcePath, hexMirrorsT)
|
return getWithMirrors(resourcePath, hexMirrorsT)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -503,11 +536,35 @@ function maybePrependWithV(v) {
|
|||||||
if (isVersion(v)) {
|
if (isVersion(v)) {
|
||||||
return `v${v.replace('v', '')}`
|
return `v${v.replace('v', '')}`
|
||||||
}
|
}
|
||||||
|
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function maybeRemoveVPrefix(ver) {
|
||||||
|
let ret = ver
|
||||||
|
if (isVersion(ver)) {
|
||||||
|
ret = ver.replace('v', '')
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
function xyzAbcVersion(pref, suf) {
|
||||||
|
// This accounts for stuff like 6.0.2.0.1.0, as proposed by Erlang's
|
||||||
|
// https://www.erlang.org/doc/system_principles/versions.html
|
||||||
|
const dd = '\\.?(\\d+)?'
|
||||||
|
return new RegExp(
|
||||||
|
`${pref}v?(\\d+)${dd}${dd}${dd}${dd}${dd}(?:-rc\\.?\\d+)?(?:-otp-\\d+)?${suf}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function versionAbc(ver) {
|
||||||
|
// For a version like 6.0.2.0.1.0, return 0.1.0
|
||||||
|
return ver.match(/\d+(?:\.[^.]+)?(?:\.[^.]+)?(?:\.)?(.*)/)[1]
|
||||||
|
}
|
||||||
|
|
||||||
function isVersion(v) {
|
function isVersion(v) {
|
||||||
return /^v?\d+/.test(v)
|
return v.match(xyzAbcVersion('^', '$')) !== null
|
||||||
}
|
}
|
||||||
|
|
||||||
function getInput(inputName, required, alternativeName, alternatives) {
|
function getInput(inputName, required, alternativeName, alternatives) {
|
||||||
@@ -525,6 +582,7 @@ alongside ${alternativeName}=${alternativeValue} \
|
|||||||
} else if (!input) {
|
} else if (!input) {
|
||||||
input = alternativeValue
|
input = alternativeValue
|
||||||
}
|
}
|
||||||
|
|
||||||
return input
|
return input
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -538,6 +596,7 @@ function parseVersionFile(versionFilePath0) {
|
|||||||
`The specified version file, ${versionFilePath0}, does not exist`,
|
`The specified version file, ${versionFilePath0}, does not exist`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
core.startGroup(`Parsing version file at ${versionFilePath0}`)
|
core.startGroup(`Parsing version file at ${versionFilePath0}`)
|
||||||
const appVersions = new Map()
|
const appVersions = new Map()
|
||||||
const versions = fs.readFileSync(versionFilePath, 'utf8')
|
const versions = fs.readFileSync(versionFilePath, 'utf8')
|
||||||
@@ -571,6 +630,7 @@ function jsonParseAsList(maybeJson) {
|
|||||||
if (!Array.isArray(obj)) {
|
if (!Array.isArray(obj)) {
|
||||||
throw new Error('expected a list!')
|
throw new Error('expected a list!')
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj
|
return obj
|
||||||
} catch (exc) {
|
} catch (exc) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|||||||
+52
-2
@@ -104,9 +104,18 @@ async function testOTPVersions() {
|
|||||||
let expected
|
let expected
|
||||||
let spec
|
let spec
|
||||||
let osVersion
|
let osVersion
|
||||||
|
let before
|
||||||
const hexMirrors = ['https://repo.hex.pm', 'https://cdn.jsdelivr.net/hex']
|
const hexMirrors = ['https://repo.hex.pm', 'https://cdn.jsdelivr.net/hex']
|
||||||
|
|
||||||
if (process.platform === 'linux') {
|
if (process.platform === 'linux') {
|
||||||
|
before = simulateInput('version-type', 'strict')
|
||||||
|
spec = '25.3.2.1'
|
||||||
|
osVersion = 'ubuntu-20.04'
|
||||||
|
expected = 'OTP-25.3.2.1'
|
||||||
|
got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
|
||||||
|
assert.deepStrictEqual(got, expected)
|
||||||
|
simulateInput('version-type', before)
|
||||||
|
|
||||||
spec = '19.3.x'
|
spec = '19.3.x'
|
||||||
osVersion = 'ubuntu-16.04'
|
osVersion = 'ubuntu-16.04'
|
||||||
expected = 'OTP-19.3.6.13'
|
expected = 'OTP-19.3.6.13'
|
||||||
@@ -131,6 +140,12 @@ async function testOTPVersions() {
|
|||||||
got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
|
got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
|
||||||
assert.deepStrictEqual(got, expected)
|
assert.deepStrictEqual(got, expected)
|
||||||
|
|
||||||
|
spec = '20.3.8.26'
|
||||||
|
osVersion = 'ubuntu-20.04'
|
||||||
|
expected = 'OTP-20.3.8.26'
|
||||||
|
got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
|
||||||
|
assert.deepStrictEqual(got, expected)
|
||||||
|
|
||||||
spec = '20.x'
|
spec = '20.x'
|
||||||
osVersion = 'ubuntu-20.04'
|
osVersion = 'ubuntu-20.04'
|
||||||
expected = 'OTP-20.3.8.26'
|
expected = 'OTP-20.3.8.26'
|
||||||
@@ -291,7 +306,7 @@ async function testGetVersionFromSpec() {
|
|||||||
let expected
|
let expected
|
||||||
let spec
|
let spec
|
||||||
let before
|
let before
|
||||||
const versions = [
|
const versions0 = [
|
||||||
'3.2.30.5',
|
'3.2.30.5',
|
||||||
'3.2.3.5',
|
'3.2.3.5',
|
||||||
'1',
|
'1',
|
||||||
@@ -317,10 +332,20 @@ async function testGetVersionFromSpec() {
|
|||||||
'22.3.4.9.1',
|
'22.3.4.9.1',
|
||||||
'22.3.4.12.1',
|
'22.3.4.12.1',
|
||||||
'22.3.4.10.1',
|
'22.3.4.10.1',
|
||||||
|
'22.3.4.2',
|
||||||
'main',
|
'main',
|
||||||
'v11.11.0-rc.0-otp-23',
|
'v11.11.0-rc.0-otp-23',
|
||||||
'22.3.4.2',
|
'22.3.4.2.1.0',
|
||||||
|
'12.1.2.2',
|
||||||
|
'12.1.2.4',
|
||||||
|
'12.1.2.0',
|
||||||
|
'12.1.2.3',
|
||||||
|
'12.1.2.3.0',
|
||||||
]
|
]
|
||||||
|
const versions = {}
|
||||||
|
versions0.forEach((version) => {
|
||||||
|
versions[version] = version
|
||||||
|
})
|
||||||
|
|
||||||
spec = '1'
|
spec = '1'
|
||||||
expected = '1.1.0'
|
expected = '1.1.0'
|
||||||
@@ -417,6 +442,31 @@ async function testGetVersionFromSpec() {
|
|||||||
assert.deepStrictEqual(got, expected)
|
assert.deepStrictEqual(got, expected)
|
||||||
simulateInput('version-type', before)
|
simulateInput('version-type', before)
|
||||||
|
|
||||||
|
spec = '22.3.4.2'
|
||||||
|
expected = '22.3.4.2.1.0'
|
||||||
|
got = setupBeam.getVersionFromSpec(spec, versions)
|
||||||
|
assert.deepStrictEqual(got, expected)
|
||||||
|
|
||||||
|
spec = '22.3.4.2.1'
|
||||||
|
expected = '22.3.4.2.1.0'
|
||||||
|
got = setupBeam.getVersionFromSpec(spec, versions)
|
||||||
|
assert.deepStrictEqual(got, expected)
|
||||||
|
|
||||||
|
spec = '22.3.4.2.1.0'
|
||||||
|
expected = '22.3.4.2.1.0'
|
||||||
|
got = setupBeam.getVersionFromSpec(spec, versions)
|
||||||
|
assert.deepStrictEqual(got, expected)
|
||||||
|
|
||||||
|
spec = '12.1.2.3'
|
||||||
|
expected = '12.1.2.3.0'
|
||||||
|
got = setupBeam.getVersionFromSpec(spec, versions)
|
||||||
|
assert.deepStrictEqual(got, expected)
|
||||||
|
|
||||||
|
spec = '22.3.4.2.1.0.1'
|
||||||
|
expected = null
|
||||||
|
got = setupBeam.getVersionFromSpec(spec, versions)
|
||||||
|
assert.deepStrictEqual(got, expected)
|
||||||
|
|
||||||
before = simulateInput('version-type', 'strict')
|
before = simulateInput('version-type', 'strict')
|
||||||
spec = '22.3.4.3'
|
spec = '22.3.4.3'
|
||||||
expected = null
|
expected = null
|
||||||
|
|||||||
Reference in New Issue
Block a user