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
36 changes: 36 additions & 0 deletions bin/omarchy-update-mise
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,45 @@

# omarchy:summary=Update mise-managed tools

retarget_iso_node_pin() {
local config_file="${MISE_CONFIG_FILE:-$HOME/.config/mise/config.toml}"
local package_dir="${OMARCHY_PROVISIONING_PACKAGES_DIR:-/var/lib/omarchy/provisioning/packages}"
local state_dir="${XDG_STATE_HOME:-$HOME/.local/state}/omarchy"
local migrated_marker="$state_dir/iso-node-mise-policy-migrated"
local bundled_tarball=""
local node_version=""

[[ -f $migrated_marker || ! -f $config_file || ! -d $package_dir ]] && return 0

bundled_tarball=$(find "$package_dir" -maxdepth 1 -type f -name 'node-v*-linux-x64.tar.gz' -print -quit 2>/dev/null)
[[ -n $bundled_tarball ]] || return 0

node_version=$(sed -nE 's/^[[:space:]]*node[[:space:]]*=[[:space:]]*"([0-9]+\.[0-9]+\.[0-9]+)"[[:space:]]*$/\1/p' "$config_file" | head -n1)

if [[ -n $node_version && -f $package_dir/node-v${node_version}-linux-x64.tar.gz ]]; then
echo "Retarget bundled ISO Node $node_version to latest"
if ! mise use -g node@latest; then
echo "Warning: could not retarget the bundled Node pin yet; will retry on the next update" >&2
return 0
fi
fi

# The provisioning package directory is retained after first boot. Once this
# machine has passed through the policy check, never reinterpret a later
# user-authored exact Node pin as an ISO pin just because it matches that old
# bundled tarball.
mkdir -p "$state_dir"
: >"$migrated_marker"
}

if omarchy-cmd-present mise; then
echo -e "\e[32m\nUpdate mise tools\e[0m"

# Offline ISO provisioning uses its bundled Node version exactly so first boot
# does not need the network. The first normal update then converges that
# Omarchy-owned pin onto the same moving `latest` policy as network installs.
retarget_iso_node_pin

# mise withholds releases younger than its cooldown, so tools stay behind for
# days after they ship. Running omarchy update is the user asking for current
# versions now, which is the same call the mup alias makes by hand.
Expand Down
96 changes: 96 additions & 0 deletions test/shell.d/update-mise-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#!/bin/bash

set -euo pipefail

source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"

script="$ROOT/bin/omarchy-update-mise"
test_tmp=$(mktemp -d)
trap 'rm -rf "$test_tmp"' EXIT

run_case() {
local name="$1"
local configured_version="$2"
local bundled_version="$3"
local migrated="$4"
local fail_retarget="$5"
local case_dir="$test_tmp/$name"
local home="$case_dir/home"
local state="$case_dir/state"
local packages="$case_dir/packages"
local mock_bin="$case_dir/bin"
local log="$case_dir/mise.log"

mkdir -p "$home/.config/mise" "$state/omarchy" "$packages" "$mock_bin"
printf '[tools]\nnode = "%s"\n' "$configured_version" >"$home/.config/mise/config.toml"

if [[ -n $bundled_version ]]; then
touch "$packages/node-v${bundled_version}-linux-x64.tar.gz"
fi
if [[ $migrated == true ]]; then
touch "$state/omarchy/iso-node-mise-policy-migrated"
fi

cat >"$mock_bin/omarchy-cmd-present" <<'EOF'
#!/bin/bash
exit 0
EOF

cat >"$mock_bin/mise" <<'EOF'
#!/bin/bash
printf '%s\t%s\n' "${MISE_MINIMUM_RELEASE_AGE:-unset}" "$*" >>"$MISE_TEST_LOG"
if [[ ${MISE_TEST_FAIL_RETARGET:-false} == true && $* == "use -g node@latest" ]]; then
exit 1
fi
exit 0
EOF
chmod +x "$mock_bin/omarchy-cmd-present" "$mock_bin/mise"

HOME="$home" \
XDG_STATE_HOME="$state" \
OMARCHY_PROVISIONING_PACKAGES_DIR="$packages" \
MISE_TEST_LOG="$log" \
MISE_TEST_FAIL_RETARGET="$fail_retarget" \
PATH="$mock_bin:$PATH" \
bash "$script" >/dev/null 2>"$case_dir/stderr"
}

run_case iso-pin 26.7.0 26.7.0 false false
grep -Fx $'unset\tuse -g node@latest' "$test_tmp/iso-pin/mise.log" >/dev/null ||
fail "mise update retargets an exact Node pin that matches the bundled ISO tarball"
grep -Fx $'0\tup' "$test_tmp/iso-pin/mise.log" >/dev/null ||
fail "mise update still upgrades tools after retargeting the ISO Node pin"
[[ -f $test_tmp/iso-pin/state/omarchy/iso-node-mise-policy-migrated ]] ||
fail "mise update records the completed ISO Node policy migration"
pass "mise update retargets the bundled ISO Node pin once"

run_case manual-pin 24.0.0 26.7.0 false false
if grep -Fq $'\tuse -g node@latest' "$test_tmp/manual-pin/mise.log"; then
fail "mise update preserves an exact Node pin that does not match the bundled ISO"
fi
grep -Fx $'0\tup' "$test_tmp/manual-pin/mise.log" >/dev/null ||
fail "mise update still upgrades other tools with a manual Node pin"
[[ -f $test_tmp/manual-pin/state/omarchy/iso-node-mise-policy-migrated ]] ||
fail "mise update closes the legacy ISO check after preserving a manual pin"
pass "mise update preserves a manual exact Node pin"

run_case already-migrated 26.7.0 26.7.0 true false
if grep -Fq $'\tuse -g node@latest' "$test_tmp/already-migrated/mise.log"; then
fail "mise update does not reinterpret later Node pins after migration"
fi
pass "mise update leaves later user pins alone after migration"

run_case no-iso-state 26.7.0 '' false false
if grep -Fq $'\tuse -g node@latest' "$test_tmp/no-iso-state/mise.log"; then
fail "mise update does not retarget exact pins on non-ISO installs"
fi
[[ ! -f $test_tmp/no-iso-state/state/omarchy/iso-node-mise-policy-migrated ]] ||
fail "mise update does not create an ISO migration marker without provisioning packages"
pass "mise update ignores exact pins on non-ISO installs"

run_case retry-after-failure 26.7.0 26.7.0 false true
[[ ! -f $test_tmp/retry-after-failure/state/omarchy/iso-node-mise-policy-migrated ]] ||
fail "mise update leaves a failed ISO retarget eligible for retry"
grep -Fq 'will retry on the next update' "$test_tmp/retry-after-failure/stderr" ||
fail "mise update reports a deferred ISO Node retarget"
pass "mise update retries a failed ISO Node retarget later"