feat: output active tool versions after installation

Add outputs for active tool versions to eliminate the need for wrapper
steps to extract version information for cache keys.

New outputs:
- Individual tool outputs (e.g., steps.mise.outputs.bun = "1.0.0")
- versions: JSON object with all active tools and full metadata

Closes #448
This commit is contained in:
Jorge Rodriguez 2026-04-21 15:07:44 +02:00
parent db69447ab3
commit 3ae98ac76a
No known key found for this signature in database
GPG key ID: A22D46F0D97D588A
6 changed files with 197 additions and 1 deletions

View file

@ -147,6 +147,50 @@ jobs:
- run: which jq
- run: jq --version
version_outputs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Setup mise
id: mise
uses: ./
with:
cache: false
mise_toml: |
[tools]
jq = "1.7.1"
bun = "1.2.0"
- name: Verify individual tool outputs
run: |
echo "jq version: ${{ steps.mise.outputs.jq }}"
echo "bun version: ${{ steps.mise.outputs.bun }}"
if [ -z "${{ steps.mise.outputs.jq }}" ]; then
echo "ERROR: jq output is empty"
exit 1
fi
if [ -z "${{ steps.mise.outputs.bun }}" ]; then
echo "ERROR: bun output is empty"
exit 1
fi
echo "Individual tool outputs verified successfully"
- name: Verify versions JSON output
run: |
echo "versions JSON: ${{ steps.mise.outputs.versions }}"
# Parse and validate JSON structure
echo '${{ steps.mise.outputs.versions }}' | jq -e '.jq.version' > /dev/null
echo '${{ steps.mise.outputs.versions }}' | jq -e '.bun.version' > /dev/null
echo "versions JSON output verified successfully"
- name: Use version output in cache key (simulation)
run: |
# Simulate using the version output in a cache key
CACHE_KEY="bun-cache-linux-${{ steps.mise.outputs.bun }}"
echo "Generated cache key: $CACHE_KEY"
if [[ "$CACHE_KEY" != *"1.2.0"* ]]; then
echo "ERROR: Cache key does not contain expected version"
exit 1
fi
echo "Cache key simulation successful"
final:
needs:
- build
@ -155,6 +199,7 @@ jobs:
- checksum_failure
- custom_cache_key
- fetch_from_github
- version_outputs
runs-on: ubuntu-latest
timeout-minutes: 1
if: always()

View file

@ -94,6 +94,58 @@ You can also extend the default cache key:
This gives you full control over cache invalidation based on the specific aspects that matter to your workflow.
## Outputs
The action provides the following outputs:
| Output | Description |
|--------|-------------|
| `cache-hit` | Boolean indicating if the cache was restored |
| `versions` | JSON object with all active tool versions and metadata |
| `<tool-name>` | Version string for each active tool (e.g., `bun`, `node`, `python`) |
### Using Tool Version Outputs
After mise installs tools, you can access the resolved versions directly without needing a separate step:
```yaml
- name: Setup tools with Mise
id: mise
uses: jdx/mise-action@v4
# Access individual tool versions directly
- name: Cache bun
uses: actions/cache@v5
with:
path: ~/.bun/install/cache
key: bun-cache-${{ runner.os }}-${{ steps.mise.outputs.bun }}-${{ hashFiles('**/bun.lock') }}
# Or use the full versions JSON for complex scenarios
- name: Show all versions
run: echo '${{ steps.mise.outputs.versions }}'
```
The `versions` output contains full metadata for each active tool:
```json
{
"bun": {
"version": "1.0.0",
"requested_version": "latest",
"install_path": "/home/runner/.local/share/mise/installs/bun/1.0.0",
"source": {
"type": "mise.toml",
"path": "/home/runner/work/repo/mise.toml"
}
},
"node": {
"version": "20.10.0",
"requested_version": "20",
"install_path": "/home/runner/.local/share/mise/installs/node/20.10.0"
}
}
```
## GitHub API Rate Limits
When installing tools hosted on GitHub (like `gh`, `node`, `bun`, etc.), mise needs to make API calls to GitHub's releases API. Without authentication, these calls are subject to GitHub's rate limit of 60 requests per hour, which can cause installation failures.

View file

@ -88,6 +88,8 @@ inputs:
outputs:
cache-hit:
description: A boolean value to indicate if a cache was hit.
versions:
description: JSON object containing all active tool versions with metadata (version, requested_version, install_path, source).
runs:
using: node24
main: dist/index.js

34
dist/index.js generated vendored
View file

@ -84859,6 +84859,7 @@ async function run() {
await testMise();
if (getBooleanInput('install')) {
await miseInstall();
await outputToolVersions();
if (cacheKey && getBooleanInput('cache_save')) {
await saveCache(cacheKey);
}
@ -84921,6 +84922,39 @@ async function exportMiseEnv() {
}
endGroup();
}
async function outputToolVersions() {
startGroup('Outputting tool versions');
const cwd = getCwd();
try {
const output = await getExecOutput('mise', ['ls', '--json'], {
cwd,
silent: true
});
const tools = JSON.parse(output.stdout);
const activeVersions = {};
for (const [toolName, versions] of Object.entries(tools)) {
const activeVersion = versions.find(v => v.active);
if (activeVersion) {
// Set individual output: steps.mise.outputs.bun = "1.0.0"
setOutput(toolName, activeVersion.version);
info(`${toolName}: ${activeVersion.version}`);
// Collect for JSON output with full metadata
activeVersions[toolName] = {
version: activeVersion.version,
requested_version: activeVersion.requested_version,
install_path: activeVersion.install_path,
source: activeVersion.source
};
}
}
// Set JSON output with all active versions
setOutput('versions', JSON.stringify(activeVersions));
}
catch (error) {
warning(`Failed to output tool versions: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
endGroup();
}
function cleanVersion(version) {
// remove 'v' prefix if present
return version.replace(/^v/, '');

2
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long

View file

@ -64,6 +64,7 @@ async function run(): Promise<void> {
await testMise()
if (core.getBooleanInput('install')) {
await miseInstall()
await outputToolVersions()
if (cacheKey && core.getBooleanInput('cache_save')) {
await saveCache(cacheKey)
}
@ -134,6 +135,68 @@ async function exportMiseEnv(): Promise<void> {
core.endGroup()
}
interface ToolSource {
type: string
path: string
}
interface ToolInfo {
version: string
requested_version?: string
install_path: string
source?: ToolSource
installed: boolean
active: boolean
}
interface ToolVersionOutput {
version: string
requested_version?: string
install_path: string
source?: ToolSource
}
async function outputToolVersions(): Promise<void> {
core.startGroup('Outputting tool versions')
const cwd = getCwd()
try {
const output = await exec.getExecOutput('mise', ['ls', '--json'], {
cwd,
silent: true
})
const tools: Record<string, ToolInfo[]> = JSON.parse(output.stdout)
const activeVersions: Record<string, ToolVersionOutput> = {}
for (const [toolName, versions] of Object.entries(tools)) {
const activeVersion = versions.find(v => v.active)
if (activeVersion) {
// Set individual output: steps.mise.outputs.bun = "1.0.0"
core.setOutput(toolName, activeVersion.version)
core.info(`${toolName}: ${activeVersion.version}`)
// Collect for JSON output with full metadata
activeVersions[toolName] = {
version: activeVersion.version,
requested_version: activeVersion.requested_version,
install_path: activeVersion.install_path,
source: activeVersion.source
}
}
}
// Set JSON output with all active versions
core.setOutput('versions', JSON.stringify(activeVersions))
} catch (error) {
core.warning(
`Failed to output tool versions: ${error instanceof Error ? error.message : 'Unknown error'}`
)
}
core.endGroup()
}
function cleanVersion(version: string) {
// remove 'v' prefix if present
return version.replace(/^v/, '')