New option to work with one or more hex.pm mirrors (#197)

* New option to work with one or more hex.pm mirrors

Add a new option called `hexpm-mirrors` for one or more hex.pm mirrors.
Default list is `builds.hex.pm`, so behavior is unaffected unless option is
used.

Signed-off-by: Paul Guyot <pguyot@kallisys.net>

* Implement suggested rewording changes from @paulo-ferraz-oliveira

Co-authored-by: Paulo F. Oliveira <paulo.ferraz.oliveira@gmail.com>
Signed-off-by: Paul Guyot <pguyot@kallisys.net>

---------

Signed-off-by: Paul Guyot <pguyot@kallisys.net>
Co-authored-by: Paulo F. Oliveira <paulo.ferraz.oliveira@gmail.com>
This commit is contained in:
Paul Guyot
2023-05-04 08:27:05 +02:00
committed by GitHub
parent 9641cb96c1
commit cf692c3264
13 changed files with 362 additions and 99 deletions
+58
View File
@@ -0,0 +1,58 @@
---
name: hexpm-mirrors
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
test-failing-first-mirror:
name: Test option hexpm-mirrors with a dummy first mirror
runs-on: ${{matrix.os}}
strategy:
fail-fast: false
matrix:
os: ['ubuntu-22.04', 'windows-2022']
otp-version: ['24']
elixir-version: ['v1.14', '']
install-rebar: [true, false]
install-hex: [true, false]
steps:
- uses: actions/checkout@v3
- name: Use erlef/setup-beam
id: setup-beam
uses: ./
with:
otp-version: ${{matrix.otp-version}}
elixir-version: ${{matrix.elixir-version}}
install-rebar: ${{matrix.install-rebar}}
install-hex: ${{matrix.install-hex}}
hexpm-mirrors: |
https://mirror.invalid
https://cdn.jsdelivr.net/hex
https://builds.hex.pm
test-invalid-mirror:
name: Test errors with mirror
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: Use erlef/setup-beam
id: failing-setup-beam
uses: ./
continue-on-error: true
with:
otp-version: '24.3.4.6'
elixir-version: 'v1.13.4'
install-rebar: true
install-hex: true
hexpm-mirrors: https://mirror.invalid
- name: Report unexpected success
if: ${{ steps.failing-setup-beam.outcome == 'success' }}
run: |
echo "Action is expected to fail"
exit 1
+41
View File
@@ -216,6 +216,47 @@ jobs:
**Note**: the `otp-version: false` input is only applicable when installing Gleam. **Note**: the `otp-version: false` input is only applicable when installing Gleam.
## Alternative hex.pm mirrors
It is possible to use alternative hex.pm mirror(s), in their declared order, with
option `hexpm-mirrors`. By default, the action will use `builds.hex.pm`.
To use other alternative mirrors, add one per line, as shown below.
```yaml
# create this in .github/workflows/ci.yml
on: push
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: erlef/setup-beam@v1
with:
otp-version: '25'
# Use `cdn.jsdelivr.net/hex` as an alternative to `builds.hex.pm`
hexpm-mirrors: https://cdn.jsdelivr.net/hex
```
Alternatively, you may try `cdn.jsdelivr.net/hex` if `builds.hex.pm` fails:
```yaml
# create this in .github/workflows/ci.yml
on: push
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: erlef/setup-beam@v1
with:
otp-version: '25'
hexpm-mirrors: |
https://builds.hex.pm
https://cdn.jsdelivr.net/hex
```
## Environment variables ## Environment variables
Base installation folders (useful for e.g. fetching headers for NIFs) are available in the following Base installation folders (useful for e.g. fetching headers for NIFs) are available in the following
+19 -17
View File
@@ -102,48 +102,49 @@ async function testOTPVersions() {
let expected let expected
let spec let spec
let osVersion let osVersion
const hexMirrors = ['https://repo.hex.pm', 'https://cdn.jsdelivr.net/hex']
if (process.platform === 'linux') { if (process.platform === 'linux') {
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'
got = await setupBeam.getOTPVersion(spec, osVersion) got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
spec = '^19.3.6' spec = '^19.3.6'
osVersion = 'ubuntu-16.04' osVersion = 'ubuntu-16.04'
expected = 'OTP-19.3.6.13' expected = 'OTP-19.3.6.13'
got = await setupBeam.getOTPVersion(spec, osVersion) got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
spec = '^19.3' spec = '^19.3'
osVersion = 'ubuntu-18.04' osVersion = 'ubuntu-18.04'
expected = 'OTP-19.3.6.13' expected = 'OTP-19.3.6.13'
got = await setupBeam.getOTPVersion(spec, osVersion) got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
spec = '20' spec = '20'
osVersion = 'ubuntu-20.04' osVersion = 'ubuntu-20.04'
expected = 'OTP-20.3.8.26' expected = 'OTP-20.3.8.26'
got = await setupBeam.getOTPVersion(spec, osVersion) got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
assert.deepStrictEqual(got, expected) 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'
got = await setupBeam.getOTPVersion(spec, osVersion) got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
spec = '20.0' spec = '20.0'
osVersion = 'ubuntu-20.04' osVersion = 'ubuntu-20.04'
expected = 'OTP-20.0.5' expected = 'OTP-20.0.5'
got = await setupBeam.getOTPVersion(spec, osVersion) got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
spec = '20.0.x' spec = '20.0.x'
osVersion = 'ubuntu-20.04' osVersion = 'ubuntu-20.04'
expected = 'OTP-20.0.5' expected = 'OTP-20.0.5'
got = await setupBeam.getOTPVersion(spec, osVersion) got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
} }
@@ -151,19 +152,19 @@ async function testOTPVersions() {
spec = '24.0.1' spec = '24.0.1'
osVersion = 'windows-latest' osVersion = 'windows-latest'
expected = '24.0.1' expected = '24.0.1'
got = await setupBeam.getOTPVersion(spec, osVersion) got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
spec = '23.2.x' spec = '23.2.x'
osVersion = 'windows-2016' osVersion = 'windows-2016'
expected = '23.2.7' expected = '23.2.7'
got = await setupBeam.getOTPVersion(spec, osVersion) got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
spec = '23.0' spec = '23.0'
osVersion = 'windows-2019' osVersion = 'windows-2019'
expected = '23.0.4' expected = '23.0.4'
got = await setupBeam.getOTPVersion(spec, osVersion) got = await setupBeam.getOTPVersion(spec, osVersion, hexMirrors)
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
} }
} }
@@ -173,30 +174,31 @@ async function testElixirVersions() {
let expected let expected
let spec let spec
let otpVersion let otpVersion
const hexMirrors = ['https://repo.hex.pm']
spec = '1.1.x' spec = '1.1.x'
otpVersion = 'OTP-17' otpVersion = 'OTP-17'
expected = 'v1.1.1-otp-17' expected = 'v1.1.1-otp-17'
got = await setupBeam.getElixirVersion(spec, otpVersion) got = await setupBeam.getElixirVersion(spec, otpVersion, hexMirrors)
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
spec = '1.10.4' spec = '1.10.4'
otpVersion = 'OTP-23' otpVersion = 'OTP-23'
expected = 'v1.10.4-otp-23' expected = 'v1.10.4-otp-23'
got = await setupBeam.getElixirVersion(spec, otpVersion) got = await setupBeam.getElixirVersion(spec, otpVersion, hexMirrors)
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
spec = '1.12.1' spec = '1.12.1'
otpVersion = 'OTP-24.0.2' otpVersion = 'OTP-24.0.2'
expected = 'v1.12.1-otp-24' expected = 'v1.12.1-otp-24'
got = await setupBeam.getElixirVersion(spec, otpVersion) got = await setupBeam.getElixirVersion(spec, otpVersion, hexMirrors)
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
simulateInput('version-type', 'strict') simulateInput('version-type', 'strict')
spec = '1.14.0' spec = '1.14.0'
otpVersion = 'master' otpVersion = 'master'
expected = 'v1.14.0' expected = 'v1.14.0'
got = await setupBeam.getElixirVersion(spec, otpVersion) got = await setupBeam.getElixirVersion(spec, otpVersion, hexMirrors)
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
simulateInput('version-type', 'loose') simulateInput('version-type', 'loose')
@@ -204,7 +206,7 @@ async function testElixirVersions() {
spec = 'v1.11.0-rc.0' spec = 'v1.11.0-rc.0'
otpVersion = 'OTP-23' otpVersion = 'OTP-23'
expected = 'v1.11.0-rc.0-otp-23' expected = 'v1.11.0-rc.0-otp-23'
got = await setupBeam.getElixirVersion(spec, otpVersion) got = await setupBeam.getElixirVersion(spec, otpVersion, hexMirrors)
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
simulateInput('version-type', 'loose') simulateInput('version-type', 'loose')
@@ -212,7 +214,7 @@ async function testElixirVersions() {
spec = 'v1.11.0' spec = 'v1.11.0'
otpVersion = '22.3.4.2' otpVersion = '22.3.4.2'
expected = 'v1.11.0-otp-22' expected = 'v1.11.0-otp-22'
got = await setupBeam.getElixirVersion(spec, otpVersion) got = await setupBeam.getElixirVersion(spec, otpVersion, hexMirrors)
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
simulateInput('version-type', 'loose') simulateInput('version-type', 'loose')
@@ -220,7 +222,7 @@ async function testElixirVersions() {
spec = 'main' spec = 'main'
otpVersion = '23.1' otpVersion = '23.1'
expected = 'main-otp-23' expected = 'main-otp-23'
got = await setupBeam.getElixirVersion(spec, otpVersion) got = await setupBeam.getElixirVersion(spec, otpVersion, hexMirrors)
assert.deepStrictEqual(got, expected) assert.deepStrictEqual(got, expected)
simulateInput('version-type', 'loose') simulateInput('version-type', 'loose')
} }
+4
View File
@@ -45,6 +45,10 @@ inputs:
version-file: version-file:
description: a versions file (e.g. as used by `asdf`), which defines inputs description: a versions file (e.g. as used by `asdf`), which defines inputs
default: '' default: ''
hexpm-mirrors:
description: mirror(s) for hex.pm, one per line
default: |
https://builds.hex.pm
outputs: outputs:
elixir-version: elixir-version:
description: Exact version of Elixir that was installed description: Exact version of Elixir that was installed
+114 -37
View File
@@ -7120,6 +7120,7 @@ try {
/***/ 2127: /***/ 2127:
/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
const core = __nccwpck_require__(2186)
const { exec } = __nccwpck_require__(1514) const { exec } = __nccwpck_require__(1514)
const path = __nccwpck_require__(1017) const path = __nccwpck_require__(1017)
@@ -7128,11 +7129,28 @@ const path = __nccwpck_require__(1017)
* *
* @param {string} osVersion * @param {string} osVersion
* @param {string} otpVersion * @param {string} otpVersion
* @param {string[]} hexMirrors
*/ */
async function installOTP(osVersion, otpVersion) { async function installOTP(osVersion, otpVersion, hexMirrors) {
const OS = process.platform const OS = process.platform
if (OS === 'linux') { if (OS === 'linux') {
await exec(__nccwpck_require__.ab + "install-otp.sh", [osVersion, otpVersion]) if (hexMirrors.length === 0) {
throw new Error(
`Could not install Erlang/OTP ${otpVersion} from any hex.pm mirror`,
)
}
const [hexMirror, ...hexMirrorsT] = hexMirrors
try {
await exec(__nccwpck_require__.ab + "install-otp.sh", [
osVersion,
otpVersion,
hexMirror,
])
return
} catch (err) {
core.info(`install-otp.sh failed for mirror ${hexMirror}`)
}
await installOTP(osVersion, otpVersion, hexMirrorsT)
} else if (OS === 'win32') { } else if (OS === 'win32') {
const script = __nccwpck_require__.ab + "install-otp.ps1" const script = __nccwpck_require__.ab + "install-otp.ps1"
await exec(`pwsh.exe ${script} -VSN:${otpVersion}`) await exec(`pwsh.exe ${script} -VSN:${otpVersion}`)
@@ -7143,15 +7161,34 @@ async function installOTP(osVersion, otpVersion) {
* Install Elixir. * Install Elixir.
* *
* @param {string} elixirVersion * @param {string} elixirVersion
* @param {string[]} hexMirrors
*/ */
async function installElixir(elixirVersion) { async function installElixir(elixirVersion, hexMirrors) {
const OS = process.platform if (hexMirrors.length === 0) {
if (OS === 'linux') { throw new Error(
await exec(__nccwpck_require__.ab + "install-elixir.sh", [elixirVersion]) `Could not install Elixir ${elixirVersion} from any hex.pm mirror`,
} else if (OS === 'win32') { )
const script = __nccwpck_require__.ab + "install-elixir.ps1"
await exec(`pwsh.exe ${script} -VSN:${elixirVersion}`)
} }
const [hexMirror, ...hexMirrorsT] = hexMirrors
const OS = process.platform
let script
try {
if (OS === 'linux') {
script = __nccwpck_require__.ab + "install-elixir.sh"
await exec(__nccwpck_require__.ab + "install-elixir.sh", [elixirVersion, hexMirror])
return
}
if (OS === 'win32') {
script = __nccwpck_require__.ab + "install-elixir.ps1"
await exec(
`pwsh.exe ${script} -VSN:${elixirVersion} -HEX_MIRROR:${hexMirror}`,
)
return
}
} catch (err) {
core.info(`${script} failed for mirror ${hexMirror}`)
}
await installElixir(elixirVersion, hexMirrorsT)
} }
/** /**
@@ -7238,16 +7275,23 @@ async function main() {
const elixirSpec = getInput('elixir-version', false, 'elixir', versions) const elixirSpec = getInput('elixir-version', false, 'elixir', versions)
const gleamSpec = getInput('gleam-version', false, 'gleam', versions) const gleamSpec = getInput('gleam-version', false, 'gleam', versions)
const rebar3Spec = getInput('rebar3-version', false, 'rebar', versions) const rebar3Spec = getInput('rebar3-version', false, 'rebar', versions)
const hexMirrors = core.getMultilineInput('hexpm-mirrors', {
required: false,
})
if (otpSpec !== 'false') { if (otpSpec !== 'false') {
await installOTP(otpSpec, osVersion) await installOTP(otpSpec, osVersion, hexMirrors)
const elixirInstalled = await maybeInstallElixir(elixirSpec, otpSpec) const elixirInstalled = await maybeInstallElixir(
elixirSpec,
otpSpec,
hexMirrors,
)
if (elixirInstalled === true) { if (elixirInstalled === true) {
const shouldMixRebar = getInput('install-rebar', false) const shouldMixRebar = getInput('install-rebar', false)
await mix(shouldMixRebar, 'rebar') await mix(shouldMixRebar, 'rebar', hexMirrors)
const shouldMixHex = getInput('install-hex', false) const shouldMixHex = getInput('install-hex', false)
await mix(shouldMixHex, 'hex') await mix(shouldMixHex, 'hex', hexMirrors)
} }
} else if (!gleamSpec) { } else if (!gleamSpec) {
throw new Error('otp-version=false is only available when installing Gleam') throw new Error('otp-version=false is only available when installing Gleam')
@@ -7257,12 +7301,12 @@ async function main() {
await maybeInstallRebar3(rebar3Spec) await maybeInstallRebar3(rebar3Spec)
} }
async function installOTP(otpSpec, osVersion) { async function installOTP(otpSpec, osVersion, hexMirrors) {
const otpVersion = await getOTPVersion(otpSpec, osVersion) const otpVersion = await getOTPVersion(otpSpec, osVersion, hexMirrors)
console.log( console.log(
`##[group]Installing Erlang/OTP ${otpVersion} - built on ${osVersion}`, `##[group]Installing Erlang/OTP ${otpVersion} - built on ${osVersion}`,
) )
await installer.installOTP(osVersion, otpVersion) await installer.installOTP(osVersion, otpVersion, hexMirrors)
core.setOutput('otp-version', otpVersion) core.setOutput('otp-version', otpVersion)
core.addPath(`${process.env.RUNNER_TEMP}/.setup-beam/otp/bin`) core.addPath(`${process.env.RUNNER_TEMP}/.setup-beam/otp/bin`)
console.log('##[endgroup]') console.log('##[endgroup]')
@@ -7270,13 +7314,17 @@ async function installOTP(otpSpec, osVersion) {
return otpVersion return otpVersion
} }
async function maybeInstallElixir(elixirSpec, otpVersion) { async function maybeInstallElixir(elixirSpec, otpSpec, hexMirrors) {
let installed = false let installed = false
if (elixirSpec) { if (elixirSpec) {
const elixirVersion = await getElixirVersion(elixirSpec, otpVersion) const elixirVersion = await getElixirVersion(
elixirSpec,
otpSpec,
hexMirrors,
)
console.log(`##[group]Installing Elixir ${elixirVersion}`) console.log(`##[group]Installing Elixir ${elixirVersion}`)
await installer.installElixir(elixirVersion) 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') {
@@ -7295,12 +7343,28 @@ async function maybeInstallElixir(elixirSpec, otpVersion) {
return installed return installed
} }
async function mix(shouldMix, what) { async function mixWithMirrors(cmd, args, hexMirrors) {
if (hexMirrors.length === 0) {
throw new Error('mix failed with every mirror')
}
const [hexMirror, ...hexMirrorsT] = hexMirrors
process.env.HEX_MIRROR = hexMirror
try {
return await exec(cmd, args)
} catch (err) {
core.info(
`mix failed with mirror ${process.env.HEX_MIRROR} with message ${err.message})`,
)
}
return mixWithMirrors(cmd, args, hexMirrorsT)
}
async function mix(shouldMix, what, hexMirrors) {
if (shouldMix === 'true') { if (shouldMix === 'true') {
const cmd = 'mix' const cmd = 'mix'
const args = [`local.${what}`, '--force'] const args = [`local.${what}`, '--force']
console.log(`##[group]Running ${cmd} ${args}`) console.log(`##[group]Running ${cmd} ${args}`)
await exec(cmd, args) await mixWithMirrors(cmd, args, hexMirrors)
console.log('##[endgroup]') console.log('##[endgroup]')
} }
} }
@@ -7344,8 +7408,8 @@ async function maybeInstallRebar3(rebar3Spec) {
return installed return installed
} }
async function getOTPVersion(otpSpec0, osVersion) { async function getOTPVersion(otpSpec0, osVersion, hexMirrors) {
const otpVersions = await getOTPVersions(osVersion) const otpVersions = await getOTPVersions(osVersion, hexMirrors)
let otpSpec = otpSpec0 // might be a branch (?) let otpSpec = otpSpec0 // might be a branch (?)
const otpVersion = getVersionFromSpec( const otpVersion = getVersionFromSpec(
otpSpec, otpSpec,
@@ -7364,10 +7428,10 @@ async function getOTPVersion(otpSpec0, osVersion) {
return otpVersions.get(otpVersion) // from the reference, for download return otpVersions.get(otpVersion) // from the reference, for download
} }
async function getElixirVersion(exSpec0, otpVersion0) { 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() const elixirVersions = await getElixirVersions(hexMirrors)
const semverVersions = Array.from(elixirVersions.keys()).sort() const semverVersions = Array.from(elixirVersions.keys()).sort()
const exSpec = exSpec0.replace(/-otp-.*$/, '') const exSpec = exSpec0.replace(/-otp-.*$/, '')
const elixirVersionFromSpec = getVersionFromSpec(exSpec, semverVersions, true) const elixirVersionFromSpec = getVersionFromSpec(exSpec, semverVersions, true)
@@ -7427,19 +7491,19 @@ async function getRebar3Version(r3Spec) {
return rebar3Version return rebar3Version
} }
async function getOTPVersions(osVersion) { async function getOTPVersions(osVersion, hexMirrors) {
let originListing let otpVersionsListings
let pageIdxs
if (process.platform === 'linux') { if (process.platform === 'linux') {
originListing = `https://builds.hex.pm/builds/otp/${osVersion}/builds.txt` otpVersionsListings = await getWithMirrors(
pageIdxs = [null] `/builds/otp/${osVersion}/builds.txt`,
hexMirrors,
)
} else if (process.platform === 'win32') { } else if (process.platform === 'win32') {
originListing = const originListing =
'https://api.github.com/repos/erlang/otp/releases?per_page=100' 'https://api.github.com/repos/erlang/otp/releases?per_page=100'
pageIdxs = [1, 2, 3] otpVersionsListings = await get(originListing, [1, 2, 3])
} }
const otpVersionsListings = await get(originListing, pageIdxs)
const otpVersions = new Map() const otpVersions = new Map()
if (process.platform === 'linux') { if (process.platform === 'linux') {
@@ -7469,10 +7533,10 @@ async function getOTPVersions(osVersion) {
return otpVersions return otpVersions
} }
async function getElixirVersions() { async function getElixirVersions(hexMirrors) {
const elixirVersionsListings = await get( const elixirVersionsListings = await getWithMirrors(
'https://builds.hex.pm/builds/elixir/builds.txt', '/builds/elixir/builds.txt',
[null], hexMirrors,
) )
const otpVersionsForElixirMap = new Map() const otpVersionsForElixirMap = new Map()
@@ -7656,6 +7720,19 @@ async function get(url0, pageIdxs) {
return Promise.all(pageIdxs.map(getPage)) return Promise.all(pageIdxs.map(getPage))
} }
async function getWithMirrors(resourcePath, hexMirrors) {
if (hexMirrors.length === 0) {
throw new Error(`Could not fetch ${resourcePath} from any hex.pm mirror`)
}
const [hexMirror, ...hexMirrorsT] = hexMirrors
try {
return await get(`${hexMirror}${resourcePath}`, [null])
} catch (err) {
core.info(`get failed for URL ${hexMirror}${resourcePath}`)
}
return getWithMirrors(resourcePath, hexMirrorsT)
}
function maybePrependWithV(v) { function maybePrependWithV(v) {
if (isVersion(v)) { if (isVersion(v)) {
return `v${v.replace('v', '')}` return `v${v.replace('v', '')}`
+2 -2
View File
@@ -1,4 +1,4 @@
param([Parameter(Mandatory=$true)][string]${VSN}) param([Parameter(Mandatory=$true)][string]${VSN}, [Parameter(Mandatory=$true)][string]${HEX_MIRROR})
$ErrorActionPreference="Stop" $ErrorActionPreference="Stop"
@@ -9,7 +9,7 @@ $FILE_OUTPUT="elixir.zip"
$DIR_FOR_BIN=".setup-beam/elixir" $DIR_FOR_BIN=".setup-beam/elixir"
$ProgressPreference="SilentlyContinue" $ProgressPreference="SilentlyContinue"
Invoke-WebRequest "https://builds.hex.pm/builds/elixir/${FILE_INPUT}" -OutFile "${FILE_OUTPUT}" Invoke-WebRequest "${HEX_MIRROR}/builds/elixir/${FILE_INPUT}" -OutFile "${FILE_OUTPUT}"
$ProgressPreference="Continue" $ProgressPreference="Continue"
New-Item "${DIR_FOR_BIN}" -ItemType Directory | Out-Null New-Item "${DIR_FOR_BIN}" -ItemType Directory | Out-Null
$ProgressPreference="SilentlyContinue" $ProgressPreference="SilentlyContinue"
+2 -1
View File
@@ -5,11 +5,12 @@ set -eo pipefail
cd "${RUNNER_TEMP}" cd "${RUNNER_TEMP}"
VSN=${1} VSN=${1}
HEX_MIRROR=${2}
FILE_INPUT="${VSN}.zip" FILE_INPUT="${VSN}.zip"
FILE_OUTPUT=elixir.zip FILE_OUTPUT=elixir.zip
DIR_FOR_BIN=.setup-beam/elixir DIR_FOR_BIN=.setup-beam/elixir
wget -q -O "${FILE_OUTPUT}" "https://builds.hex.pm/builds/elixir/${FILE_INPUT}" wget -q -O "${FILE_OUTPUT}" "${HEX_MIRROR}/builds/elixir/${FILE_INPUT}"
mkdir -p "${DIR_FOR_BIN}" mkdir -p "${DIR_FOR_BIN}"
unzip -q -o -d "${DIR_FOR_BIN}" "${FILE_OUTPUT}" unzip -q -o -d "${DIR_FOR_BIN}" "${FILE_OUTPUT}"
echo "Installed Elixir version follows" echo "Installed Elixir version follows"
+2 -1
View File
@@ -6,11 +6,12 @@ cd "${RUNNER_TEMP}"
OS=${1} OS=${1}
VSN=${2} VSN=${2}
HEX_MIRROR=${3}
FILE_INPUT="${VSN}.tar.gz" FILE_INPUT="${VSN}.tar.gz"
FILE_OUTPUT=otp.tar.gz FILE_OUTPUT=otp.tar.gz
DIR_FOR_BIN=.setup-beam/otp DIR_FOR_BIN=.setup-beam/otp
wget -q -O "${FILE_OUTPUT}" "https://builds.hex.pm/builds/otp/${OS}/${FILE_INPUT}" wget -q -O "${FILE_OUTPUT}" "${HEX_MIRROR}/builds/otp/${OS}/${FILE_INPUT}"
mkdir -p "${DIR_FOR_BIN}" mkdir -p "${DIR_FOR_BIN}"
tar zxf "${FILE_OUTPUT}" -C "${DIR_FOR_BIN}" --strip-components=1 tar zxf "${FILE_OUTPUT}" -C "${DIR_FOR_BIN}" --strip-components=1
"${DIR_FOR_BIN}/Install" -minimal "$(pwd)/${DIR_FOR_BIN}" "${DIR_FOR_BIN}/Install" -minimal "$(pwd)/${DIR_FOR_BIN}"
+2 -2
View File
@@ -1,4 +1,4 @@
param([Parameter(Mandatory=$true)][string]${VSN}) param([Parameter(Mandatory=$true)][string]${VSN}, [Parameter(Mandatory=$true)][string]${HEX_MIRROR})
$ErrorActionPreference="Stop" $ErrorActionPreference="Stop"
@@ -9,7 +9,7 @@ $FILE_OUTPUT="elixir.zip"
$DIR_FOR_BIN=".setup-beam/elixir" $DIR_FOR_BIN=".setup-beam/elixir"
$ProgressPreference="SilentlyContinue" $ProgressPreference="SilentlyContinue"
Invoke-WebRequest "https://builds.hex.pm/builds/elixir/${FILE_INPUT}" -OutFile "${FILE_OUTPUT}" Invoke-WebRequest "${HEX_MIRROR}/builds/elixir/${FILE_INPUT}" -OutFile "${FILE_OUTPUT}"
$ProgressPreference="Continue" $ProgressPreference="Continue"
New-Item "${DIR_FOR_BIN}" -ItemType Directory | Out-Null New-Item "${DIR_FOR_BIN}" -ItemType Directory | Out-Null
$ProgressPreference="SilentlyContinue" $ProgressPreference="SilentlyContinue"
+2 -1
View File
@@ -5,11 +5,12 @@ set -eo pipefail
cd "${RUNNER_TEMP}" cd "${RUNNER_TEMP}"
VSN=${1} VSN=${1}
HEX_MIRROR=${2}
FILE_INPUT="${VSN}.zip" FILE_INPUT="${VSN}.zip"
FILE_OUTPUT=elixir.zip FILE_OUTPUT=elixir.zip
DIR_FOR_BIN=.setup-beam/elixir DIR_FOR_BIN=.setup-beam/elixir
wget -q -O "${FILE_OUTPUT}" "https://builds.hex.pm/builds/elixir/${FILE_INPUT}" wget -q -O "${FILE_OUTPUT}" "${HEX_MIRROR}/builds/elixir/${FILE_INPUT}"
mkdir -p "${DIR_FOR_BIN}" mkdir -p "${DIR_FOR_BIN}"
unzip -q -o -d "${DIR_FOR_BIN}" "${FILE_OUTPUT}" unzip -q -o -d "${DIR_FOR_BIN}" "${FILE_OUTPUT}"
echo "Installed Elixir version follows" echo "Installed Elixir version follows"
+2 -1
View File
@@ -6,11 +6,12 @@ cd "${RUNNER_TEMP}"
OS=${1} OS=${1}
VSN=${2} VSN=${2}
HEX_MIRROR=${3}
FILE_INPUT="${VSN}.tar.gz" FILE_INPUT="${VSN}.tar.gz"
FILE_OUTPUT=otp.tar.gz FILE_OUTPUT=otp.tar.gz
DIR_FOR_BIN=.setup-beam/otp DIR_FOR_BIN=.setup-beam/otp
wget -q -O "${FILE_OUTPUT}" "https://builds.hex.pm/builds/otp/${OS}/${FILE_INPUT}" wget -q -O "${FILE_OUTPUT}" "${HEX_MIRROR}/builds/otp/${OS}/${FILE_INPUT}"
mkdir -p "${DIR_FOR_BIN}" mkdir -p "${DIR_FOR_BIN}"
tar zxf "${FILE_OUTPUT}" -C "${DIR_FOR_BIN}" --strip-components=1 tar zxf "${FILE_OUTPUT}" -C "${DIR_FOR_BIN}" --strip-components=1
"${DIR_FOR_BIN}/Install" -minimal "$(pwd)/${DIR_FOR_BIN}" "${DIR_FOR_BIN}/Install" -minimal "$(pwd)/${DIR_FOR_BIN}"
+46 -9
View File
@@ -1,3 +1,4 @@
const core = require('@actions/core')
const { exec } = require('@actions/exec') const { exec } = require('@actions/exec')
const path = require('path') const path = require('path')
@@ -6,11 +7,28 @@ const path = require('path')
* *
* @param {string} osVersion * @param {string} osVersion
* @param {string} otpVersion * @param {string} otpVersion
* @param {string[]} hexMirrors
*/ */
async function installOTP(osVersion, otpVersion) { async function installOTP(osVersion, otpVersion, hexMirrors) {
const OS = process.platform const OS = process.platform
if (OS === 'linux') { if (OS === 'linux') {
await exec(path.join(__dirname, 'install-otp.sh'), [osVersion, otpVersion]) if (hexMirrors.length === 0) {
throw new Error(
`Could not install Erlang/OTP ${otpVersion} from any hex.pm mirror`,
)
}
const [hexMirror, ...hexMirrorsT] = hexMirrors
try {
await exec(path.join(__dirname, 'install-otp.sh'), [
osVersion,
otpVersion,
hexMirror,
])
return
} catch (err) {
core.info(`install-otp.sh failed for mirror ${hexMirror}`)
}
await installOTP(osVersion, otpVersion, hexMirrorsT)
} else if (OS === 'win32') { } else if (OS === 'win32') {
const script = path.join(__dirname, 'install-otp.ps1') const script = path.join(__dirname, 'install-otp.ps1')
await exec(`pwsh.exe ${script} -VSN:${otpVersion}`) await exec(`pwsh.exe ${script} -VSN:${otpVersion}`)
@@ -21,15 +39,34 @@ async function installOTP(osVersion, otpVersion) {
* Install Elixir. * Install Elixir.
* *
* @param {string} elixirVersion * @param {string} elixirVersion
* @param {string[]} hexMirrors
*/ */
async function installElixir(elixirVersion) { async function installElixir(elixirVersion, hexMirrors) {
const OS = process.platform if (hexMirrors.length === 0) {
if (OS === 'linux') { throw new Error(
await exec(path.join(__dirname, 'install-elixir.sh'), [elixirVersion]) `Could not install Elixir ${elixirVersion} from any hex.pm mirror`,
} else if (OS === 'win32') { )
const script = path.join(__dirname, 'install-elixir.ps1')
await exec(`pwsh.exe ${script} -VSN:${elixirVersion}`)
} }
const [hexMirror, ...hexMirrorsT] = hexMirrors
const OS = process.platform
let script
try {
if (OS === 'linux') {
script = path.join(__dirname, 'install-elixir.sh')
await exec(script, [elixirVersion, hexMirror])
return
}
if (OS === 'win32') {
script = path.join(__dirname, 'install-elixir.ps1')
await exec(
`pwsh.exe ${script} -VSN:${elixirVersion} -HEX_MIRROR:${hexMirror}`,
)
return
}
} catch (err) {
core.info(`${script} failed for mirror ${hexMirror}`)
}
await installElixir(elixirVersion, hexMirrorsT)
} }
/** /**
+68 -28
View File
@@ -30,16 +30,23 @@ async function main() {
const elixirSpec = getInput('elixir-version', false, 'elixir', versions) const elixirSpec = getInput('elixir-version', false, 'elixir', versions)
const gleamSpec = getInput('gleam-version', false, 'gleam', versions) const gleamSpec = getInput('gleam-version', false, 'gleam', versions)
const rebar3Spec = getInput('rebar3-version', false, 'rebar', versions) const rebar3Spec = getInput('rebar3-version', false, 'rebar', versions)
const hexMirrors = core.getMultilineInput('hexpm-mirrors', {
required: false,
})
if (otpSpec !== 'false') { if (otpSpec !== 'false') {
await installOTP(otpSpec, osVersion) await installOTP(otpSpec, osVersion, hexMirrors)
const elixirInstalled = await maybeInstallElixir(elixirSpec, otpSpec) const elixirInstalled = await maybeInstallElixir(
elixirSpec,
otpSpec,
hexMirrors,
)
if (elixirInstalled === true) { if (elixirInstalled === true) {
const shouldMixRebar = getInput('install-rebar', false) const shouldMixRebar = getInput('install-rebar', false)
await mix(shouldMixRebar, 'rebar') await mix(shouldMixRebar, 'rebar', hexMirrors)
const shouldMixHex = getInput('install-hex', false) const shouldMixHex = getInput('install-hex', false)
await mix(shouldMixHex, 'hex') await mix(shouldMixHex, 'hex', hexMirrors)
} }
} else if (!gleamSpec) { } else if (!gleamSpec) {
throw new Error('otp-version=false is only available when installing Gleam') throw new Error('otp-version=false is only available when installing Gleam')
@@ -49,12 +56,12 @@ async function main() {
await maybeInstallRebar3(rebar3Spec) await maybeInstallRebar3(rebar3Spec)
} }
async function installOTP(otpSpec, osVersion) { async function installOTP(otpSpec, osVersion, hexMirrors) {
const otpVersion = await getOTPVersion(otpSpec, osVersion) const otpVersion = await getOTPVersion(otpSpec, osVersion, hexMirrors)
console.log( console.log(
`##[group]Installing Erlang/OTP ${otpVersion} - built on ${osVersion}`, `##[group]Installing Erlang/OTP ${otpVersion} - built on ${osVersion}`,
) )
await installer.installOTP(osVersion, otpVersion) await installer.installOTP(osVersion, otpVersion, hexMirrors)
core.setOutput('otp-version', otpVersion) core.setOutput('otp-version', otpVersion)
core.addPath(`${process.env.RUNNER_TEMP}/.setup-beam/otp/bin`) core.addPath(`${process.env.RUNNER_TEMP}/.setup-beam/otp/bin`)
console.log('##[endgroup]') console.log('##[endgroup]')
@@ -62,13 +69,17 @@ async function installOTP(otpSpec, osVersion) {
return otpVersion return otpVersion
} }
async function maybeInstallElixir(elixirSpec, otpVersion) { async function maybeInstallElixir(elixirSpec, otpSpec, hexMirrors) {
let installed = false let installed = false
if (elixirSpec) { if (elixirSpec) {
const elixirVersion = await getElixirVersion(elixirSpec, otpVersion) const elixirVersion = await getElixirVersion(
elixirSpec,
otpSpec,
hexMirrors,
)
console.log(`##[group]Installing Elixir ${elixirVersion}`) console.log(`##[group]Installing Elixir ${elixirVersion}`)
await installer.installElixir(elixirVersion) 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') {
@@ -87,12 +98,28 @@ async function maybeInstallElixir(elixirSpec, otpVersion) {
return installed return installed
} }
async function mix(shouldMix, what) { async function mixWithMirrors(cmd, args, hexMirrors) {
if (hexMirrors.length === 0) {
throw new Error('mix failed with every mirror')
}
const [hexMirror, ...hexMirrorsT] = hexMirrors
process.env.HEX_MIRROR = hexMirror
try {
return await exec(cmd, args)
} catch (err) {
core.info(
`mix failed with mirror ${process.env.HEX_MIRROR} with message ${err.message})`,
)
}
return mixWithMirrors(cmd, args, hexMirrorsT)
}
async function mix(shouldMix, what, hexMirrors) {
if (shouldMix === 'true') { if (shouldMix === 'true') {
const cmd = 'mix' const cmd = 'mix'
const args = [`local.${what}`, '--force'] const args = [`local.${what}`, '--force']
console.log(`##[group]Running ${cmd} ${args}`) console.log(`##[group]Running ${cmd} ${args}`)
await exec(cmd, args) await mixWithMirrors(cmd, args, hexMirrors)
console.log('##[endgroup]') console.log('##[endgroup]')
} }
} }
@@ -136,8 +163,8 @@ async function maybeInstallRebar3(rebar3Spec) {
return installed return installed
} }
async function getOTPVersion(otpSpec0, osVersion) { async function getOTPVersion(otpSpec0, osVersion, hexMirrors) {
const otpVersions = await getOTPVersions(osVersion) const otpVersions = await getOTPVersions(osVersion, hexMirrors)
let otpSpec = otpSpec0 // might be a branch (?) let otpSpec = otpSpec0 // might be a branch (?)
const otpVersion = getVersionFromSpec( const otpVersion = getVersionFromSpec(
otpSpec, otpSpec,
@@ -156,10 +183,10 @@ async function getOTPVersion(otpSpec0, osVersion) {
return otpVersions.get(otpVersion) // from the reference, for download return otpVersions.get(otpVersion) // from the reference, for download
} }
async function getElixirVersion(exSpec0, otpVersion0) { 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() const elixirVersions = await getElixirVersions(hexMirrors)
const semverVersions = Array.from(elixirVersions.keys()).sort() const semverVersions = Array.from(elixirVersions.keys()).sort()
const exSpec = exSpec0.replace(/-otp-.*$/, '') const exSpec = exSpec0.replace(/-otp-.*$/, '')
const elixirVersionFromSpec = getVersionFromSpec(exSpec, semverVersions, true) const elixirVersionFromSpec = getVersionFromSpec(exSpec, semverVersions, true)
@@ -219,19 +246,19 @@ async function getRebar3Version(r3Spec) {
return rebar3Version return rebar3Version
} }
async function getOTPVersions(osVersion) { async function getOTPVersions(osVersion, hexMirrors) {
let originListing let otpVersionsListings
let pageIdxs
if (process.platform === 'linux') { if (process.platform === 'linux') {
originListing = `https://builds.hex.pm/builds/otp/${osVersion}/builds.txt` otpVersionsListings = await getWithMirrors(
pageIdxs = [null] `/builds/otp/${osVersion}/builds.txt`,
hexMirrors,
)
} else if (process.platform === 'win32') { } else if (process.platform === 'win32') {
originListing = const originListing =
'https://api.github.com/repos/erlang/otp/releases?per_page=100' 'https://api.github.com/repos/erlang/otp/releases?per_page=100'
pageIdxs = [1, 2, 3] otpVersionsListings = await get(originListing, [1, 2, 3])
} }
const otpVersionsListings = await get(originListing, pageIdxs)
const otpVersions = new Map() const otpVersions = new Map()
if (process.platform === 'linux') { if (process.platform === 'linux') {
@@ -261,10 +288,10 @@ async function getOTPVersions(osVersion) {
return otpVersions return otpVersions
} }
async function getElixirVersions() { async function getElixirVersions(hexMirrors) {
const elixirVersionsListings = await get( const elixirVersionsListings = await getWithMirrors(
'https://builds.hex.pm/builds/elixir/builds.txt', '/builds/elixir/builds.txt',
[null], hexMirrors,
) )
const otpVersionsForElixirMap = new Map() const otpVersionsForElixirMap = new Map()
@@ -448,6 +475,19 @@ async function get(url0, pageIdxs) {
return Promise.all(pageIdxs.map(getPage)) return Promise.all(pageIdxs.map(getPage))
} }
async function getWithMirrors(resourcePath, hexMirrors) {
if (hexMirrors.length === 0) {
throw new Error(`Could not fetch ${resourcePath} from any hex.pm mirror`)
}
const [hexMirror, ...hexMirrorsT] = hexMirrors
try {
return await get(`${hexMirror}${resourcePath}`, [null])
} catch (err) {
core.info(`get failed for URL ${hexMirror}${resourcePath}`)
}
return getWithMirrors(resourcePath, hexMirrorsT)
}
function maybePrependWithV(v) { function maybePrependWithV(v) {
if (isVersion(v)) { if (isVersion(v)) {
return `v${v.replace('v', '')}` return `v${v.replace('v', '')}`