Skip to content
Open
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
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,23 @@ Acceptable values are latest or any semantic version string like v3.5.0 Use this
id: install
```

Alternatively, the version can be read from a [`.tool-versions`](https://asdf-vm.com/manage/configuration.html) file (the format used by [asdf](https://asdf-vm.com/) and [mise](https://mise.jdx.dev/)) via the `version-file` input:

```yaml
- uses: azure/setup-helm@v5.0.0
with:
version-file: .tool-versions
id: install
```

The action reads the version declared for the `helm` tool, for example:

```
helm 3.18.4
```

If both `version` and `version-file` are set, `version` takes precedence.

> [!NOTE]
> If something goes wrong with fetching the latest version the action will use the hardcoded default version (currently v3.18.3). If you rely on a certain version higher than the default, you should explicitly use that version instead of latest.

Expand Down
5 changes: 4 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ description: 'Install a specific version of helm binary. Acceptable values are l
inputs:
version:
description: 'Version of helm'
required: true
required: false
default: 'latest'
version-file:
description: 'Path to a .tool-versions file to read the helm version from'
required: false
token:
description: GitHub token. Used to be required to fetch the latest version
required: false
Expand Down
50 changes: 49 additions & 1 deletion src/run.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ vi.mock('fs', async (importOriginal) => {
readdirSync: vi.fn(),
statSync: vi.fn(),
chmodSync: vi.fn(),
readFileSync: vi.fn()
readFileSync: vi.fn(),
existsSync: vi.fn()
}
})

Expand Down Expand Up @@ -161,6 +162,53 @@ describe('run.ts', () => {
expect(run.getValidVersion('3.8.0')).toBe('v3.8.0')
})

test('parseToolVersions() - return the helm version from .tool-versions content', () => {
const content = ['nodejs 20.11.0', 'helm 3.14.0', 'terraform 1.7.0'].join(
'\n'
)
expect(run.parseToolVersions(content)).toBe('3.14.0')
})

test('parseToolVersions() - ignore comments and blank lines', () => {
const content = ['# tools', '', ' helm 3.15.2 ', ''].join('\n')
expect(run.parseToolVersions(content)).toBe('3.15.2')
})

test('parseToolVersions() - return the first version when several are listed', () => {
expect(run.parseToolVersions('helm 3.14.0 3.13.0')).toBe('3.14.0')
})

test('parseToolVersions() - return empty string when helm is not declared', () => {
expect(run.parseToolVersions('nodejs 20.11.0')).toBe('')
})

test('getVersionFromToolVersionsFile() - read the helm version from a file', () => {
vi.mocked(fs.existsSync).mockReturnValue(true)
vi.mocked(fs.readFileSync).mockReturnValue('helm 3.14.0')

expect(run.getVersionFromToolVersionsFile('.tool-versions')).toBe(
'3.14.0'
)
expect(fs.readFileSync).toHaveBeenCalledWith('.tool-versions', 'utf8')
})

test('getVersionFromToolVersionsFile() - throw when the file does not exist', () => {
vi.mocked(fs.existsSync).mockReturnValue(false)

expect(() =>
run.getVersionFromToolVersionsFile('missing.tool-versions')
).toThrow("The version-file 'missing.tool-versions' does not exist")
})

test('getVersionFromToolVersionsFile() - throw when no helm version is present', () => {
vi.mocked(fs.existsSync).mockReturnValue(true)
vi.mocked(fs.readFileSync).mockReturnValue('nodejs 20.11.0')

expect(() =>
run.getVersionFromToolVersionsFile('.tool-versions')
).toThrow("No helm version found in '.tool-versions'")
})

test('walkSync() - return path to the all files matching fileToFind in dir', () => {
vi.mocked(fs.readdirSync).mockImplementation((file, _?) => {
if (file == 'mainFolder')
Expand Down
48 changes: 47 additions & 1 deletion src/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,23 @@ const helmToolName = 'helm'
export const stableHelmVersion = 'v3.18.4'

export async function run() {
let version = core.getInput('version', {required: true})
let version = core.getInput('version')
const versionFile = core.getInput('version-file')

if (versionFile) {
if (version && version !== 'latest') {
core.warning(
`Both 'version' and 'version-file' inputs are specified, only 'version' will be used.`
)
} else {
version = getVersionFromToolVersionsFile(versionFile)
core.info(`Resolved Helm version '${version}' from '${versionFile}'`)
}
}

if (!version) {
version = 'latest'
}

if (version !== 'latest' && version[0] !== 'v') {
core.info('Getting latest Helm version')
Expand Down Expand Up @@ -46,6 +62,36 @@ export function getValidVersion(version: string): string {
return 'v' + version
}

// Reads a .tool-versions file and returns the helm version declared in it
export function getVersionFromToolVersionsFile(filePath: string): string {
if (!fs.existsSync(filePath)) {
throw new Error(`The version-file '${filePath}' does not exist`)
}
const content = fs.readFileSync(filePath, 'utf8')
const version = parseToolVersions(content)
if (!version) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can we add a semver-shape regex check here for the helm version?

throw new Error(`No helm version found in '${filePath}'`)
}
return version
}

// Parses .tool-versions content (asdf/mise format) and returns the first
// helm version, or an empty string when none is declared. Lines look like
// `helm 3.14.0`; comments (#) and blank lines are ignored.
export function parseToolVersions(content: string): string {
for (const line of content.split(/\r?\n/)) {
const trimmed = line.trim()
if (!trimmed || trimmed.startsWith('#')) {
continue
}
const [tool, version] = trimmed.split(/\s+/)
if (tool === helmToolName && version) {
return version
}
}
return ''
}

// Gets the latest helm version or returns a default stable if getting latest fails
export async function getLatestHelmVersion(): Promise<string> {
try {
Expand Down
Loading