diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f9004f..478e503 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0. - Binary-probe fallback in `guide.sh` when the post-install snapshot refresh is stale. ### Fixed +- difftastic 0.71.0 puts the version into its release file names (`difft-0.71.0-x86_64-unknown-linux-gnu.tar.gz`); the catalog download URL now includes it. byobu is tagged `trustmux-v7.19` since the trustmux rename, and those tags fill the first page of the tags API, so the installer found no stable tag; it now accepts both tag forms. - `cmd_update_local` in MERGE mode now refreshes multi-version cycle entries (`python@3.14`, …) instead of only the base-tool entry. Resolved false-negative "Upgrade did not succeed" messages after successful uv installs. ### Changed diff --git a/catalog/difftastic.json b/catalog/difftastic.json index f83207c..836fbe2 100644 --- a/catalog/difftastic.json +++ b/catalog/difftastic.json @@ -6,7 +6,7 @@ "homepage": "https://github.com/Wilfred/difftastic", "github_repo": "Wilfred/difftastic", "binary_name": "difft", - "download_url_template": "https://github.com/Wilfred/difftastic/releases/download/{version}/difft-{arch}-unknown-linux-gnu.tar.gz", + "download_url_template": "https://github.com/Wilfred/difftastic/releases/download/{version}/difft-{version}-{arch}-unknown-linux-gnu.tar.gz", "arch_map": { "x86_64": "x86_64", "aarch64": "aarch64" @@ -17,7 +17,7 @@ "priority": 1, "config": { "repo": "Wilfred/difftastic", - "asset_pattern": "difft-x86_64-unknown-linux-gnu.tar.gz" + "asset_pattern": "difft-.*-x86_64-unknown-linux-gnu.tar.gz" } }, { diff --git a/scripts/install_byobu.sh b/scripts/install_byobu.sh index f62a04e..32118f7 100755 --- a/scripts/install_byobu.sh +++ b/scripts/install_byobu.sh @@ -53,18 +53,22 @@ get_installed_version() { fi } -get_target_version() { +# Print the newest stable release tag. Upstream tags releases both as "7.19" +# and, since the trustmux rename, as "trustmux-v7.19"; the prefixed tags fill +# the first page of the tags API, so accept both forms. For equal versions +# the plain tag wins. +get_target_tag() { local tags_json="" - local version="" tags_json="$(github_api_get "repos/$GITHUB_REPO/tags?per_page=100")" || tags_json="" - version="$(printf '%s' "$tags_json" | + printf '%s' "$tags_json" | jq -r 'if type == "array" then .[].name else empty end' | - grep -E '^[0-9]+([.][0-9]+)+$' | - sort -V | - tail -1)" - printf '%s' "$version" + grep -E '^(trustmux-v)?[0-9]+([.][0-9]+)+$' | + awk '{ v = $0; sub(/^trustmux-v/, "", v); print v "\t" ($0 == v ? 1 : 0) "\t" $0 }' | + sort -t "$(printf '\t')" -k1,1V -k2,2n | + tail -1 | + cut -f3 || true } remove_manifest_files() { @@ -84,6 +88,9 @@ remove_manifest_files() { install_byobu() { local version="${1:-}" + local tag="$version" + local candidate="" + local -a tags=() local before="" local after="" local archive="" @@ -96,7 +103,13 @@ install_byobu() { if [ -z "$version" ]; then echo "[$TOOL] Fetching latest stable tag..." >&2 - version="$(get_target_version)" + tag="$(get_target_tag)" + fi + version="${tag#trustmux-v}" + # An explicit plain version may exist only as trustmux-v + tags=("$tag") + if [ "$tag" = "$version" ]; then + tags+=("trustmux-v$version") fi if ! grep -Eq '^[0-9]+([.][0-9]+)+$' <<<"$version"; then echo "[$TOOL] Error: Invalid stable version: ${version:-}" >&2 @@ -108,13 +121,18 @@ install_byobu() { BUILD_LOG="$BUILD_TMPDIR/build.log" archive="$BUILD_TMPDIR/byobu-$version.tar.gz" stage_dir="$BUILD_TMPDIR/stage" - url="https://github.com/$GITHUB_REPO/archive/refs/tags/${version}.tar.gz" - - echo "[$TOOL] Downloading $url..." >&2 - if ! curl --proto '=https' --proto-redir '=https' -fL \ - --retry 3 --retry-delay 1 --connect-timeout 10 \ - "$url" -o "$archive"; then - echo "[$TOOL] Error: Failed to download $url" >&2 + url="" + for candidate in "${tags[@]}"; do + echo "[$TOOL] Downloading tag $candidate..." >&2 + if curl --proto '=https' --proto-redir '=https' -fsSL \ + --retry 3 --retry-delay 1 --connect-timeout 10 \ + "https://github.com/$GITHUB_REPO/archive/refs/tags/${candidate}.tar.gz" -o "$archive"; then + url="https://github.com/$GITHUB_REPO/archive/refs/tags/${candidate}.tar.gz" + break + fi + done + if [ -z "$url" ]; then + echo "[$TOOL] Error: Failed to download tag(s): ${tags[*]}" >&2 return 1 fi if ! tar -xzf "$archive" -C "$BUILD_TMPDIR"; then diff --git a/tests/test_catalog_and_collectors.py b/tests/test_catalog_and_collectors.py index 4eb2208..39f5ba6 100644 --- a/tests/test_catalog_and_collectors.py +++ b/tests/test_catalog_and_collectors.py @@ -392,7 +392,8 @@ def test_byobu_installer_is_executable_and_filters_stable_tags(self): content = script_path.read_text() assert "^[0-9]+([.][0-9]+)+$" in content - assert "archive/refs/tags/${version}.tar.gz" in content + # The tag, not the version: releases are tagged "trustmux-v7.19" too + assert "archive/refs/tags/${candidate}.tar.gz" in content assert './configure --prefix="$INSTALL_PREFIX"' in content assert "$INSTALL_PREFIX/bin/byobu" in content assert "uninstall)" in content diff --git a/tests/test_install_gh_fallback.py b/tests/test_install_gh_fallback.py index 7518534..78bd25d 100644 --- a/tests/test_install_gh_fallback.py +++ b/tests/test_install_gh_fallback.py @@ -92,7 +92,7 @@ def test_fails_cleanly_when_neither_source_answers(self, fake_bin, tmp_path): @skip_on_windows class TestGhErrorBodyFallback: def test_byobu_falls_back_to_curl_when_gh_fails(self, fake_bin, tmp_path): - proc = _run_sourced("install_byobu.sh", "get_target_version", fake_bin, tmp_path) + proc = _run_sourced("install_byobu.sh", "get_target_tag", fake_bin, tmp_path) assert proc.returncode == 0, proc.stderr assert proc.stdout.strip() == "7.18" assert "Cannot index" not in proc.stderr @@ -100,10 +100,50 @@ def test_byobu_falls_back_to_curl_when_gh_fails(self, fake_bin, tmp_path): def test_byobu_uses_gh_result_when_gh_succeeds(self, fake_bin, tmp_path): _write_stub(fake_bin, "gh", f"printf '%s' '{BYOBU_TAGS_JSON}'\n") _write_stub(fake_bin, "curl", "exit 99\n") - proc = _run_sourced("install_byobu.sh", "get_target_version", fake_bin, tmp_path) + proc = _run_sourced("install_byobu.sh", "get_target_tag", fake_bin, tmp_path) assert proc.returncode == 0, proc.stderr assert proc.stdout.strip() == "7.18" + def test_byobu_accepts_trustmux_prefixed_tags(self, fake_bin, tmp_path): + # Real first page of the tags API after the trustmux rename: no plain tag on it + tags = ( + '[{"name":"trustmux-v7.20rc5"},{"name":"trustmux-v7.19"},' + '{"name":"trustmux-v7.19rc17"},{"name":"trustmux-v7.18"}]' + ) + _write_stub(fake_bin, "gh", f"printf '%s' '{tags}'\n") + proc = _run_sourced("install_byobu.sh", "get_target_tag", fake_bin, tmp_path) + assert proc.returncode == 0, proc.stderr + assert proc.stdout.strip() == "trustmux-v7.19" + + def test_byobu_prefers_plain_tag_for_equal_versions(self, fake_bin, tmp_path): + tags = '[{"name":"trustmux-v7.19"},{"name":"7.19"},{"name":"7.18"}]' + _write_stub(fake_bin, "gh", f"printf '%s' '{tags}'\n") + proc = _run_sourced("install_byobu.sh", "get_target_tag", fake_bin, tmp_path) + assert proc.returncode == 0, proc.stderr + assert proc.stdout.strip() == "7.19" + + def test_byobu_explicit_version_falls_back_to_trustmux_tag(self, fake_bin, tmp_path): + # "install 7.20" when upstream only tagged trustmux-v7.20: the plain tag 404s + for cmd in ("make", "autoreconf", "automake", "autoconf"): + _write_stub(fake_bin, cmd, "exit 0\n") + _write_stub( + fake_bin, + "curl", + """for arg in "$@"; do + case "$arg" in + */refs/tags/trustmux-v7.20.tar.gz) echo "archive" > "${@: -1}"; exit 0 ;; + esac +done +exit 22 +""", + ) + proc = _run_sourced("install_byobu.sh", "install_byobu 7.20", fake_bin, tmp_path) + assert proc.returncode == 1 + # Reached the extract step with the prefixed tag; the stub archive is not a tarball + assert "Invalid source archive: https://github.com/dustinkirkland/byobu/archive/refs/tags/trustmux-v7.20.tar.gz" in ( + proc.stderr + ) + def test_tmux_falls_back_to_release_redirect_when_gh_fails(self, fake_bin, tmp_path): proc = _run_sourced("install_tmux.sh", "get_target_version", fake_bin, tmp_path) assert proc.returncode == 0, proc.stderr