Improve visibility (+ fix bugs) over version-type and opt-in versions (#57)

(and tweak README regarding action versioning)
This commit is contained in:
Paulo F. Oliveira
2021-07-09 10:11:50 +01:00
committed by GitHub
parent d8a37f5aac
commit 830642517c
5 changed files with 113 additions and 48 deletions
+12
View File
@@ -92,6 +92,17 @@ jobs:
otp-version: '24'
rebar3-version: '3.15'
os: 'ubuntu-20.04'
- elixir-version: 'v1.11.0'
otp-version: '22.3.4.2'
os: 'ubuntu-20.04'
version-type: 'strict'
- elixir-version: '1.10.3'
otp-version: '22.3.4.1'
os: 'ubuntu-20.04'
version-type: 'strict'
- elixir-version: '1.10.3'
otp-version: '22.3.4.1'
os: 'ubuntu-20.04'
steps:
- uses: actions/checkout@v2
- name: Use erlef/setup-beam
@@ -101,6 +112,7 @@ jobs:
otp-version: ${{matrix.combo.otp-version}}
elixir-version: ${{matrix.combo.elixir-version}}
rebar3-version: ${{matrix.combo.rebar3-version}}
version-type: ${{matrix.combo.version-type}}
- name: Erlang/OTP version (action)
run: echo "Erlang/OTP ${{steps.setup-beam.outputs.otp-version}}"
- name: Elixir version (action)
+15 -3
View File
@@ -34,9 +34,9 @@ Additionally, it is recommended that one specifies Erlang/OTP, Elixir and `rebar
using YAML strings, as these examples do, so that numbers like `23.0` don't
end up being parsed as `23`, which is not equivalent.
For pre-release Elixir versions, such as `1.11.0-rc.0`, use the full version
specifier (`1.11.0-rc.0`). Pre-release versions are opt-in, so `1.11.x` will
not match a pre-release.
For pre-release versions, such as `v1.11.0-rc.0`, use the full version
specifier (`v1.11.0-rc.0`) and set option `version-type` to `strict`. Pre-release versions are
opt-in, so `1.11.x` will not match a pre-release.
### Compatibility between Operating System and Erlang/OTP
@@ -159,6 +159,18 @@ jobs:
The Elixir Problem Matchers in this repository are adapted from [here](https://github.com/fr1zle/vscode-elixir/blob/45eddb589acd7ac98e0c7305d1c2b24668ca709a/package.json#L70-L118). See [MATCHER_NOTICE](MATCHER_NOTICE.md) for license details.
## Action versioning
`setup-beam` has three version paths, described below, for example version `1.8.0`:
- `@v1`: the latest in the `1.y.z` series (this tag is movable),
- `@v1.8`: the latest in the `1.8.z` series (this tag is movable),
- `@v1.8.0`: release `1.8.0` (this tag is not movable).
To prevent issues in CI (unless you're OK with potential incompatibility between versions - we
make real a effort to not introduce those without bumping major) we suggest you to use `@vx.y.z`,
whenever possible.
## License
The scripts and documentation in this project are released under the [MIT license](LICENSE.md).
+24 -17
View File
@@ -166,6 +166,12 @@ async function testElixirVersions() {
got = await setupBeam.getElixirVersion(spec, otpVersion)
assert.deepStrictEqual(got, expected)
spec = '1.12.1'
otpVersion = 'OTP-24.0.2'
expected = 'v1.12.1-otp-24'
got = await setupBeam.getElixirVersion(spec, otpVersion)
assert.deepStrictEqual(got, expected)
simulateInput('version-type', 'strict')
spec = 'v1.11.0-rc.0'
otpVersion = 'OTP-23'
@@ -173,6 +179,14 @@ async function testElixirVersions() {
got = await setupBeam.getElixirVersion(spec, otpVersion)
assert.deepStrictEqual(got, expected)
simulateInput('version-type', 'loose')
simulateInput('version-type', 'strict')
spec = 'v1.11.0'
otpVersion = '22.3.4.2'
expected = 'v1.11.0-otp-22'
got = await setupBeam.getElixirVersion(spec, otpVersion)
assert.deepStrictEqual(got, expected)
simulateInput('version-type', 'loose')
}
async function testRebar3Versions() {
@@ -228,6 +242,7 @@ async function testGetVersionFromSpec() {
'22.3.4.10.1',
'master',
'v11.11.0-rc.0-otp-23',
'22.3.4.2',
]
spec = '1'
@@ -286,6 +301,11 @@ async function testGetVersionFromSpec() {
assert.deepStrictEqual(got, expected)
simulateInput('version-type', 'loose')
spec = '24.0-rc2'
expected = '24.0-rc2'
got = setupBeam.getVersionFromSpec(spec, versions)
assert.deepStrictEqual(got, expected)
spec = '22.3'
expected = '22.3.4.12.1'
got = setupBeam.getVersionFromSpec(spec, versions)
@@ -318,25 +338,12 @@ async function testGetVersionFromSpec() {
got = setupBeam.getVersionFromSpec(spec, versions)
assert.deepStrictEqual(got, expected)
spec = '11.11'
expected = 'v11.11.0-rc.0-otp-23'
got = setupBeam.getVersionFromSpec(spec, versions)
assert.deepStrictEqual(got, expected)
spec = '11.11.0'
expected = 'v11.11.0-rc.0-otp-23'
got = setupBeam.getVersionFromSpec(spec, versions)
assert.deepStrictEqual(got, expected)
spec = 'v11.11'
expected = 'v11.11.0-rc.0-otp-23'
got = setupBeam.getVersionFromSpec(spec, versions)
assert.deepStrictEqual(got, expected)
spec = 'v11.11.0'
expected = 'v11.11.0-rc.0-otp-23'
simulateInput('version-type', 'strict')
spec = '22.3.4.2'
expected = '22.3.4.2'
got = setupBeam.getVersionFromSpec(spec, versions)
assert.deepStrictEqual(got, expected)
simulateInput('version-type', 'loose')
}
function simulateInput(key, value) {
+31 -14
View File
@@ -4777,7 +4777,8 @@ async function getOTPVersion(otpSpec0, osVersion) {
}
if (otpVersion === null) {
throw new Error(
`Requested Erlang/OTP version (${otpSpec0}) not found in version list`,
`Requested Erlang/OTP version (${otpSpec0}) not found in version list ` +
"(should you be using option 'version-type': 'strict'?)",
)
}
@@ -4788,7 +4789,7 @@ async function getElixirVersion(exSpec0, otpVersion) {
const elixirVersions = await getElixirVersions()
const semverVersions = Array.from(elixirVersions.keys()).sort()
const exSpec = exSpec0.match(/^(.+)(-otp-.+)/) || exSpec0.match(/^(.+)/)
const exSpec = exSpec0.match(/^v?(.+)(-otp-.+)/) || exSpec0.match(/^v?(.+)/)
let elixirVersion
if (exSpec[2]) {
throw new Error(
@@ -4801,7 +4802,8 @@ async function getElixirVersion(exSpec0, otpVersion) {
}
if (!exSpec || elixirVersion === null) {
throw new Error(
`Requested Elixir version (${exSpec0}) not found in version list`,
`Requested Elixir version (${exSpec0}) not found in version list ` +
"(should you be using option 'version-type': 'strict'?)",
)
}
const otpMatch = otpVersion.match(/^(?:OTP-)?([^.]+)/)
@@ -4824,11 +4826,11 @@ async function getElixirVersion(exSpec0, otpVersion) {
} else {
throw new Error(
`Requested Elixir / Erlang/OTP version (${exSpec0} / ${otpVersion}) not ` +
'found in version list',
"found in version list (should you be using option 'version-type': 'strict'?)",
)
}
return elixirVersionWithOTP
return `v${elixirVersionWithOTP}`
}
async function getRebar3Version(r3Spec) {
@@ -4836,7 +4838,8 @@ async function getRebar3Version(r3Spec) {
const rebar3Version = getVersionFromSpec(r3Spec, rebar3Versions)
if (rebar3Version === null) {
throw new Error(
`Requested rebar3 version (${r3Spec}) not found in version list`,
`Requested rebar3 version (${r3Spec}) not found in version list ` +
"(should you be using option 'version-type': 'strict'?)",
)
}
@@ -4896,7 +4899,7 @@ async function getElixirVersions() {
.split('\n')
.forEach((line) => {
const elixirMatch =
line.match(/^(.+)-otp-([^ ]+)/) || line.match(/^([^ ]+)/)
line.match(/^v?(.+)-otp-([^ ]+)/) || line.match(/^v?([^ ]+)/)
const elixirVersion = elixirMatch[1]
const otpVersion = elixirMatch[2]
const otpVersions = otpVersionsForElixirMap.get(elixirVersion) || []
@@ -4928,18 +4931,19 @@ async function getRebar3Versions() {
function getVersionFromSpec(spec, versions) {
let version = null
if (core.getInput('version-type', { required: false }) === 'strict') {
if (
spec.match(/rc/) ||
core.getInput('version-type', { required: false }) === 'strict'
) {
version = spec
}
if (version === null) {
// We keep a map of semver => "spec" in order to use semver ranges to find appropriate versions
const versionsMap = versions.sort(sortVersions).reduce((acc, v) => {
try {
acc[semver.coerce(v).version] = v
} catch {
// some stuff can't be coerced, like 'master'
acc[v] = v
if (!v.match(/rc/)) {
// release candidates are opt-in
acc[maybeCoerced(v)] = v
}
return acc
}, {})
@@ -4948,13 +4952,26 @@ function getVersionFromSpec(spec, versions) {
version =
versionsMap[semver.maxSatisfying(Object.keys(versionsMap), rangeForMax)]
} else {
version = versionsMap[spec]
version = versionsMap[maybeCoerced(spec)]
}
}
return version
}
function maybeCoerced(v) {
let ret
try {
ret = semver.coerce(v).version
} catch {
// some stuff can't be coerced, like 'master'
ret = v
}
return ret
}
function sortVersions(left, right) {
let ret = 0
const newL = verAsComparableStr(left)
+31 -14
View File
@@ -121,7 +121,8 @@ async function getOTPVersion(otpSpec0, osVersion) {
}
if (otpVersion === null) {
throw new Error(
`Requested Erlang/OTP version (${otpSpec0}) not found in version list`,
`Requested Erlang/OTP version (${otpSpec0}) not found in version list ` +
"(should you be using option 'version-type': 'strict'?)",
)
}
@@ -132,7 +133,7 @@ async function getElixirVersion(exSpec0, otpVersion) {
const elixirVersions = await getElixirVersions()
const semverVersions = Array.from(elixirVersions.keys()).sort()
const exSpec = exSpec0.match(/^(.+)(-otp-.+)/) || exSpec0.match(/^(.+)/)
const exSpec = exSpec0.match(/^v?(.+)(-otp-.+)/) || exSpec0.match(/^v?(.+)/)
let elixirVersion
if (exSpec[2]) {
throw new Error(
@@ -145,7 +146,8 @@ async function getElixirVersion(exSpec0, otpVersion) {
}
if (!exSpec || elixirVersion === null) {
throw new Error(
`Requested Elixir version (${exSpec0}) not found in version list`,
`Requested Elixir version (${exSpec0}) not found in version list ` +
"(should you be using option 'version-type': 'strict'?)",
)
}
const otpMatch = otpVersion.match(/^(?:OTP-)?([^.]+)/)
@@ -168,11 +170,11 @@ async function getElixirVersion(exSpec0, otpVersion) {
} else {
throw new Error(
`Requested Elixir / Erlang/OTP version (${exSpec0} / ${otpVersion}) not ` +
'found in version list',
"found in version list (should you be using option 'version-type': 'strict'?)",
)
}
return elixirVersionWithOTP
return `v${elixirVersionWithOTP}`
}
async function getRebar3Version(r3Spec) {
@@ -180,7 +182,8 @@ async function getRebar3Version(r3Spec) {
const rebar3Version = getVersionFromSpec(r3Spec, rebar3Versions)
if (rebar3Version === null) {
throw new Error(
`Requested rebar3 version (${r3Spec}) not found in version list`,
`Requested rebar3 version (${r3Spec}) not found in version list ` +
"(should you be using option 'version-type': 'strict'?)",
)
}
@@ -240,7 +243,7 @@ async function getElixirVersions() {
.split('\n')
.forEach((line) => {
const elixirMatch =
line.match(/^(.+)-otp-([^ ]+)/) || line.match(/^([^ ]+)/)
line.match(/^v?(.+)-otp-([^ ]+)/) || line.match(/^v?([^ ]+)/)
const elixirVersion = elixirMatch[1]
const otpVersion = elixirMatch[2]
const otpVersions = otpVersionsForElixirMap.get(elixirVersion) || []
@@ -272,18 +275,19 @@ async function getRebar3Versions() {
function getVersionFromSpec(spec, versions) {
let version = null
if (core.getInput('version-type', { required: false }) === 'strict') {
if (
spec.match(/rc/) ||
core.getInput('version-type', { required: false }) === 'strict'
) {
version = spec
}
if (version === null) {
// We keep a map of semver => "spec" in order to use semver ranges to find appropriate versions
const versionsMap = versions.sort(sortVersions).reduce((acc, v) => {
try {
acc[semver.coerce(v).version] = v
} catch {
// some stuff can't be coerced, like 'master'
acc[v] = v
if (!v.match(/rc/)) {
// release candidates are opt-in
acc[maybeCoerced(v)] = v
}
return acc
}, {})
@@ -292,13 +296,26 @@ function getVersionFromSpec(spec, versions) {
version =
versionsMap[semver.maxSatisfying(Object.keys(versionsMap), rangeForMax)]
} else {
version = versionsMap[spec]
version = versionsMap[maybeCoerced(spec)]
}
}
return version
}
function maybeCoerced(v) {
let ret
try {
ret = semver.coerce(v).version
} catch {
// some stuff can't be coerced, like 'master'
ret = v
}
return ret
}
function sortVersions(left, right) {
let ret = 0
const newL = verAsComparableStr(left)