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
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,27 @@ Acceptable values are latest or any semantic version string like `v1.15.0`. Use
id: install
```

Alternatively, read the kubectl version from an
[asdf/mise `.tool-versions` file](https://asdf-vm.com/manage/configuration.html):

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

The kubectl entry may use `major.minor`, `major.minor.patch`, an optional `v`
prefix, or `latest`:

```text
kubectl 1.31.2
```

When both inputs are set, a specific `version` other than `latest` takes
precedence and the action emits a warning. The default `version: latest` allows
`version-file` to select the version.

Refer to the action metadata file for details about all the inputs https://github.com/Azure/setup-kubectl/blob/main/action.yml

# Contributing
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 kubectl binary. Acceptable values ar
inputs:
version:
description: 'Version of kubectl'
required: true
required: false
default: 'latest'
version-file:
description: 'Path to a .tool-versions (asdf/mise) file to read the kubectl version from. A specific version other than latest takes precedence.'
required: false
downloadBaseURL:
description: 'Base URL to download kubectl from (https only). Use for private mirrors.'
required: false
Expand Down
69 changes: 69 additions & 0 deletions src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,3 +304,72 @@ export function getExecutableExtension(): string {
}
return ''
}

export function parseToolVersionsFile(filePath: string): string {
const maxBytes = 64 * 1024
const pathStats = fs.lstatSync(filePath, {bigint: true})
if (pathStats.isSymbolicLink() || !pathStats.isFile()) {
throw new Error(
`The version-file '${filePath}' must be a regular file and not a symbolic link.`
)
}
if (pathStats.size > BigInt(maxBytes)) {
throw new Error(
`The version-file '${filePath}' exceeds the ${maxBytes}-byte size limit.`
)
}

const noFollow = fs.constants.O_NOFOLLOW ?? 0
// A FIFO swapped in after lstat must not block open before fstat can reject it.
// O_NONBLOCK has no effect on regular files; these flags are POSIX-only.
const nonBlock = fs.constants.O_NONBLOCK ?? 0
const fd = fs.openSync(filePath, fs.constants.O_RDONLY | noFollow | nonBlock)
let content: string
try {
const fileStats = fs.fstatSync(fd, {bigint: true})
if (!fileStats.isFile()) {
throw new Error(
`The version-file '${filePath}' must be a regular file and not a symbolic link.`
)
}
if (pathStats.dev !== fileStats.dev || pathStats.ino !== fileStats.ino) {
throw new Error(
`The version-file '${filePath}' changed while it was being opened.`
)
}

const buffer = Buffer.alloc(maxBytes + 1)
let bytesRead = 0
while (bytesRead < buffer.length) {
const count = fs.readSync(
fd,
buffer,
bytesRead,
buffer.length - bytesRead,
null
)
if (count === 0) break
bytesRead += count
}
if (bytesRead > maxBytes) {
throw new Error(
`The version-file '${filePath}' exceeds the ${maxBytes}-byte size limit.`
)
}
content = buffer.toString('utf8', 0, bytesRead)
} finally {
fs.closeSync(fd)
}

for (const line of content.split('\n')) {
const trimmed = line.trim()
if (trimmed.startsWith('#') || trimmed === '') continue
const [tool, version] = trimmed.split(/\s+/)
if (tool === 'kubectl' && version) {
return version
}
}
throw new Error(
`Could not find a kubectl entry in tool-versions file: ${filePath}`
)
}
Loading