Compare commits

...

3 Commits

Author SHA1 Message Date
Bryan Paxton ade4f1d567 Don't preprend v when elixir version does not start with digits (#61) 2021-07-20 14:08:24 -05:00
Paulo F. Oliveira 9283f857f1 Improve warning message for missing ImageOS env. variable (self-hosted runners) (#59) 2021-07-12 18:35:08 +01:00
Paulo F. Oliveira 830642517c Improve visibility (+ fix bugs) over version-type and opt-in versions (#57)
(and tweak README regarding action versioning)
2021-07-09 10:11:50 +01:00
6 changed files with 200 additions and 55 deletions
+16 -4
View File
@@ -17,7 +17,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: '12'
node-version: 12
- run: npm install -g npm
- run: npm install
- run: npm run build
@@ -31,12 +31,24 @@ jobs:
- name: Check if build left artifacts
run: git diff --exit-code
unit_test:
name: Unit tests
unit_tests_ubuntu:
name: Unit tests (Ubuntu)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with: {node-version: '12'}
with:
node-version: 12
- run: npm ci
- run: npm test
unit_tests_windows:
name: Unit tests (Windows)
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12
- run: npm install --production
- run: npm test
+15
View File
@@ -92,6 +92,20 @@ 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'
- elixir-version: 'master'
otp-version: '23.1'
os: 'ubuntu-20.04'
steps:
- uses: actions/checkout@v2
- name: Use erlef/setup-beam
@@ -101,6 +115,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)
+44 -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
@@ -53,6 +53,35 @@ and Erlang/OTP.
**Note** *: prior to 23, Windows builds are only available for minor versions, e.g. 21.0, 21.3, 22.0, etc.
### Self-hosted runners
Self-hosted runners need to set env. variable `ImageOS` to one of the following, since the action
uses that to download assets:
| ImageOS | Operating system
|- |-
| ubuntu16 | ubuntu-16.04
| ubuntu18 | ubuntu-18.04
| ubuntu20 | ubuntu-20.04
| win16 | windows-2016
| win19 | windows-2019
as per the following example:
```yaml
...
jobs:
test:
runs-on: self-hosted
env:
ImageOS: ubuntu20 # equivalent to runs-on ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: erlef/setup-beam@v1
...
```
### Basic example (Erlang/OTP + Elixir, on Ubuntu)
```yaml
@@ -159,6 +188,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).
+33 -18
View File
@@ -136,7 +136,7 @@ async function testOTPVersions() {
spec = '23.2.x'
osVersion = 'windows-2016'
expected = '23.2.7.4'
expected = '23.2.7'
got = await setupBeam.getOTPVersion(spec, osVersion)
assert.deepStrictEqual(got, expected)
@@ -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,22 @@ 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')
simulateInput('version-type', 'strict')
spec = 'master'
otpVersion = '23.1'
expected = 'master-otp-23'
got = await setupBeam.getElixirVersion(spec, otpVersion)
assert.deepStrictEqual(got, expected)
simulateInput('version-type', 'loose')
}
async function testRebar3Versions() {
@@ -228,6 +250,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 +309,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 +346,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) {
+46 -15
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,14 @@ 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
const DigitStart = new RegExp('^\\d+')
return DigitStart.test(elixirVersion)
? `v${elixirVersionWithOTP}`
: elixirVersionWithOTP
}
async function getRebar3Version(r3Spec) {
@@ -4836,7 +4841,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 +4902,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 +4934,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 +4955,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)
@@ -4984,8 +5004,19 @@ function getRunnerOSVersion() {
win16: 'windows-2016',
win19: 'windows-2019',
}
const containerFromEnvImageOS = ImageOSToContainer[process.env.ImageOS]
return ImageOSToContainer[process.env.ImageOS]
if (!containerFromEnvImageOS) {
throw new Error(
"Tried to map a target OS from env. variable 'ImageOS', but failed. If you're using a " +
"self-hosted runner, you should set 'env': 'ImageOS': ... to one of the following: " +
"['" +
`${Object.keys(ImageOSToContainer).join("', '")}` +
"']",
)
}
return containerFromEnvImageOS
}
async function get(url0, pageIdxs) {
+46 -15
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,14 @@ 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
const DigitStart = new RegExp('^\\d+')
return DigitStart.test(elixirVersion)
? `v${elixirVersionWithOTP}`
: elixirVersionWithOTP
}
async function getRebar3Version(r3Spec) {
@@ -180,7 +185,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 +246,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 +278,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 +299,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)
@@ -328,8 +348,19 @@ function getRunnerOSVersion() {
win16: 'windows-2016',
win19: 'windows-2019',
}
const containerFromEnvImageOS = ImageOSToContainer[process.env.ImageOS]
return ImageOSToContainer[process.env.ImageOS]
if (!containerFromEnvImageOS) {
throw new Error(
"Tried to map a target OS from env. variable 'ImageOS', but failed. If you're using a " +
"self-hosted runner, you should set 'env': 'ImageOS': ... to one of the following: " +
"['" +
`${Object.keys(ImageOSToContainer).join("', '")}` +
"']",
)
}
return containerFromEnvImageOS
}
async function get(url0, pageIdxs) {