fix(release): restore linux compatibility fallbacks

This commit is contained in:
argenis de la rosa 2026-03-11 03:29:55 -04:00 committed by Argenis
parent 2b6085b10e
commit b940c7b641
4 changed files with 187 additions and 27 deletions

View File

@ -202,7 +202,7 @@ jobs:
include:
# Keep GNU Linux release artifacts on Ubuntu 22.04 to preserve
# a broadly compatible GLIBC baseline for user distributions.
- os: [self-hosted, Linux, X64, blacksmith-2vcpu-ubuntu-2404]
- os: ubuntu-22.04
target: x86_64-unknown-linux-gnu
artifact: zeroclaw
archive_ext: tar.gz
@ -217,7 +217,7 @@ jobs:
linker_env: ""
linker: ""
use_cross: true
- os: [self-hosted, Linux, X64, blacksmith-2vcpu-ubuntu-2404]
- os: ubuntu-22.04
target: aarch64-unknown-linux-gnu
artifact: zeroclaw
archive_ext: tar.gz
@ -232,7 +232,7 @@ jobs:
linker_env: ""
linker: ""
use_cross: true
- os: [self-hosted, Linux, X64, blacksmith-2vcpu-ubuntu-2404]
- os: ubuntu-22.04
target: armv7-unknown-linux-gnueabihf
artifact: zeroclaw
archive_ext: tar.gz

View File

@ -132,29 +132,33 @@ get_available_disk_mb() {
fi
}
detect_release_target() {
detect_release_targets() {
local os arch
os="$(uname -s)"
arch="$(uname -m)"
case "$os:$arch" in
Linux:x86_64)
echo "x86_64-unknown-linux-gnu"
printf '%s\n' \
"x86_64-unknown-linux-musl" \
"x86_64-unknown-linux-gnu"
;;
Linux:aarch64|Linux:arm64)
echo "aarch64-unknown-linux-gnu"
printf '%s\n' \
"aarch64-unknown-linux-musl" \
"aarch64-unknown-linux-gnu"
;;
Linux:armv7l|Linux:armv6l)
echo "armv7-unknown-linux-gnueabihf"
printf '%s\n' "armv7-unknown-linux-gnueabihf"
;;
Darwin:x86_64)
echo "x86_64-apple-darwin"
printf '%s\n' "x86_64-apple-darwin"
;;
Darwin:arm64|Darwin:aarch64)
echo "aarch64-apple-darwin"
printf '%s\n' "aarch64-apple-darwin"
;;
FreeBSD:amd64|FreeBSD:x86_64)
echo "x86_64-unknown-freebsd"
printf '%s\n' "x86_64-unknown-freebsd"
;;
*)
return 1
@ -264,6 +268,7 @@ detect_config_channel_features() {
install_prebuilt_binary() {
local target archive_url temp_dir archive_path extracted_bin install_dir
local -a candidate_targets=()
if ! have_cmd curl; then
warn "curl is required for pre-built binary installation."
@ -274,19 +279,25 @@ install_prebuilt_binary() {
return 1
fi
target="$(detect_release_target || true)"
if [[ -z "$target" ]]; then
mapfile -t candidate_targets < <(detect_release_targets || true)
if [[ "${#candidate_targets[@]}" -eq 0 ]]; then
warn "No pre-built binary target mapping for $(uname -s)/$(uname -m)."
return 1
fi
archive_url="https://github.com/zeroclaw-labs/zeroclaw/releases/latest/download/zeroclaw-${target}.tar.gz"
temp_dir="$(mktemp -d -t zeroclaw-prebuilt-XXXXXX)"
archive_path="$temp_dir/zeroclaw-${target}.tar.gz"
info "Attempting pre-built binary install for target: $target"
if ! curl -fsSL "$archive_url" -o "$archive_path"; then
warn "Could not download release asset: $archive_url"
for target in "${candidate_targets[@]}"; do
archive_url="https://github.com/zeroclaw-labs/zeroclaw/releases/latest/download/zeroclaw-${target}.tar.gz"
archive_path="$temp_dir/zeroclaw-${target}.tar.gz"
info "Attempting pre-built binary install for target: $target"
if curl -fsSL "$archive_url" -o "$archive_path"; then
break
fi
rm -f "$archive_path"
archive_path=""
done
if [[ -z "${archive_path:-}" || ! -f "$archive_path" ]]; then
warn "Could not download a compatible release asset."
rm -rf "$temp_dir"
return 1
fi

View File

@ -0,0 +1,121 @@
#!/usr/bin/env python3
"""Behavioral checks for release installer target selection helpers."""
from __future__ import annotations
import subprocess
import textwrap
import unittest
import re
from pathlib import Path
ROOT = Path(__file__).resolve().parents[3]
INSTALL_RELEASE = ROOT / "scripts" / "install-release.sh"
BOOTSTRAP = ROOT / "scripts" / "bootstrap.sh"
PUB_RELEASE = ROOT / ".github" / "workflows" / "pub-release.yml"
def run_cmd(cmd: list[str]) -> subprocess.CompletedProcess[str]:
return subprocess.run(
cmd,
text=True,
capture_output=True,
check=False,
)
def extract_function(function_name: str, script_path: Path) -> str:
lines = script_path.read_text(encoding="utf-8").splitlines()
start = None
for index, line in enumerate(lines):
if line == f"{function_name}() {{":
start = index
break
if start is None:
raise AssertionError(f"could not find function {function_name} in {script_path}")
body: list[str] = []
for line in lines[start:]:
body.append(line)
if line == "}":
break
return "\n".join(body) + "\n"
def run_shell_function(script_path: Path, function_name: str, os_name: str, arch: str) -> list[str]:
function_source = extract_function(function_name, script_path)
shell = textwrap.dedent(
f"""
set -euo pipefail
{function_source}
uname() {{
if [[ "${{1:-}}" == "-m" ]]; then
printf '%s\\n' "{arch}"
else
printf '%s\\n' "{os_name}"
fi
}}
{function_name}
"""
)
proc = run_cmd(["bash", "-lc", shell])
if proc.returncode != 0:
raise AssertionError(proc.stderr or proc.stdout)
return [line for line in proc.stdout.splitlines() if line]
def workflow_target_os(target: str) -> str:
workflow = PUB_RELEASE.read_text(encoding="utf-8")
pattern = re.compile(
rf"^\s+- os: (?P<os>.+)\n\s+target: {re.escape(target)}$",
re.MULTILINE,
)
match = pattern.search(workflow)
if match is None:
raise AssertionError(f"could not find workflow target block for {target}")
return match.group("os").strip()
class ReleaseInstallerTargetSelectionTest(unittest.TestCase):
def test_install_release_prefers_musl_for_linux_x86_64(self) -> None:
self.assertEqual(
run_shell_function(INSTALL_RELEASE, "linux_triples", "Linux", "x86_64"),
["x86_64-unknown-linux-musl", "x86_64-unknown-linux-gnu"],
)
def test_install_release_prefers_musl_for_linux_aarch64(self) -> None:
self.assertEqual(
run_shell_function(INSTALL_RELEASE, "linux_triples", "Linux", "aarch64"),
["aarch64-unknown-linux-musl", "aarch64-unknown-linux-gnu"],
)
def test_bootstrap_prefers_musl_for_linux_x86_64(self) -> None:
self.assertEqual(
run_shell_function(BOOTSTRAP, "detect_release_targets", "Linux", "x86_64"),
["x86_64-unknown-linux-musl", "x86_64-unknown-linux-gnu"],
)
def test_bootstrap_preserves_non_linux_target_mapping(self) -> None:
self.assertEqual(
run_shell_function(BOOTSTRAP, "detect_release_targets", "Darwin", "arm64"),
["aarch64-apple-darwin"],
)
def test_pub_release_keeps_gnu_linux_targets_on_ubuntu_22_04(self) -> None:
self.assertEqual(workflow_target_os("x86_64-unknown-linux-gnu"), "ubuntu-22.04")
self.assertEqual(workflow_target_os("aarch64-unknown-linux-gnu"), "ubuntu-22.04")
self.assertEqual(workflow_target_os("armv7-unknown-linux-gnueabihf"), "ubuntu-22.04")
def test_pub_release_keeps_musl_linux_targets_on_self_hosted_runner(self) -> None:
expected = "[self-hosted, Linux, X64, blacksmith-2vcpu-ubuntu-2404]"
self.assertEqual(workflow_target_os("x86_64-unknown-linux-musl"), expected)
self.assertEqual(workflow_target_os("aarch64-unknown-linux-musl"), expected)
def test_scripts_remain_shell_parseable(self) -> None:
proc = run_cmd(["bash", "-n", str(INSTALL_RELEASE), str(BOOTSTRAP)])
self.assertEqual(proc.returncode, 0, msg=proc.stderr)
if __name__ == "__main__":
unittest.main()

View File

@ -23,13 +23,23 @@ run_privileged() {
fi
}
linux_triple() {
linux_triples() {
local arch
arch="$(uname -m)"
case "$arch" in
x86_64|amd64) echo "x86_64-unknown-linux-gnu" ;;
aarch64|arm64) echo "aarch64-unknown-linux-gnu" ;;
armv7l|armv7) echo "armv7-unknown-linux-gnueabihf" ;;
x86_64|amd64)
printf '%s\n' \
"x86_64-unknown-linux-musl" \
"x86_64-unknown-linux-gnu"
;;
aarch64|arm64)
printf '%s\n' \
"aarch64-unknown-linux-musl" \
"aarch64-unknown-linux-gnu"
;;
armv7l|armv7)
printf '%s\n' "armv7-unknown-linux-gnueabihf"
;;
*)
echo "error: unsupported Linux architecture: $arch" >&2
echo "supported: x86_64, aarch64, armv7" >&2
@ -90,9 +100,8 @@ need_cmd tar
need_cmd mktemp
need_cmd install
TRIPLE="$(linux_triple)"
ASSET="zeroclaw-${TRIPLE}.tar.gz"
DOWNLOAD_URL="${RELEASE_BASE}/${ASSET}"
TRIPLE=""
ASSET=""
TMP_DIR="$(mktemp -d)"
cleanup() {
@ -106,8 +115,27 @@ if ! curl -fsSL "$API_URL" >/dev/null; then
exit 1
fi
echo "==> Downloading ${ASSET}"
curl -fL "$DOWNLOAD_URL" -o "$TMP_DIR/$ASSET"
download_asset() {
local triple asset download_url
while IFS= read -r triple; do
[ -n "$triple" ] || continue
asset="zeroclaw-${triple}.tar.gz"
download_url="${RELEASE_BASE}/${asset}"
echo "==> Attempting ${asset}"
if curl -fsSL "$download_url" -o "$TMP_DIR/$asset"; then
TRIPLE="$triple"
ASSET="$asset"
return 0
fi
done < <(linux_triples)
return 1
}
if ! download_asset; then
echo "error: unable to download a compatible Linux release artifact" >&2
exit 1
fi
echo "==> Extracting release archive"
tar -xzf "$TMP_DIR/$ASSET" -C "$TMP_DIR"