Skip to content
Merged
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
64 changes: 64 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,69 @@
# Changelog

## [2026.6.12](https://github.com/jdx/mise/compare/v2026.6.11..v2026.6.12) - 2026-06-21

### 🚀 Features

- **(bootstrap)** add skip controls by @jdx in [#10497](https://github.com/jdx/mise/pull/10497)
- **(http)** resolve cross-platform lock checksums from published metadata by @itochan in [#10509](https://github.com/jdx/mise/pull/10509)
- **(upgrade)** fix tool removal when minimum_release_age is set by @roele in [#10466](https://github.com/jdx/mise/pull/10466)

### 🐛 Bug Fixes

- **(aqua)** support checksum verification fields by @risu729 in [#10473](https://github.com/jdx/mise/pull/10473)
- **(backend)** resolve dependency executables on Windows by @risu729 in [#10514](https://github.com/jdx/mise/pull/10514)
- **(env)** expand escaped dollar in env shell expansion by @jdx in [#10511](https://github.com/jdx/mise/pull/10511)
- **(install)** rebuild symlinks after partial installs by @risu729 in [#10470](https://github.com/jdx/mise/pull/10470)
- **(npm)** warn when system pnpm/bun may not support minimum_release_age by @risu729 in [#10491](https://github.com/jdx/mise/pull/10491)
- **(pipx)** upgrade shared pip for release age installs by @risu729 in [#10472](https://github.com/jdx/mise/pull/10472)
- **(pipx)** warn for unsupported uv exclude-newer by @risu729 in [#10510](https://github.com/jdx/mise/pull/10510)
- **(pipx)** force pip backend for mise pipx subprocess calls by @risu729 in [#10513](https://github.com/jdx/mise/pull/10513)
- **(system)** drop bare -- from dnf argv (breaks DNF5 install/upgrade) by @spencergilbert in [#10538](https://github.com/jdx/mise/pull/10538)
- **(task)** align duplicate config task precedence by @risu729 in [#10471](https://github.com/jdx/mise/pull/10471)
- **(task)** skip mise configs in task include dirs by @jdx in [#10500](https://github.com/jdx/mise/pull/10500)
- **(task)** error on empty task shell by @jdx in [#10517](https://github.com/jdx/mise/pull/10517)
- **(task)** honor show_full_cmd in the task command header by @JamBalaya56562 in [#10518](https://github.com/jdx/mise/pull/10518)
- **(vfox)** resolve tools=true env path templates against the dependency toolset by @JamBalaya56562 in [#10481](https://github.com/jdx/mise/pull/10481)

### 📚 Documentation

- **(dotfiles)** make self-managing config first-run safe by @jdx in [#10494](https://github.com/jdx/mise/pull/10494)
- **(env)** remove emoji checkboxes by @jdx in [#10504](https://github.com/jdx/mise/pull/10504)
- recommend keeping mise current by @jdx in [#10505](https://github.com/jdx/mise/pull/10505)

### 📦️ Dependency Updates

- bump usage to 3.5.2 by @jdx in [#10498](https://github.com/jdx/mise/pull/10498)
- update ghcr.io/jdx/mise:rpm docker digest to b5e0574 by @renovate[bot] in [#10531](https://github.com/jdx/mise/pull/10531)
- update ghcr.io/jdx/mise:alpine docker digest to 892c324 by @renovate[bot] in [#10529](https://github.com/jdx/mise/pull/10529)
- update jdx/mise-action digest to e6a8b39 by @renovate[bot] in [#10532](https://github.com/jdx/mise/pull/10532)
- update rust docker digest to c681116 by @renovate[bot] in [#10533](https://github.com/jdx/mise/pull/10533)
- update ubuntu:26.04 docker digest to e153663 by @renovate[bot] in [#10534](https://github.com/jdx/mise/pull/10534)
- update ghcr.io/jdx/mise:deb docker digest to 3d636fa by @renovate[bot] in [#10530](https://github.com/jdx/mise/pull/10530)
- update dependency esbuild to v0.28.1 by @renovate[bot] in [#10535](https://github.com/jdx/mise/pull/10535)
- update ubuntu:26.04 docker digest to 53958ec by @renovate[bot] in [#10539](https://github.com/jdx/mise/pull/10539)

### 📦 Registry

- add aspire ([github:microsoft/aspire](https://github.com/microsoft/aspire)) by @davidfowl in [#10520](https://github.com/jdx/mise/pull/10520)
- add nub by @colinhacks in [#10544](https://github.com/jdx/mise/pull/10544)
- add ldc ([github:ldc-developers/ldc](https://github.com/ldc-developers/ldc)) by @slbls in [#10527](https://github.com/jdx/mise/pull/10527)
- relax checkov test by @jdx in [#10548](https://github.com/jdx/mise/pull/10548)

### New Contributors

- @spencergilbert made their first contribution in [#10538](https://github.com/jdx/mise/pull/10538)
- @slbls made their first contribution in [#10527](https://github.com/jdx/mise/pull/10527)
- @colinhacks made their first contribution in [#10544](https://github.com/jdx/mise/pull/10544)
- @davidfowl made their first contribution in [#10520](https://github.com/jdx/mise/pull/10520)

### 📦 Aqua Registry Updates

#### New Packages (2)

- [`EpicGames/lore`](https://github.com/EpicGames/lore)
- [`cdxgen/cdxgen`](https://github.com/cdxgen/cdxgen)

## [2026.6.11](https://github.com/jdx/mise/compare/v2026.6.10..v2026.6.11) - 2026-06-16

### 🚀 Features
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ members = [

[package]
name = "mise"
version = "2026.6.11"
version = "2026.6.12"
edition = "2024"
description = "Dev tools, env vars, and tasks in one CLI"
authors = ["Jeff Dickey (@jdx)"]
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ $ ~/.local/bin/mise --version
/ / / / / / (__ ) __/_____/ __/ / / /_____/ /_/ / / /_/ / /__/ __/
/_/ /_/ /_/_/____/\___/ \___/_/ /_/ / .___/_/\__,_/\___/\___/
/_/ by @jdx
2026.6.11 macos-arm64 (2026-06-16)
2026.6.12 macos-arm64 (2026-06-21)
```

Hook mise into your shell (pick the right one for your shell):
Expand Down
2 changes: 1 addition & 1 deletion completions/_mise
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ _mise() {
return 1
fi

local spec_file="${TMPDIR:-/tmp}/usage__usage_spec_mise_2026_6_11.spec"
local spec_file="${TMPDIR:-/tmp}/usage__usage_spec_mise_2026_6_12.spec"
if [[ ! -f "$spec_file" ]]; then
mise usage >| "$spec_file"
fi
Expand Down
2 changes: 1 addition & 1 deletion completions/mise.bash
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ _mise() {

local cur prev words cword was_split comp_args
_comp_initialize -n : -- "$@" || return
local spec_file="${TMPDIR:-/tmp}/usage__usage_spec_mise_2026_6_11.spec"
local spec_file="${TMPDIR:-/tmp}/usage__usage_spec_mise_2026_6_12.spec"
if [[ ! -f "$spec_file" ]]; then
mise usage >| "$spec_file"
fi
Expand Down
2 changes: 1 addition & 1 deletion completions/mise.fish
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ if ! type -p usage &> /dev/null
return 1
end
set -l tmpdir (if set -q TMPDIR; echo $TMPDIR; else; echo /tmp; end)
set -l spec_file "$tmpdir/usage__usage_spec_mise_2026_6_11.spec"
set -l spec_file "$tmpdir/usage__usage_spec_mise_2026_6_12.spec"
if not test -f "$spec_file"
mise usage | string collect > "$spec_file"
end
Expand Down
2 changes: 1 addition & 1 deletion completions/mise.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Register-ArgumentCompleter -Native -CommandName 'mise' -ScriptBlock {
param($wordToComplete, $commandAst, $cursorPosition)

$tmpDir = if ($env:TEMP) { $env:TEMP } else { [System.IO.Path]::GetTempPath() }
$specFile = Join-Path $tmpDir "usage__usage_spec_mise_2026_6_11.kdl"
$specFile = Join-Path $tmpDir "usage__usage_spec_mise_2026_6_12.kdl"

if (-not (Test-Path $specFile)) {
mise usage | Out-File -FilePath $specFile -Encoding utf8
Expand Down
2 changes: 1 addition & 1 deletion default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

rustPlatform.buildRustPackage {
pname = "mise";
version = "2026.6.11";
version = "2026.6.12";

src = lib.cleanSource ./.;

Expand Down
2 changes: 1 addition & 1 deletion docs/.vitepress/stars.data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
export default {
load() {
return {
stars: "29.5k",
stars: "29.8k",
};
},
};
4 changes: 2 additions & 2 deletions docs/bootstrap/systemd.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ and enable without keeping the unit running.
- **User services only** — mise writes to `~/.config/systemd/user` and uses
`systemctl --user`. System services in `/etc/systemd/system` are not
supported.
- **Target user only** — run mise as the user that owns the services, with an
active systemd user bus. `sudo mise` is skipped because `systemctl --user`
- **Target user only** — run mise as the user who owns the services, with a
reachable systemd user manager. `sudo mise` is skipped because `systemctl --user`
would target the wrong user manager.
- **Manual application only** — mise never writes or starts systemd services
implicitly; only `mise bootstrap systemd apply` and `mise bootstrap` do.
Expand Down
66 changes: 66 additions & 0 deletions docs/dev-tools/backends/http.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,72 @@ linux-x64 = {
}
```

### `checksum_url`

URL of a published checksum source. When set, [`mise lock`](/dev-tools/mise-lock)
resolves checksums for every target platform — including platforms other than
the one you are running on — **without downloading the artifacts**. This lets a
single machine produce a complete, cross-platform lockfile.

`checksum_url` is a template (supports <code v-pre>{{ version }}</code>, <code v-pre>{{ os() }}</code>, <code v-pre>{{ arch() }}</code>
and is platform-specific via `platforms.<key>.checksum_url`). It may point at any
of:

- an **individual checksum file** (e.g. `<artifact>.sha256`), which may contain
just the hash or `<hash> <filename>`;
- a **SHASUMS**-style file listing `<hash> <filename>` for many platforms (the row
is matched by the artifact's filename);
- a **manifest** (e.g. JSON), combined with `checksum_expr` below.

For individual and SHASUMS checksum files, the algorithm is detected from the
file's name (`*.sha512`, `SHA512SUMS`, `*.md5`, `*.b3`, defaulting to sha256).

```toml
# Individual checksum file (one per artifact)
[tools."http:my-tool"]
version = "1.0.0"
url = "https://example.com/releases/my-tool-{{ version }}-{{ os() }}-{{ arch() }}.tar.gz"
checksum_url = "https://example.com/releases/my-tool-{{ version }}-{{ os() }}-{{ arch() }}.tar.gz.sha256"

# SHASUMS (one file lists every platform)
[tools."http:other-tool"]
version = "1.0.0"
url = 'https://example.com/{{ version }}/other_{{ version }}_{{ os(macos="darwin") }}_{{ arch(x64="amd64") }}.zip'
checksum_url = 'https://example.com/{{ version }}/other_{{ version }}_SHASUMS'
```

### `checksum_expr`

When the checksum lives in a manifest (rather than a plain checksum file), use
`checksum_expr` to extract it. The manifest body fetched from `checksum_url` is
evaluated with [expr-lang](https://expr-lang.org). The following variables are
available: `body` (the raw manifest), `version`, `os`, `arch`, `url` (the
resolved artifact URL for the target), and `filename`.

The expression must evaluate to a qualified `algo:hash` **string** (e.g.
`sha256:<hash>`, `sha512:<hash>`). Build the prefix in the expression: prepend a
literal when the algorithm is fixed (`"sha256:" + entry.hash`), or read it from
the manifest when it varies (`entry.algo + ":" + entry.hash`).

```toml
[tools."http:my-tool"]
version = "1.10.0"
checksum_url = "https://example.com/versions.json"
# Match the file whose url equals the resolved artifact url, return sha256:<hash>
checksum_expr = '"sha256:" + filter(fromJSON(body)[version + ""].files, { #.url == url })[0].sha256'

[tools."http:my-tool".platforms]
linux-x64 = { url = "https://example.com/my-tool-{{ version }}-linux-x86_64.tar.gz" }
macos-arm64 = { url = "https://example.com/my-tool-{{ version }}-macos-arm64.tar.gz" }
```

::: tip expr-lang gotchas
The predicate placeholder must be written as `{ #... }` **with a space** after
`{`, because `{#` is the Tera comment delimiter. To index a map by a runtime
value, force evaluation with `[version + ""]` — a bare `[version]` is treated as
the literal key `"version"`.
:::

### `size`

Verify the downloaded file size:
Expand Down
110 changes: 110 additions & 0 deletions e2e/backend/test_http_lock_checksum
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/usr/bin/env bash

# Cross-platform `mise lock` for the http backend resolves published checksums
# for platforms other than the host, without downloading artifacts. Covers the
# SHASUMS form (matched by filename) and the individual checksum file form, with
# os()/arch() in the url rendered per target platform.

SRV="$PWD/srv"
mkdir -p "$SRV"

# sha256 of each artifact's bytes (the string written below).
LINUX_SHA="ae26b73f6db848ed1ccb7c35ec59234cd74ecf9d344f422732058df5be2e6a01" # "tool linux payload"
MACOS_SHA="40a3a5cdad86d4833b06b463da7f294fae29b61298aeb729e4e9dbf5e45ba4af" # "tool macos payload"
FILE_LINUX_SHA="508f35a45c1c4869a5949ec3d96779237619c36b7a6b51f6a83400de9fc5b01e" # "individual linux payload"
FILE_MACOS_SHA="f4fbe0d002f0331efc717160d7ea559c0f1172685d454aac59c12c1379d2cc49" # "individual macos payload"
# sha512 (128 hex chars) of "tool512 linux payload" — algorithm detected from the file name
SHA512_LINUX="78b83c1f3aa14cfa6c5a551a92d90c147b3c029304429d96bc86560e0f08fc9cf69c343c2dc52fec0d7c7bceee894bb5647d4f3e3359816b231dafaee8799363"

printf '%s' "tool linux payload" >"$SRV/tool_1.0.0_linux.tar.gz"
printf '%s' "tool macos payload" >"$SRV/tool_1.0.0_macos.tar.gz"
printf '%s' "individual linux payload" >"$SRV/file_1.0.0_linux.tar.gz"
printf '%s' "individual macos payload" >"$SRV/file_1.0.0_macos.tar.gz"
printf '%s' "tool512 linux payload" >"$SRV/tool512_1.0.0_linux.tar.gz"

# SHASUMS file listing both platform artifacts (HashiCorp/OpenShift style)
cat >"$SRV/tool_1.0.0_SHASUMS" <<EOF
${LINUX_SHA} tool_1.0.0_linux.tar.gz
${MACOS_SHA} tool_1.0.0_macos.tar.gz
EOF

# A sha512 SHASUMS: the algorithm is inferred from the file name (SHA512SUMS)
cat >"$SRV/tool512_1.0.0_SHA512SUMS" <<EOF
${SHA512_LINUX} tool512_1.0.0_linux.tar.gz
EOF

# Individual checksum files (neo4j/dart style): just the raw hash per artifact
echo "$FILE_LINUX_SHA" >"$SRV/file_1.0.0_linux.tar.gz.sha256"
echo "$FILE_MACOS_SHA" >"$SRV/file_1.0.0_macos.tar.gz.sha256"

# A SHASUMS list whose entries don't match this tool's artifact name (a naming
# mismatch). Locking must NOT fall back to the first hash in the list and
# silently write another artifact's checksum.
BOGUS_SHA="1111111111111111111111111111111111111111111111111111111111111111"
cat >"$SRV/mismatch_1.0.0_SHASUMS" <<EOF
${BOGUS_SHA} someothertool_1.0.0_linux.tar.gz
EOF

# Start a static file server on an ephemeral port
PORT_FILE="$TMPDIR/mise_lock_http_port"
python3 - "$SRV" "$PORT_FILE" <<'PY' &
import http.server, socketserver, sys, os
srv, port_file = sys.argv[1], sys.argv[2]
os.chdir(srv)
socketserver.TCPServer.allow_reuse_address = True
with socketserver.TCPServer(("127.0.0.1", 0), http.server.SimpleHTTPRequestHandler) as httpd:
with open(port_file, "w") as f:
f.write(str(httpd.server_address[1]))
httpd.serve_forever()
PY
SERVER_PID=$!
cleanup() { kill "$SERVER_PID" 2>/dev/null || true; }
trap cleanup EXIT

wait_for_file "$PORT_FILE" "lock http port file" 30 "$SERVER_PID"
PORT=$(cat "$PORT_FILE")

cat >mise.toml <<EOF
[tools."http:xplat-shasums"]
version = "1.0.0"
url = "http://127.0.0.1:${PORT}/tool_{{ version }}_{{ os() }}.tar.gz"
checksum_url = "http://127.0.0.1:${PORT}/tool_{{ version }}_SHASUMS"

[tools."http:xplat-file"]
version = "1.0.0"
url = "http://127.0.0.1:${PORT}/file_{{ version }}_{{ os() }}.tar.gz"
checksum_url = "http://127.0.0.1:${PORT}/file_{{ version }}_{{ os() }}.tar.gz.sha256"

[tools."http:xplat-sha512"]
version = "1.0.0"
url = "http://127.0.0.1:${PORT}/tool512_{{ version }}_{{ os() }}.tar.gz"
checksum_url = "http://127.0.0.1:${PORT}/tool512_{{ version }}_SHA512SUMS"

[tools."http:xplat-shasums-mismatch"]
version = "1.0.0"
url = "http://127.0.0.1:${PORT}/mismatch_{{ version }}_{{ os() }}.tar.gz"
checksum_url = "http://127.0.0.1:${PORT}/mismatch_{{ version }}_SHASUMS"
EOF

mise lock --platform linux-x64,macos-x64

# sha512 SHASUMS: algorithm detected from the file name, labeled sha512:
assert_contains "cat mise.lock" "sha512:${SHA512_LINUX}"

# SHASUMS form: each target platform gets its own filename-matched checksum
assert_contains "cat mise.lock" "sha256:${LINUX_SHA}"
assert_contains "cat mise.lock" "sha256:${MACOS_SHA}"
# url() is rendered per target platform, not the host
assert_contains "cat mise.lock" "tool_1.0.0_linux.tar.gz"
assert_contains "cat mise.lock" "tool_1.0.0_macos.tar.gz"

# Individual checksum file form: raw-hash file resolved per platform
assert_contains "cat mise.lock" "sha256:${FILE_LINUX_SHA}"
assert_contains "cat mise.lock" "sha256:${FILE_MACOS_SHA}"
assert_contains "cat mise.lock" "file_1.0.0_linux.tar.gz"
assert_contains "cat mise.lock" "file_1.0.0_macos.tar.gz"

# SHASUMS naming mismatch: a url-only entry is written, and the unrelated first
# hash from the list is never locked as this artifact's checksum.
assert_contains "cat mise.lock" "mismatch_1.0.0_linux.tar.gz"
assert_not_contains "cat mise.lock" "$BOGUS_SHA"
Loading
Loading