Add Windows to the mix (#49)

This commit is contained in:
Paulo F. Oliveira
2021-06-24 21:58:51 +01:00
committed by GitHub
parent dd4eb24e91
commit 82b4475ba2
21 changed files with 553 additions and 168 deletions
+13 -10
View File
@@ -6,14 +6,17 @@ extends:
- airbnb
parserOptions:
ecmaVersion: 12
rules: {
indent: ["warn", 2],
max-len: ["warn", 100],
no-console: 0,
no-undef: "error",
no-unused-vars: ["error", {"varsIgnorePattern": "^_"}],
no-use-before-define: 0,
operator-linebreak: 0,
require-jsdoc: 0,
rules:
indent: ["warn", 2]
max-len: ["warn", 100]
no-console: 0
no-undef: "error"
no-unused-vars: ["error", {"varsIgnorePattern": "^_"}]
no-use-before-define: 0
operator-linebreak: 0
require-jsdoc: 0
semi: 0
}
settings:
react:
version: 999.999.999
+1 -1
View File
@@ -21,12 +21,12 @@ jobs:
- run: npm install -g npm
- 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
- run: npm run licenses
- run: npm run format
- name: Check if build left artifacts
run: git diff --exit-code
+47 -5
View File
@@ -2,10 +2,12 @@
name: test
on:
push: {branches: main}
pull_request: {branches: main}
repository_dispatch:
workflow_dispatch:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
unit_test:
@@ -18,7 +20,7 @@ jobs:
- run: npm ci
- run: npm test
integration_test:
integration_test_ubuntu:
name: >
Pre-release integration tests
(Ubuntu ${{matrix.combo.os}},
@@ -136,3 +138,43 @@ jobs:
cd test-projects/rebar3
rebar3 ct
if: ${{matrix.combo.rebar3-version}}
integration_test_windows:
name: >
Pre-release integration tests
(Windows ${{matrix.combo.os}},
Erlang/OTP ${{matrix.combo.otp-version}},
rebar3 ${{matrix.combo.rebar3-version}})
runs-on: ${{matrix.combo.os}}
strategy:
fail-fast: false
matrix:
combo:
- otp-version: '24.0.2'
rebar3-version: '3.16'
os: 'windows-2019'
- otp-version: '23.0'
rebar3-version: '3.15'
os: 'windows-2019'
- otp-version: '24.0.2'
rebar3-version: '3.16'
os: 'windows-2016'
- otp-version: '23.0'
rebar3-version: '3.15'
os: 'windows-2016'
steps:
- uses: actions/checkout@v2
- name: Use erlef/setup-beam
id: setup-beam
uses: ./
with:
otp-version: ${{matrix.combo.otp-version}}
rebar3-version: ${{matrix.combo.rebar3-version}}
- name: Erlang/OTP version (action)
run: echo "Erlang/OTP ${{steps.setup-beam.outputs.otp-version}}"
- name: rebar3 version (action)
run: echo "rebar3 ${{steps.setup-beam.outputs.rebar3-version}}"
- name: Run rebar3 project tests
run: |
cd test-projects/rebar3
rebar3 ct
+20
View File
@@ -45,6 +45,8 @@ and Erlang/OTP.
| ubuntu-16.04 | 17 - 24 | ✅
| ubuntu-18.04 | 17 - 24 | ✅
| ubuntu-20.04 | 20 - 24 | ✅
| windows-2016 | 23 - 24 | ✅
| windows-2019 | 23 - 24 | ✅
### Basic example (Elixir)
@@ -130,6 +132,24 @@ jobs:
- run: rebar3 ct
```
### Basic example (`rebar3` on Windows 2016)
```yaml
# create this in .github/workflows/ci.yml
on: push
jobs:
test:
runs-on: windows-2019
steps:
- uses: actions/checkout@v2
- uses: erlef/setup-beam@v1
with:
otp-version: '24.0.2'
rebar3-version: '3.16.1'
- run: rebar3 ct
```
## Elixir Problem Matchers
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.
+57 -35
View File
@@ -81,47 +81,69 @@ async function testOTPVersions() {
let spec
let osVersion
spec = '19.3.x'
osVersion = 'ubuntu-16.04'
expected = 'OTP-19.3.6'
got = await setupBeam.getOTPVersion(spec, osVersion)
assert.deepStrictEqual(got, expected)
if (process.platform === 'linux') {
spec = '19.3.x'
osVersion = 'ubuntu-16.04'
expected = 'OTP-19.3.6'
got = await setupBeam.getOTPVersion(spec, osVersion)
assert.deepStrictEqual(got, expected)
spec = '^19.3.6'
osVersion = 'ubuntu-16.04'
expected = 'OTP-19.3.6'
got = await setupBeam.getOTPVersion(spec, osVersion)
assert.deepStrictEqual(got, expected)
spec = '^19.3.6'
osVersion = 'ubuntu-16.04'
expected = 'OTP-19.3.6'
got = await setupBeam.getOTPVersion(spec, osVersion)
assert.deepStrictEqual(got, expected)
spec = '^19.3'
osVersion = 'ubuntu-18.04'
expected = 'OTP-19.3.6'
got = await setupBeam.getOTPVersion(spec, osVersion)
assert.deepStrictEqual(got, expected)
spec = '^19.3'
osVersion = 'ubuntu-18.04'
expected = 'OTP-19.3.6'
got = await setupBeam.getOTPVersion(spec, osVersion)
assert.deepStrictEqual(got, expected)
spec = '20'
osVersion = 'ubuntu-20.04'
expected = 'OTP-20.3.8'
got = await setupBeam.getOTPVersion(spec, osVersion)
assert.deepStrictEqual(got, expected)
spec = '20'
osVersion = 'ubuntu-20.04'
expected = 'OTP-20.3.8'
got = await setupBeam.getOTPVersion(spec, osVersion)
assert.deepStrictEqual(got, expected)
spec = '20.x'
osVersion = 'ubuntu-20.04'
expected = 'OTP-20.3.8'
got = await setupBeam.getOTPVersion(spec, osVersion)
assert.deepStrictEqual(got, expected)
spec = '20.x'
osVersion = 'ubuntu-20.04'
expected = 'OTP-20.3.8'
got = await setupBeam.getOTPVersion(spec, osVersion)
assert.deepStrictEqual(got, expected)
spec = '20.0'
osVersion = 'ubuntu-20.04'
expected = 'OTP-20.0.5'
got = await setupBeam.getOTPVersion(spec, osVersion)
assert.deepStrictEqual(got, expected)
spec = '20.0'
osVersion = 'ubuntu-20.04'
expected = 'OTP-20.0'
got = await setupBeam.getOTPVersion(spec, osVersion)
assert.deepStrictEqual(got, expected)
spec = '20.0.x'
osVersion = 'ubuntu-20.04'
expected = 'OTP-20.0.5'
got = await setupBeam.getOTPVersion(spec, osVersion)
assert.deepStrictEqual(got, expected)
spec = '20.0.x'
osVersion = 'ubuntu-20.04'
expected = 'OTP-20.0.5'
got = await setupBeam.getOTPVersion(spec, osVersion)
assert.deepStrictEqual(got, expected)
}
if (process.platform === 'win32') {
spec = '24.0.1'
osVersion = 'windows-latest'
expected = '24.0.1'
got = await setupBeam.getOTPVersion(spec, osVersion)
assert.deepStrictEqual(got, expected)
spec = '23.2.x'
osVersion = 'windows-2016'
expected = '23.2.7'
got = await setupBeam.getOTPVersion(spec, osVersion)
assert.deepStrictEqual(got, expected)
spec = '23.0'
osVersion = 'windows-2019'
expected = '23.0'
got = await setupBeam.getOTPVersion(spec, osVersion)
assert.deepStrictEqual(got, expected)
}
}
async function testElixirVersions() {
+159 -58
View File
@@ -4594,7 +4594,13 @@ const path = __nccwpck_require__(5622)
* @param {string} otpVersion
*/
async function installOTP(osVersion, otpVersion) {
await exec(__nccwpck_require__.ab + "install-otp", [osVersion, otpVersion])
const OS = process.platform
if (OS === 'linux') {
await exec(__nccwpck_require__.ab + "install-otp.sh", [osVersion, otpVersion])
} else if (OS === 'win32') {
const script = __nccwpck_require__.ab + "install-otp.ps1"
await exec(`powershell.exe ${script} -VSN:${otpVersion}`)
}
}
/**
@@ -4603,7 +4609,13 @@ async function installOTP(osVersion, otpVersion) {
* @param {string} elixirVersion
*/
async function installElixir(elixirVersion) {
await exec(__nccwpck_require__.ab + "install-elixir", [elixirVersion])
const OS = process.platform
if (OS === 'linux') {
await exec(__nccwpck_require__.ab + "install-elixir.sh", [elixirVersion])
} else if (OS === 'win32') {
const script = __nccwpck_require__.ab + "install-elixir.ps1"
await exec(`powershell.exe ${script} ${elixirVersion}`)
}
}
/**
@@ -4612,12 +4624,20 @@ async function installElixir(elixirVersion) {
* @param {string} rebar3Version
*/
async function installRebar3(rebar3Version) {
await exec(__nccwpck_require__.ab + "install-rebar3", [rebar3Version])
const OS = process.platform
if (OS === 'linux') {
await exec(__nccwpck_require__.ab + "install-rebar3.sh", [rebar3Version])
} else if (OS === 'win32') {
const script = __nccwpck_require__.ab + "install-rebar3.ps1"
await exec(`powershell.exe ${script} -VSN:${rebar3Version}`)
}
}
function checkPlatform() {
if (process.platform !== 'linux') {
throw new Error('@erlef/setup-beam only supports Ubuntu Linux at this time')
if (process.platform !== 'linux' && process.platform !== 'win32') {
throw new Error(
'@erlef/setup-beam only supports Ubuntu and Windows at this time',
)
}
}
@@ -4653,20 +4673,24 @@ async function main() {
const otpVersion = await installOTP(otpSpec, osVersion)
const elixirSpec = core.getInput('elixir-version', { required: false })
const elixirInstalled = await maybeInstallElixir(elixirSpec, otpVersion)
const shouldMixHex = core.getInput('install-hex', {
required: false,
})
const elixirInstalled = await maybeInstallElixir(
elixirSpec,
otpVersion,
shouldMixHex,
)
if (elixirInstalled === true) {
const shouldMixRebar = core.getInput('install-rebar', {
required: false,
})
await mix(shouldMixRebar, 'rebar')
const shouldMixHex = core.getInput('install-hex', {
required: false,
})
await mix(shouldMixHex, 'hex')
}
const rebar3Spec = core.getInput('rebar3-version', { required: false })
maybeInstallRebar3(rebar3Spec)
await maybeInstallRebar3(rebar3Spec)
}
async function installOTP(otpSpec, osVersion) {
@@ -4676,13 +4700,17 @@ async function installOTP(otpSpec, osVersion) {
)
await installer.installOTP(osVersion, otpVersion)
core.setOutput('otp-version', otpVersion)
prependToPath(`${process.env.RUNNER_TEMP}/.setup-beam/otp/bin`)
if (process.platform === 'linux') {
prependToPath(`${process.env.RUNNER_TEMP}/.setup-beam/otp/bin`)
} else if (process.platform === 'win32') {
prependToPath(`C:/Program Files/erl-${otpVersion}/bin`)
}
console.log('##[endgroup]')
return otpVersion
}
async function maybeInstallElixir(elixirSpec, otpVersion) {
async function maybeInstallElixir(elixirSpec, otpVersion, shouldMixHex) {
if (elixirSpec) {
const elixirVersion = await getElixirVersion(elixirSpec, otpVersion)
console.log(`##[group]Installing Elixir ${elixirVersion}`)
@@ -4698,6 +4726,12 @@ async function maybeInstallElixir(elixirSpec, otpVersion) {
return true
}
if (shouldMixHex) {
console.log(
"hex will not be installed (overriding default) since Elixir wasn't either",
)
}
return false
}
@@ -4784,7 +4818,7 @@ async function getElixirVersion(exSpec0, otpVersion) {
`Using Elixir ${elixirVersion} (built for OTP ${otpVersionMajor})`,
)
} else {
// ... and it's not available: fallback to the "generic" version (v1.4.5 only).
// ... and it's not available: fallback to the 'generic' version (v1.4.5 only).
elixirVersionWithOTP = elixirVersion
core.info(`Using Elixir ${elixirVersion}`)
}
@@ -4811,34 +4845,61 @@ async function getRebar3Version(r3Spec) {
}
async function getOTPVersions(osVersion) {
const otpVersionsListing = await get(
`https://repo.hex.pm/builds/otp/${osVersion}/builds.txt`,
)
let originListing
let pageIdxs
if (process.platform === 'linux') {
originListing = `https://repo.hex.pm/builds/otp/${osVersion}/builds.txt`
pageIdxs = [null]
} else if (process.platform === 'win32') {
originListing =
'https://api.github.com/repos/erlang/otp/releases?per_page=100'
pageIdxs = [1, 2, 3]
}
const otpVersionsListings = await get(originListing, pageIdxs)
const otpVersions = new Map()
otpVersionsListing
.trim()
.split('\n')
.forEach((line) => {
const otpMatch = line.match(/^(OTP-)?([^ ]+)/)
if (process.platform === 'linux') {
otpVersionsListings
.trim()
.split('\n')
.forEach((line) => {
const otpMatch = line.match(/^(OTP-)?([^ ]+)/)
let otpVersion = otpMatch[2]
if (semver.validRange(otpVersion)) {
otpVersion = semver.minVersion(otpVersion).version
}
otpVersions.set(otpVersion, otpMatch[0]) // we keep the original for later reference
let otpVersion = otpMatch[2]
if (semver.validRange(otpVersion) && hasPatch(otpVersion)) {
otpVersion = semver.minVersion(otpVersion).version
}
otpVersions.set(otpVersion, otpMatch[0]) // we keep the original for later reference
})
} else if (process.platform === 'win32') {
otpVersionsListings.forEach((otpVersionsListing) => {
JSON.parse(otpVersionsListing)
.map((x) => x.assets)
.flat()
.filter((x) => x.name.match(/^otp_win64_.*.exe$/))
.forEach((x) => {
const otpMatch = x.name.match(/^otp_win64_(.*).exe$/)
let otpVersion = otpMatch[1]
if (semver.validRange(otpVersion) && hasPatch(otpVersion)) {
otpVersion = semver.minVersion(otpVersion).version
}
otpVersions.set(otpVersion, otpVersion)
})
})
}
return otpVersions
}
async function getElixirVersions() {
const elixirVersionsListing = await get(
const elixirVersionsListings = await get(
'https://repo.hex.pm/builds/elixir/builds.txt',
[null],
)
const otpVersionsForElixirMap = new Map()
elixirVersionsListing
elixirVersionsListings
.trim()
.split('\n')
.forEach((line) => {
@@ -4858,13 +4919,17 @@ async function getElixirVersions() {
}
async function getRebar3Versions() {
const resultJSON = await get(
const resultJSONs = await get(
'https://api.github.com/repos/erlang/rebar3/releases?per_page=100',
[1, 2, 3],
)
const rebar3VersionsListing = JSON.parse(resultJSON)
.map((x) => x.tag_name)
.sort()
const rebar3VersionsListing = []
resultJSONs.forEach((resultJSON) => {
JSON.parse(resultJSON)
.map((x) => x.tag_name)
.sort()
.forEach((v) => rebar3VersionsListing.push(v))
})
return rebar3VersionsListing
}
@@ -4877,43 +4942,79 @@ function getVersionFromSpec(spec, versions) {
}
function getRunnerOSVersion() {
const mapToUbuntuVersion = {
const ImageOSToContainer = {
ubuntu16: 'ubuntu-16.04',
ubuntu18: 'ubuntu-18.04',
ubuntu20: 'ubuntu-20.04',
win16: 'windows-2016',
win19: 'windows-2019',
}
return mapToUbuntuVersion[process.env.ImageOS] || 'ubuntu-18.04'
return ImageOSToContainer[process.env.ImageOS]
}
function get(url) {
return new Promise((resolve, reject) => {
https
.get(
url,
{
headers: { 'user-agent': 'setup-beam' },
},
(res) => {
let data = ''
res.on('data', (chunk) => {
data += chunk
})
res.on('end', () => {
resolve(data)
})
},
)
.on('error', (err) => {
reject(err)
})
})
async function get(url0, pageIdxs) {
function getPage(pageIdx) {
return new Promise((resolve, reject) => {
const url = new URL(url0)
if (pageIdx !== null) {
url.searchParams.append('page', pageIdx)
}
https
.get(
url,
{
headers: { 'user-agent': 'setup-beam' },
},
(res) => {
let data = ''
res.on('data', (chunk) => {
data += chunk
})
res.on('end', () => {
if (res.statusCode >= 400 && res.statusCode <= 599) {
reject(
new Error(
`Got ${res.statusCode} from ${url}. Exiting with error`,
),
)
} else {
resolve(data)
}
})
},
)
.on('error', (err) => {
reject(err)
})
})
}
let ret
if (pageIdxs[0] === null) {
ret = getPage(null)
} else {
ret = Promise.all(pageIdxs.map((pageIdx) => getPage(pageIdx)))
}
return ret
}
function prependToPath(what) {
process.env.PATH = `${what}:${process.env.PATH}`
if (process.platform === 'linux') {
process.env.PATH = `${what}:${process.env.PATH}`
} else if (process.platform === 'win32') {
process.env.PATH = `${what};${process.env.PATH}`
}
}
function hasPatch(v) {
try {
semver.patch(v)
} catch {
return false
}
return true
}
module.exports = {
getOTPVersion,
getElixirVersion,
+5
View File
@@ -0,0 +1,5 @@
Write-Output "Installer for Elixir for Windows not available"
$ErrorActionPreference="Stop"
Exit 1
View File
+19
View File
@@ -0,0 +1,19 @@
param([Parameter(Mandatory=$true)][string]$VSN)
$ErrorActionPreference="Stop"
Set-Location $Env:RUNNER_TEMP
$FILE_OUTPUT="otp.exe"
$DIR_FOR_BIN=".setup-beam/otp"
Remove-Item -Recurse -Force "$DIR_FOR_BIN" -ErrorAction SilentlyContinue
$ProgressPreference="SilentlyContinue"
Invoke-WebRequest "https://github.com/erlang/otp/releases/download/OTP-$VSN/otp_win64_$VSN.exe" -OutFile "$FILE_OUTPUT"
$ProgressPreference="Continue"
New-Item "$DIR_FOR_BIN" -ItemType Directory | Out-Null
Move-Item "$FILE_OUTPUT" "$DIR_FOR_BIN"
Start-Process "./$DIR_FOR_BIN/$FILE_OUTPUT" /S -Wait
Write-Output "C:/Program Files/erl-$VSN/bin" | Out-File -FilePath $Env:GITHUB_PATH -Encoding utf8 -Append
Write-Output "Installed Erlang/OTP version follows"
& "C:/Program Files/erl-$VSN/bin/erl.exe" "+V" | Write-Output
View File
+24
View File
@@ -0,0 +1,24 @@
param([Parameter(Mandatory=$true)][string]$VSN)
$ErrorActionPreference="Stop"
Set-Location $Env:RUNNER_TEMP
$FILE_INPUT="rebar3"
$FILE_OUTPUT="rebar3"
$FILE_OUTPUT_PS1="rebar3.ps1"
$DIR_FOR_BIN=".setup-beam/rebar3"
Remove-Item -Force "$FILE_OUTPUT" -ErrorAction SilentlyContinue
Remove-Item -Recurse -Force "$DIR_FOR_BIN" -ErrorAction SilentlyContinue
$ProgressPreference="SilentlyContinue"
Invoke-WebRequest "https://github.com/erlang/rebar3/releases/download/${VSN}/${FILE_INPUT}" -OutFile "$FILE_OUTPUT"
$ProgressPreference="Continue"
New-Item "$DIR_FOR_BIN/bin" -ItemType Directory | Out-Null
Move-Item "$FILE_OUTPUT" "$DIR_FOR_BIN/bin"
Write-Output "& escript.exe $PWD/$DIR_FOR_BIN/bin/$FILE_OUTPUT `$args" | Out-File -FilePath "$FILE_OUTPUT_PS1" -Encoding utf8 -Append
type $FILE_OUTPUT_PS1
Move-Item "$FILE_OUTPUT_PS1" "$DIR_FOR_BIN/bin"
Write-Output "$PWD/$DIR_FOR_BIN/bin" | Out-File -FilePath $Env:GITHUB_PATH -Encoding utf8 -Append
Write-Output "Installed rebar3 version follows"
& "$DIR_FOR_BIN/bin/rebar3" "version" | Write-Output
View File
+1 -1
View File
@@ -8,7 +8,7 @@
"jslint": "eslint src/**/*.js && eslint __tests__/**/*.js",
"licenses": "yarn licenses generate-disclaimer > 3RD_PARTY_LICENSES",
"markdownlint": "markdownlint *.md",
"shellcheck": "shellcheck src/install-*",
"shellcheck": "shellcheck src/install-*.sh",
"test": "node __tests__/setup-beam.test.js",
"yamllint": "yamllint .github/workflows/**.yml && yamllint .*.yml && yamllint *.yml"
},
+5
View File
@@ -0,0 +1,5 @@
Write-Output "Installer for Elixir for Windows not available"
$ErrorActionPreference="Stop"
Exit 1
+19
View File
@@ -0,0 +1,19 @@
param([Parameter(Mandatory=$true)][string]$VSN)
$ErrorActionPreference="Stop"
Set-Location $Env:RUNNER_TEMP
$FILE_OUTPUT="otp.exe"
$DIR_FOR_BIN=".setup-beam/otp"
Remove-Item -Recurse -Force "$DIR_FOR_BIN" -ErrorAction SilentlyContinue
$ProgressPreference="SilentlyContinue"
Invoke-WebRequest "https://github.com/erlang/otp/releases/download/OTP-$VSN/otp_win64_$VSN.exe" -OutFile "$FILE_OUTPUT"
$ProgressPreference="Continue"
New-Item "$DIR_FOR_BIN" -ItemType Directory | Out-Null
Move-Item "$FILE_OUTPUT" "$DIR_FOR_BIN"
Start-Process "./$DIR_FOR_BIN/$FILE_OUTPUT" /S -Wait
Write-Output "C:/Program Files/erl-$VSN/bin" | Out-File -FilePath $Env:GITHUB_PATH -Encoding utf8 -Append
Write-Output "Installed Erlang/OTP version follows"
& "C:/Program Files/erl-$VSN/bin/erl.exe" "+V" | Write-Output
+24
View File
@@ -0,0 +1,24 @@
param([Parameter(Mandatory=$true)][string]$VSN)
$ErrorActionPreference="Stop"
Set-Location $Env:RUNNER_TEMP
$FILE_INPUT="rebar3"
$FILE_OUTPUT="rebar3"
$FILE_OUTPUT_PS1="rebar3.ps1"
$DIR_FOR_BIN=".setup-beam/rebar3"
Remove-Item -Force "$FILE_OUTPUT" -ErrorAction SilentlyContinue
Remove-Item -Recurse -Force "$DIR_FOR_BIN" -ErrorAction SilentlyContinue
$ProgressPreference="SilentlyContinue"
Invoke-WebRequest "https://github.com/erlang/rebar3/releases/download/${VSN}/${FILE_INPUT}" -OutFile "$FILE_OUTPUT"
$ProgressPreference="Continue"
New-Item "$DIR_FOR_BIN/bin" -ItemType Directory | Out-Null
Move-Item "$FILE_OUTPUT" "$DIR_FOR_BIN/bin"
Write-Output "& escript.exe $PWD/$DIR_FOR_BIN/bin/$FILE_OUTPUT `$args" | Out-File -FilePath "$FILE_OUTPUT_PS1" -Encoding utf8 -Append
type $FILE_OUTPUT_PS1
Move-Item "$FILE_OUTPUT_PS1" "$DIR_FOR_BIN/bin"
Write-Output "$PWD/$DIR_FOR_BIN/bin" | Out-File -FilePath $Env:GITHUB_PATH -Encoding utf8 -Append
Write-Output "Installed rebar3 version follows"
& "$DIR_FOR_BIN/bin/rebar3" "version" | Write-Output
+25 -5
View File
@@ -8,7 +8,13 @@ const path = require('path')
* @param {string} otpVersion
*/
async function installOTP(osVersion, otpVersion) {
await exec(path.join(__dirname, 'install-otp'), [osVersion, otpVersion])
const OS = process.platform
if (OS === 'linux') {
await exec(path.join(__dirname, 'install-otp.sh'), [osVersion, otpVersion])
} else if (OS === 'win32') {
const script = path.join(__dirname, 'install-otp.ps1')
await exec(`powershell.exe ${script} -VSN:${otpVersion}`)
}
}
/**
@@ -17,7 +23,13 @@ async function installOTP(osVersion, otpVersion) {
* @param {string} elixirVersion
*/
async function installElixir(elixirVersion) {
await exec(path.join(__dirname, 'install-elixir'), [elixirVersion])
const OS = process.platform
if (OS === 'linux') {
await exec(path.join(__dirname, 'install-elixir.sh'), [elixirVersion])
} else if (OS === 'win32') {
const script = path.join(__dirname, 'install-elixir.ps1')
await exec(`powershell.exe ${script} ${elixirVersion}`)
}
}
/**
@@ -26,12 +38,20 @@ async function installElixir(elixirVersion) {
* @param {string} rebar3Version
*/
async function installRebar3(rebar3Version) {
await exec(path.join(__dirname, 'install-rebar3'), [rebar3Version])
const OS = process.platform
if (OS === 'linux') {
await exec(path.join(__dirname, 'install-rebar3.sh'), [rebar3Version])
} else if (OS === 'win32') {
const script = path.join(__dirname, 'install-rebar3.ps1')
await exec(`powershell.exe ${script} -VSN:${rebar3Version}`)
}
}
function checkPlatform() {
if (process.platform !== 'linux') {
throw new Error('@erlef/setup-beam only supports Ubuntu Linux at this time')
if (process.platform !== 'linux' && process.platform !== 'win32') {
throw new Error(
'@erlef/setup-beam only supports Ubuntu and Windows at this time',
)
}
}
+134 -53
View File
@@ -17,20 +17,24 @@ async function main() {
const otpVersion = await installOTP(otpSpec, osVersion)
const elixirSpec = core.getInput('elixir-version', { required: false })
const elixirInstalled = await maybeInstallElixir(elixirSpec, otpVersion)
const shouldMixHex = core.getInput('install-hex', {
required: false,
})
const elixirInstalled = await maybeInstallElixir(
elixirSpec,
otpVersion,
shouldMixHex,
)
if (elixirInstalled === true) {
const shouldMixRebar = core.getInput('install-rebar', {
required: false,
})
await mix(shouldMixRebar, 'rebar')
const shouldMixHex = core.getInput('install-hex', {
required: false,
})
await mix(shouldMixHex, 'hex')
}
const rebar3Spec = core.getInput('rebar3-version', { required: false })
maybeInstallRebar3(rebar3Spec)
await maybeInstallRebar3(rebar3Spec)
}
async function installOTP(otpSpec, osVersion) {
@@ -40,13 +44,17 @@ async function installOTP(otpSpec, osVersion) {
)
await installer.installOTP(osVersion, otpVersion)
core.setOutput('otp-version', otpVersion)
prependToPath(`${process.env.RUNNER_TEMP}/.setup-beam/otp/bin`)
if (process.platform === 'linux') {
prependToPath(`${process.env.RUNNER_TEMP}/.setup-beam/otp/bin`)
} else if (process.platform === 'win32') {
prependToPath(`C:/Program Files/erl-${otpVersion}/bin`)
}
console.log('##[endgroup]')
return otpVersion
}
async function maybeInstallElixir(elixirSpec, otpVersion) {
async function maybeInstallElixir(elixirSpec, otpVersion, shouldMixHex) {
if (elixirSpec) {
const elixirVersion = await getElixirVersion(elixirSpec, otpVersion)
console.log(`##[group]Installing Elixir ${elixirVersion}`)
@@ -62,6 +70,12 @@ async function maybeInstallElixir(elixirSpec, otpVersion) {
return true
}
if (shouldMixHex) {
console.log(
"hex will not be installed (overriding default) since Elixir wasn't either",
)
}
return false
}
@@ -148,7 +162,7 @@ async function getElixirVersion(exSpec0, otpVersion) {
`Using Elixir ${elixirVersion} (built for OTP ${otpVersionMajor})`,
)
} else {
// ... and it's not available: fallback to the "generic" version (v1.4.5 only).
// ... and it's not available: fallback to the 'generic' version (v1.4.5 only).
elixirVersionWithOTP = elixirVersion
core.info(`Using Elixir ${elixirVersion}`)
}
@@ -175,34 +189,61 @@ async function getRebar3Version(r3Spec) {
}
async function getOTPVersions(osVersion) {
const otpVersionsListing = await get(
`https://repo.hex.pm/builds/otp/${osVersion}/builds.txt`,
)
let originListing
let pageIdxs
if (process.platform === 'linux') {
originListing = `https://repo.hex.pm/builds/otp/${osVersion}/builds.txt`
pageIdxs = [null]
} else if (process.platform === 'win32') {
originListing =
'https://api.github.com/repos/erlang/otp/releases?per_page=100'
pageIdxs = [1, 2, 3]
}
const otpVersionsListings = await get(originListing, pageIdxs)
const otpVersions = new Map()
otpVersionsListing
.trim()
.split('\n')
.forEach((line) => {
const otpMatch = line.match(/^(OTP-)?([^ ]+)/)
if (process.platform === 'linux') {
otpVersionsListings
.trim()
.split('\n')
.forEach((line) => {
const otpMatch = line.match(/^(OTP-)?([^ ]+)/)
let otpVersion = otpMatch[2]
if (semver.validRange(otpVersion)) {
otpVersion = semver.minVersion(otpVersion).version
}
otpVersions.set(otpVersion, otpMatch[0]) // we keep the original for later reference
let otpVersion = otpMatch[2]
if (semver.validRange(otpVersion) && hasPatch(otpVersion)) {
otpVersion = semver.minVersion(otpVersion).version
}
otpVersions.set(otpVersion, otpMatch[0]) // we keep the original for later reference
})
} else if (process.platform === 'win32') {
otpVersionsListings.forEach((otpVersionsListing) => {
JSON.parse(otpVersionsListing)
.map((x) => x.assets)
.flat()
.filter((x) => x.name.match(/^otp_win64_.*.exe$/))
.forEach((x) => {
const otpMatch = x.name.match(/^otp_win64_(.*).exe$/)
let otpVersion = otpMatch[1]
if (semver.validRange(otpVersion) && hasPatch(otpVersion)) {
otpVersion = semver.minVersion(otpVersion).version
}
otpVersions.set(otpVersion, otpVersion)
})
})
}
return otpVersions
}
async function getElixirVersions() {
const elixirVersionsListing = await get(
const elixirVersionsListings = await get(
'https://repo.hex.pm/builds/elixir/builds.txt',
[null],
)
const otpVersionsForElixirMap = new Map()
elixirVersionsListing
elixirVersionsListings
.trim()
.split('\n')
.forEach((line) => {
@@ -222,13 +263,17 @@ async function getElixirVersions() {
}
async function getRebar3Versions() {
const resultJSON = await get(
const resultJSONs = await get(
'https://api.github.com/repos/erlang/rebar3/releases?per_page=100',
[1, 2, 3],
)
const rebar3VersionsListing = JSON.parse(resultJSON)
.map((x) => x.tag_name)
.sort()
const rebar3VersionsListing = []
resultJSONs.forEach((resultJSON) => {
JSON.parse(resultJSON)
.map((x) => x.tag_name)
.sort()
.forEach((v) => rebar3VersionsListing.push(v))
})
return rebar3VersionsListing
}
@@ -241,43 +286,79 @@ function getVersionFromSpec(spec, versions) {
}
function getRunnerOSVersion() {
const mapToUbuntuVersion = {
const ImageOSToContainer = {
ubuntu16: 'ubuntu-16.04',
ubuntu18: 'ubuntu-18.04',
ubuntu20: 'ubuntu-20.04',
win16: 'windows-2016',
win19: 'windows-2019',
}
return mapToUbuntuVersion[process.env.ImageOS] || 'ubuntu-18.04'
return ImageOSToContainer[process.env.ImageOS]
}
function get(url) {
return new Promise((resolve, reject) => {
https
.get(
url,
{
headers: { 'user-agent': 'setup-beam' },
},
(res) => {
let data = ''
res.on('data', (chunk) => {
data += chunk
})
res.on('end', () => {
resolve(data)
})
},
)
.on('error', (err) => {
reject(err)
})
})
async function get(url0, pageIdxs) {
function getPage(pageIdx) {
return new Promise((resolve, reject) => {
const url = new URL(url0)
if (pageIdx !== null) {
url.searchParams.append('page', pageIdx)
}
https
.get(
url,
{
headers: { 'user-agent': 'setup-beam' },
},
(res) => {
let data = ''
res.on('data', (chunk) => {
data += chunk
})
res.on('end', () => {
if (res.statusCode >= 400 && res.statusCode <= 599) {
reject(
new Error(
`Got ${res.statusCode} from ${url}. Exiting with error`,
),
)
} else {
resolve(data)
}
})
},
)
.on('error', (err) => {
reject(err)
})
})
}
let ret
if (pageIdxs[0] === null) {
ret = getPage(null)
} else {
ret = Promise.all(pageIdxs.map((pageIdx) => getPage(pageIdx)))
}
return ret
}
function prependToPath(what) {
process.env.PATH = `${what}:${process.env.PATH}`
if (process.platform === 'linux') {
process.env.PATH = `${what}:${process.env.PATH}`
} else if (process.platform === 'win32') {
process.env.PATH = `${what};${process.env.PATH}`
}
}
function hasPatch(v) {
try {
semver.patch(v)
} catch {
return false
}
return true
}
module.exports = {
getOTPVersion,
getElixirVersion,