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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/node_modules
/test/.tool-versions
/test/mise.toml
/dist/package.json
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,16 +141,18 @@ e.g. `${{steps.setup-beam.outputs.erlang-version}}`

### Version file

A version file type is specified via input `version-file-type` (defaults to `.tool-versions`).
A version file is specified via input `version-file` (e.g.`.tool-versions`). This
allows not having to use YML input for versions, though the action does check (and
will exit with error) if both inputs are set.

**Note**: if you're using a version file, option `version-type` is checked to be `strict`,
and will make the action exit with error otherwise.

The following version file formats are supported:
The following are supported `version-file-type` inputs:

- `.tool-versions`, as specified by [asdf: Configuration](https://asdf-vm.com/manage/configuration.html)
- `mise.toml`, as specified by [mise-en-place](https://mise.jdx.dev/configuration.html#tools-dev-tools)

Supported version elements are the same as the ones defined for the YML portion of the action,
with the following correspondence.
Expand Down
63 changes: 46 additions & 17 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -80470,10 +80470,12 @@ var lodash = __nccwpck_require__(2356);



const toml = require('toml')

const setup_beam_dirname = external_node_path_namespaceObject.dirname((0,external_node_url_.fileURLToPath)(import.meta.url))

const MAX_HTTP_RETRIES = 3
const APPS = ['erlang', 'elixir', 'gleam', 'rebar']

if (process.env.NODE_ENV !== 'test') {
main().catch((err) => {
Expand All @@ -80492,7 +80494,10 @@ async function main() {
"you have to set version-type=strict if you're using version-file",
)
}
versions = parseVersionFile(versionFilePath)

const versionFileType =
setup_beam_getInput('version-file-type', false) || '.tool-versions'
versions = parseVersionFile(versionFilePath, versionFileType)
}

const otpSpec = setup_beam_getInput('otp-version', true, 'erlang', versions)
Expand Down Expand Up @@ -81263,28 +81268,14 @@ alongside ${alternativeName}=${alternativeValue} \
return input
}

function parseVersionFile(versionFilePath0) {
const versionFilePath = external_node_path_namespaceObject.resolve(
process.env.GITHUB_WORKSPACE,
versionFilePath0,
)
if (!external_node_fs_namespaceObject.existsSync(versionFilePath)) {
throw new Error(
`The specified version file, ${versionFilePath0}, does not exist`,
)
}

lib_core.startGroup(`Parsing version file at ${versionFilePath0}`)
function parseToolVersionsFile(versionFilePath) {
const appVersions = new Map()
const versions = external_node_fs_namespaceObject.readFileSync(versionFilePath, 'utf8')
// For the time being we parse .tool-versions
// If we ever start parsing something else, this should
// become default in a new option named e.g. version-file-type
versions.split(/\r?\n/).forEach((line) => {
const appVersion = line.match(/^([^ ]+)[ ]+(ref:v?)?([^ #]+)/)
if (appVersion) {
const app = appVersion[1]
if (['erlang', 'elixir', 'gleam', 'rebar'].includes(app)) {
if (APPS.includes(app)) {
const [, , , version] = appVersion
lib_core.info(`Consuming ${app} at version ${version}`)
appVersions.set(app, version)
Expand All @@ -81301,6 +81292,44 @@ function parseVersionFile(versionFilePath0) {
return appVersions
}

function parseMiseTomlFile(versionFilePath) {
const appVersions = new Map()
const miseToml = external_node_fs_namespaceObject.readFileSync(versionFilePath, 'utf8')
const miseTomlParsed = toml.parse(miseToml)
for (const app in miseTomlParsed.tools) {
if (APPS.includes(app)) {
const appVersion = miseTomlParsed.tools[app]
const version =
typeof appVersion == 'object' ? appVersion.version : appVersion

lib_core.info(`Consuming ${app} at version ${version}`)
appVersions.set(app, version)
}
}

return appVersions
}

function parseVersionFile(versionFilePath0, versionFileType) {
const versionFilePath = external_node_path_namespaceObject.resolve(
process.env.GITHUB_WORKSPACE,
versionFilePath0,
)
if (!external_node_fs_namespaceObject.existsSync(versionFilePath)) {
throw new Error(
`The specified version file, ${versionFilePath0}, does not exist`,
)
}
lib_core.startGroup(`Parsing ${versionFileType} file at ${versionFilePath0}`)

switch (versionFileType) {
case '.tool-versions':
return parseToolVersionsFile(versionFilePath)
case 'mise.toml':
return parseMiseTomlFile(versionFilePath)
}
}

function debugLog(groupName, message) {
const group = `Debugging for ${groupName}`
lib_core.debug(
Expand Down
13 changes: 12 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"@actions/tool-cache": "4.0.0",
"csv-parse": "6.1.0",
"lodash": "4.17.23",
"semver": "7.7.4"
"semver": "7.7.4",
"toml": "3.0.0"
},
"devDependencies": {
"@eslint/js": "10.0.1",
Expand Down
63 changes: 46 additions & 17 deletions src/setup-beam.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import * as tc from '@actions/tool-cache'
import * as semver from 'semver'
import * as csv from 'csv-parse/sync'
import _ from 'lodash'
const toml = require('toml')

const __dirname = path.dirname(fileURLToPath(import.meta.url))

const MAX_HTTP_RETRIES = 3
const APPS = ['erlang', 'elixir', 'gleam', 'rebar']

if (process.env.NODE_ENV !== 'test') {
main().catch((err) => {
Expand All @@ -30,7 +32,10 @@ async function main() {
"you have to set version-type=strict if you're using version-file",
)
}
versions = parseVersionFile(versionFilePath)

const versionFileType =
getInput('version-file-type', false) || '.tool-versions'
Copy link
Collaborator

Choose a reason for hiding this comment

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

Per https://github.com/erlef/setup-beam/blob/main/action.yml#L71, not only is the input named differently, but there's no default.

Copy link
Collaborator

Choose a reason for hiding this comment

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

What I mean with this is:

  1. you should keep reading version-file
  2. you shouldn't need this new input, since you're already making for a switch below, where you decide on the same values expected for version-file

Copy link
Contributor Author

@mruoss mruoss Mar 3, 2026

Choose a reason for hiding this comment

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

  1. you should keep reading version-file

but I do keep reading version-file, no? I didn't change that part

  1. you shouldn't need this new input, since you're already making for a switch below, where you decide on the same values expected for version-file

My point is: We're not in control of what is expected for version-file. Mise currently supports more than 7 different forms of mise.toml. Not sure about what asdf supports besides .tool-versions

Or how would the switch look like in your version?

versions = parseVersionFile(versionFilePath, versionFileType)
}

const otpSpec = getInput('otp-version', true, 'erlang', versions)
Expand Down Expand Up @@ -802,28 +807,14 @@ alongside ${alternativeName}=${alternativeValue} \
return input
}

function parseVersionFile(versionFilePath0) {
const versionFilePath = path.resolve(
process.env.GITHUB_WORKSPACE,
versionFilePath0,
)
if (!fs.existsSync(versionFilePath)) {
throw new Error(
`The specified version file, ${versionFilePath0}, does not exist`,
)
}

core.startGroup(`Parsing version file at ${versionFilePath0}`)
function parseToolVersionsFile(versionFilePath) {
const appVersions = new Map()
const versions = fs.readFileSync(versionFilePath, 'utf8')
// For the time being we parse .tool-versions
// If we ever start parsing something else, this should
// become default in a new option named e.g. version-file-type
versions.split(/\r?\n/).forEach((line) => {
const appVersion = line.match(/^([^ ]+)[ ]+(ref:v?)?([^ #]+)/)
if (appVersion) {
const app = appVersion[1]
if (['erlang', 'elixir', 'gleam', 'rebar'].includes(app)) {
if (APPS.includes(app)) {
const [, , , version] = appVersion
core.info(`Consuming ${app} at version ${version}`)
appVersions.set(app, version)
Expand All @@ -840,6 +831,44 @@ function parseVersionFile(versionFilePath0) {
return appVersions
}

function parseMiseTomlFile(versionFilePath) {
const appVersions = new Map()
const miseToml = fs.readFileSync(versionFilePath, 'utf8')
const miseTomlParsed = toml.parse(miseToml)
for (const app in miseTomlParsed.tools) {
if (APPS.includes(app)) {
const appVersion = miseTomlParsed.tools[app]
const version =
typeof appVersion == 'object' ? appVersion.version : appVersion

core.info(`Consuming ${app} at version ${version}`)
appVersions.set(app, version)
}
}

return appVersions
}

function parseVersionFile(versionFilePath0, versionFileType) {
const versionFilePath = path.resolve(
process.env.GITHUB_WORKSPACE,
versionFilePath0,
)
if (!fs.existsSync(versionFilePath)) {
throw new Error(
`The specified version file, ${versionFilePath0}, does not exist`,
)
}
core.startGroup(`Parsing ${versionFileType} file at ${versionFilePath0}`)

switch (versionFileType) {
case '.tool-versions':
return parseToolVersionsFile(versionFilePath)
case 'mise.toml':
return parseMiseTomlFile(versionFilePath)
}
}

function debugLog(groupName, message) {
const group = `Debugging for ${groupName}`
core.debug(
Expand Down
61 changes: 58 additions & 3 deletions test/setup-beam.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -969,7 +969,7 @@ describe('.getVersionFromSpec(_)', () => {
})
})

describe('version file', () => {
describe('.tool-versions file', () => {
const otpVersion = unsimulateInput('otp-version')
const elixirVersion = unsimulateInput('elixir-version')
const gleamVersion = unsimulateInput('gleam-version')
Expand All @@ -990,15 +990,70 @@ gleam ${gleam} \n`
}
fs.writeFileSync(filename, toolVersions)
process.env.GITHUB_WORKSPACE = ''
const appVersions = setupBeam.parseVersionFile(filename)
const appVersions = setupBeam.parseVersionFile(filename, '.tool-versions')
assert.strictEqual(appVersions.get('erlang'), erlang)
assert.strictEqual(appVersions.get('elixir'), elixir)

const absoluteFilename = path.join(os.tmpdir(), '.tool-versions')
fs.writeFileSync(absoluteFilename, toolVersions)

process.env.GITHUB_WORKSPACE = process.cwd()
const absoluteAppVersions = setupBeam.parseVersionFile(absoluteFilename)
const absoluteAppVersions = setupBeam.parseVersionFile(
absoluteFilename,
'.tool-versions',
)
assert.strictEqual(absoluteAppVersions.get('erlang'), erlang)
assert.strictEqual(absoluteAppVersions.get('elixir'), elixir)

assert.ok(async () => {
await setupBeam.install('otp', { toolVersion: erlang })
})
assert.ok(async () => {
await setupBeam.install('elixir', { toolVersion: elixir })
})
assert.ok(async () => {
await setupBeam.install('gleam', { toolVersion: gleam })
})
})

simulateInput('otp-version', otpVersion)
simulateInput('elixir-version', elixirVersion)
simulateInput('gleam-version', gleamVersion)
})

describe('mise.toml file', () => {
const otpVersion = unsimulateInput('otp-version')
const elixirVersion = unsimulateInput('elixir-version')
const gleamVersion = unsimulateInput('gleam-version')

it('is parsed correctly', async () => {
const erlang = '27.3.4.1'
const elixir = '1.18.4'
const gleam = '1.9.1'
let miseToml = `[tools]
"erlang" = "${erlang}"
elixir = { version = "${elixir}", postinstall="mix deps.get" } # comment, with space and ref:
"not-gleam" = 0.23 # not picked up
"gleam" = "${gleam}" \n`
const filename = 'test/mise.toml'
if (process.platform === 'win32') {
// Force \r\n to test in Windows
miseToml = miseToml.replace(/\n/g, '\r\n')
}
fs.writeFileSync(filename, miseToml)
process.env.GITHUB_WORKSPACE = ''
const appVersions = setupBeam.parseVersionFile(filename, 'mise.toml')
assert.strictEqual(appVersions.get('erlang'), erlang)
assert.strictEqual(appVersions.get('elixir'), elixir)

const absoluteFilename = path.join(os.tmpdir(), 'mise.toml')
fs.writeFileSync(absoluteFilename, miseToml)

process.env.GITHUB_WORKSPACE = process.cwd()
const absoluteAppVersions = setupBeam.parseVersionFile(
absoluteFilename,
'mise.toml',
)
assert.strictEqual(absoluteAppVersions.get('erlang'), erlang)
assert.strictEqual(absoluteAppVersions.get('elixir'), elixir)

Expand Down