Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"licenses": "yarn licenses generate-disclaimer > 3RD_PARTY_LICENSES",
"markdownlint": "markdownlint *.md ./github/**/*.md",
"shellcheck": "shellcheck .github/workflows/*.sh",
"test": "node test/setup-beam.test.js",
"test": "node --test",
"yamllint": "yamllint .github/workflows/**.yml && yamllint .*.yml && yamllint *.yml",
"clean-dist": "rm -rf ./dist",
"lint": "npm run markdownlint && npm run shellcheck && npm run yamllint && npm run jslint",
Expand All @@ -33,4 +33,4 @@
"engines": {
"node": ">=20"
}
}
}
85 changes: 85 additions & 0 deletions src/lib/getRunnerOSVersion.js
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to keep this in a single file, for now. If the time comes to split we'll do a separate pull request. (also, this way we have to compare/review across different files, which is not ideal)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to follow up with a refactor update, if you'd like, but lets keep concerns separated.

Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
const fs = require('node:fs')
const core = require('@actions/core')

const IMAGE_OS_TO_RUNNER_OS = {
ubuntu18: 'ubuntu-18.04',
ubuntu20: 'ubuntu-20.04',
ubuntu22: 'ubuntu-22.04',
ubuntu24: 'ubuntu-24.04',
win19: 'windows-2019',
win22: 'windows-2022',
}

function getRunnerOSVersion(imageOS, readFile = fs.readFileSync) {
core.startGroup('Get runner OS version')

core.info(`ImageOS is set to '${imageOS}'`)

if (imageOS === 'Linux') {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better to just look at /etc/os-release existing than this? Reason for it is we seem to be moving from one constraint to the other. If we want to be more generic we can base ourselves on the standard (/etc/os-release) and not the results we're looking at today.

core.info('Attempting to detect OS version from /etc/os-release.')

try {
const osRelease = parseOSRelease(readFile)
core.debug('Parsed /etc/os-release: ' + JSON.stringify(osRelease))

const shortVersion = osRelease.VERSION_ID?.split('.')[0]
imageOS = osRelease.ID + shortVersion

core.info(`Detected '${imageOS}'`)
} catch (error) {
core.error('Failed to parse /etc/os-release: ' + error.message)
}
}

const containerFromEnvImageOS = IMAGE_OS_TO_RUNNER_OS[imageOS]
if (!containerFromEnvImageOS) {
throw new Error(
"Tried to map a target OS from env. variable 'ImageOS' (got " +
`${imageOS}` +
"), but failed. If you're using a " +
"self-hosted runner, you should set 'env': 'ImageOS': ... to one of the following: " +
"['" +
`${Object.keys(IMAGE_OS_TO_RUNNER_OS).join("', '")}` +
"']",
)
}

core.info('Resulting runner OS: ' + containerFromEnvImageOS)

core.endGroup()

return containerFromEnvImageOS
}

/**
* Returns an Object with the contents of `/etc/os-release`, with the keys
* being the left side of the '=' and the values being the right side.
* The values are stripped of quotes and whitespace.
*
* Usually, this should result in an object like:
*
* {
* ID: 'ubuntu',
* VERSION_ID: '24.04',
* // ...other keys
* }
*
* @returns {Object} The contents of `/etc/os-release` as an object.
*/
function parseOSRelease(readFile) {
const osRelease = readFile('/etc/os-release', 'utf8')
const lines = osRelease.split('\n')

return Object.fromEntries(
lines
.filter((line) => line.includes('='))
.map((line) => {
const [key, value] = line.split('=')
return [key.trim(), value.replace(/"/g, '').trim()]
}),
)
}

module.exports = {
getRunnerOSVersion,
}
29 changes: 3 additions & 26 deletions src/setup-beam.js
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you ran npm run build-dist (as https://github.com/erlef/setup-beam/blob/main/CONTRIBUTING.md proposes) so this'll likely fail CI.

Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const semver = require('semver')
const fs = require('fs')
const os = require('os')

const { getRunnerOSVersion } = require('./lib/getRunnerOSVersion')

const MAX_HTTP_RETRIES = 3

main().catch((err) => {
Expand All @@ -27,7 +29,7 @@ async function main() {
versions = parseVersionFile(versionFilePath)
}

const osVersion = getRunnerOSVersion()
const osVersion = getRunnerOSVersion(process.env.ImageOS)
Comment on lines -30 to +32
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to keep the process. stuff inside the function.

const otpSpec = getInput('otp-version', true, 'erlang', versions)
const elixirSpec = getInput('elixir-version', false, 'elixir', versions)
const gleamSpec = getInput('gleam-version', false, 'gleam', versions)
Expand Down Expand Up @@ -538,31 +540,6 @@ function getRunnerOSArchitecture() {
)
}

function getRunnerOSVersion() {
const ImageOSToContainer = {
ubuntu18: 'ubuntu-18.04',
ubuntu20: 'ubuntu-20.04',
ubuntu22: 'ubuntu-22.04',
ubuntu24: 'ubuntu-24.04',
win19: 'windows-2019',
win22: 'windows-2022',
}
const containerFromEnvImageOS = ImageOSToContainer[process.env.ImageOS]
if (!containerFromEnvImageOS) {
throw new Error(
"Tried to map a target OS from env. variable 'ImageOS' (got " +
`${process.env.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 getUrlResponse(url, headers, attempt = 1) {
try {
const response = await fetch(url, {
Expand Down
6 changes: 6 additions & 0 deletions test/fixtures/os-release/alpine3.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.21.3
PRETTY_NAME="Alpine Linux v3.21"
HOME_URL="https://alpinelinux.org/"
BUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues"
12 changes: 12 additions & 0 deletions test/fixtures/os-release/ubuntu22.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
PRETTY_NAME="Ubuntu 22.04.5 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.5 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
13 changes: 13 additions & 0 deletions test/fixtures/os-release/ubuntu24.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
PRETTY_NAME="Ubuntu 24.04.2 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION="24.04.2 LTS (Noble Numbat)"
VERSION_CODENAME=noble
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=noble
LOGO=ubuntu-logo
13 changes: 13 additions & 0 deletions test/fixtures/os-release/ubuntu25.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
PRETTY_NAME="Ubuntu 25.04"
NAME="Ubuntu"
VERSION_ID="25.04"
VERSION="25.04 (Plucky Puffin)"
VERSION_CODENAME=plucky
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=plucky
LOGO=ubuntu-logo
97 changes: 97 additions & 0 deletions test/getRunnerOSVersion.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
const { describe, it, afterEach } = require('node:test')
const assert = require('node:assert')
const { readFileSync } = require('node:fs')
const { join } = require('node:path')

const { getRunnerOSVersion } = require('../src/lib/getRunnerOSVersion')

describe('getRunnerOSVersion', () => {
it('throws if no ImageOS env exists', async () => {
assert.throws(() => {
getRunnerOSVersion(undefined)
})
})

describe('simple mappings', () => {
for (const [imageOS, runnerOS] of [
['ubuntu18', 'ubuntu-18.04'],
['ubuntu20', 'ubuntu-20.04'],
['ubuntu22', 'ubuntu-22.04'],
['ubuntu24', 'ubuntu-24.04'],
['win19', 'windows-2019'],
['win22', 'windows-2022'],
]) {
it(`returns ${runnerOS} for ${imageOS}`, () => {
const result = getRunnerOSVersion(imageOS)

assert.strictEqual(result, runnerOS)
})
}
})

describe('detect ubuntu version if "ImageOS" is "Linux"', () => {
afterEach(() => {
// Clear the mock filesystem after each test.
for (const path in mockFS) {
delete mockFS[path]
}
})

it('detects ubuntu 24.04', () => {
mockFS['/etc/os-release'] = loadFixture('ubuntu24.txt')

const result = getRunnerOSVersion('Linux', mockedReadFileSync)
assert.strictEqual(result, 'ubuntu-24.04')
})

it('detects ubuntu 22.04', () => {
mockFS['/etc/os-release'] = loadFixture('ubuntu22.txt')

const result = getRunnerOSVersion('Linux', mockedReadFileSync)
assert.strictEqual(result, 'ubuntu-22.04')
})

it('rejects ubuntu 25.04 (valid format, but not in availability table)', () => {
mockFS['/etc/os-release'] = loadFixture('ubuntu25.txt')

assert.throws(() => {
getRunnerOSVersion('Linux', mockedReadFileSync)
})
})

it('rejects alpine 3 (invalid distro)', () => {
mockFS['/etc/os-release'] = loadFixture('alpine3.txt')

assert.throws(() => {
getRunnerOSVersion('Linux', mockedReadFileSync)
})
})

it('fails with usual message if /etc/os-release is not found', () => {
assert.throws(
() => {
getRunnerOSVersion('Linux', mockedReadFileSync)
},
{
message: /(got Linux)/,
},
)
})
})
})

function loadFixture(filename) {
const path = join(__dirname, 'fixtures', 'os-release', filename)

return readFileSync(path, 'utf8')
}

const mockFS = {}

function mockedReadFileSync(path) {
if (Object.hasOwn(mockFS, path)) {
return mockFS[path]
}

throw new Error(`File not found in mockFS: ${path} (forgot to mock it?)`)
}
Loading