Skip to content

Commit

Permalink
Improve visibility (+ fix bugs) over version-type and opt-in versions (
Browse files Browse the repository at this point in the history
…#57)

(and tweak README regarding action versioning)
  • Loading branch information
paulo-ferraz-oliveira authored Jul 9, 2021
1 parent d8a37f5 commit 8306425
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 48 deletions.
12 changes: 12 additions & 0 deletions .github/workflows/ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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).
Expand Down
41 changes: 24 additions & 17 deletions __tests__/setup-beam.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,13 +166,27 @@ 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'
expected = 'v1.11.0-rc.0-otp-23'
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() {
Expand Down Expand Up @@ -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'
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand Down
45 changes: 31 additions & 14 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'?)",
)
}

Expand All @@ -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(
Expand All @@ -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-)?([^.]+)/)
Expand All @@ -4824,19 +4826,20 @@ 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) {
const rebar3Versions = await getRebar3Versions()
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'?)",
)
}

Expand Down Expand Up @@ -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) || []
Expand Down Expand Up @@ -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
}, {})
Expand All @@ -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)
Expand Down
45 changes: 31 additions & 14 deletions src/setup-beam.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'?)",
)
}

Expand All @@ -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(
Expand All @@ -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-)?([^.]+)/)
Expand All @@ -168,19 +170,20 @@ 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) {
const rebar3Versions = await getRebar3Versions()
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'?)",
)
}

Expand Down Expand Up @@ -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) || []
Expand Down Expand Up @@ -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
}, {})
Expand All @@ -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)
Expand Down

0 comments on commit 8306425

Please sign in to comment.