fix: add gitea fallback for arm64 musl node downloads

This commit is contained in:
mm644706215
2026-03-22 23:30:57 +08:00
parent 182623f67c
commit e73a574db0
4 changed files with 93 additions and 44 deletions

View File

@@ -9,7 +9,7 @@ on:
default: true
type: boolean
build_v2:
description: 'Build V2 (22.16.0) - Current version'
description: 'Build V2 (23.2.0) - Current version'
required: false
default: true
type: boolean
@@ -89,7 +89,7 @@ jobs:
name: node-arm64-musl-v1
path: dist/*.tar.xz
# ── V2 构建: 使用交叉编译模式 (22.16.0) ──
# ── V2 构建: 使用交叉编译模式 (23.2.0) ──
build-v2:
name: Build Node.js V2 (Current)
if: ${{ inputs.build_v2 }}
@@ -110,7 +110,7 @@ jobs:
- name: Build Node.js V2 ARM64 musl (apk current mode)
run: |
NODE_VER="22.16.0"
NODE_VER="23.2.0"
mkdir -p dist
echo "=== Building Node.js v${NODE_VER}+ ARM64 musl (apk current mode) ==="
docker run --rm --platform linux/arm64 \
@@ -211,13 +211,13 @@ jobs:
| 文件 | 版本 | 用途 |
|------|------|------|
| `node-v23.x.x-linux-arm64-musl.tar.xz` | V2 (当前) | OpenClaw v2026.3.11+ (要求 >= 22.16.0) |
| `node-v23.2.0-linux-arm64-musl.tar.xz` | V2 (当前默认) | OpenClaw v2026.3.11+ (默认下载,满足 >= 22.16.0) |
| `node-v22.x.x-linux-arm64-musl.tar.xz` | V1 (旧版) | OpenClaw v2026.3.8 及更早版本 |
## 构建模式
两种版本均使用 **Alpine apk 模式** 构建:
- **V2**: 使用 Alpine `nodejs-current` 包 (v23.x)满足 OpenClaw >= 22.16.0 的要求
- **V2**: 使用 Alpine `nodejs-current` 包 (v23.x)当前默认发布 `node-v23.2.0-linux-arm64-musl.tar.xz`
- **V1**: 使用 Alpine `nodejs` LTS 包 (v22.x),兼容旧版 OpenClaw
`openclaw-env setup` 会在 ARM64 musl 设备上自动从此处下载合适的版本
`openclaw-env setup` 会在 ARM64 musl 设备上默认直连下载 V2 当前版本,必要时再回退到 Release 元数据解析

View File

@@ -15,9 +15,9 @@ set -e
. /usr/libexec/openclaw-node.sh
# ── Node.js 版本策略 ──
# V2: 当前推荐版本,用于 OpenClaw v2026.3.11+ (要求 >= 22.16.0)
# V2: 当前推荐版本,用于 OpenClaw v2026.3.11+ (默认下载 23.2.0,满足 >= 22.16.0)
# V1: 保留给显式指定旧版环境时使用,不再作为 V2 的自动回退
NODE_VERSION_V2="22.16.0"
NODE_VERSION_V2="23.2.0"
NODE_VERSION_V1="22.15.1"
# 默认使用 V2 版本 (可通过 NODE_VERSION 环境变量覆盖)
NODE_VERSION="${NODE_VERSION:-${NODE_VERSION_V2}}"
@@ -60,8 +60,11 @@ NODE_MIRROR="${NODE_MIRROR:-https://nodejs.org/dist}"
NODE_MIRROR_CN="https://npmmirror.com/mirrors/node"
NODE_MUSL_MIRROR="https://unofficial-builds.nodejs.org/download/release"
NODE_SELF_HOST="${NODE_SELF_HOST:-https://github.com/${OPENCLAW_NODE_BINS_REPO}/releases/download/node-bins}"
NODE_SELF_HOST_FALLBACK="${NODE_SELF_HOST_FALLBACK:-https://gitea.jmsu.top/lingyuzeng/luci-app-openclaw/releases/download/node-bins}"
NODE_RELEASE_API="${NODE_RELEASE_API:-https://api.github.com/repos/${OPENCLAW_NODE_BINS_REPO}/releases/tags/node-bins}"
NODE_RELEASE_API_FALLBACK="${NODE_RELEASE_API_FALLBACK:-https://gitea.jmsu.top/api/v1/repos/lingyuzeng/luci-app-openclaw/releases/tags/node-bins}"
NODE_RELEASE_PAGE="${NODE_RELEASE_PAGE:-https://github.com/${OPENCLAW_NODE_BINS_REPO}/releases/tag/node-bins}"
NODE_RELEASE_PAGE_FALLBACK="${NODE_RELEASE_PAGE_FALLBACK:-https://gitea.jmsu.top/lingyuzeng/luci-app-openclaw/releases/tag/node-bins}"
export PATH="${NODE_BASE}/bin:${OC_GLOBAL}/bin:$PATH"
export NODE_ICU_DATA="${NODE_BASE}/share/icu"
@@ -82,17 +85,14 @@ resolve_arm64_musl_node_url() {
local node_ver="$1"
local release_json="/tmp/openclaw-node-bins-release.json"
local asset_url=""
local release_api=""
echo " 正在从 ${NODE_RELEASE_API} 获取 ARM64 musl 版本列表..." >&2
if ! download_url_to_file "$NODE_RELEASE_API" "$release_json"; then
for release_api in "$NODE_RELEASE_API" "$NODE_RELEASE_API_FALLBACK"; do
[ -n "$release_api" ] || continue
echo " 正在从 ${release_api} 获取 ARM64 musl 版本列表..." >&2
if ! download_url_to_file "$release_api" "$release_json"; then
rm -f "$release_json"
log_error "无法获取 ARM64 musl Node.js 发布元数据" >&2
echo " 仓库: ${OPENCLAW_NODE_BINS_REPO}" >&2
echo " 最低要求: v${node_ver}" >&2
echo " Release API: ${NODE_RELEASE_API}" >&2
echo " Release 页面: ${NODE_RELEASE_PAGE}" >&2
echo " 请先发布 node-bins 中满足要求的 ARM64 musl 资产,或通过环境变量覆盖下载源" >&2
return 1
continue
fi
asset_url=$(oc_select_node_release_asset_url "$release_json" "linux-arm64" "$node_ver" || true)
@@ -102,12 +102,19 @@ resolve_arm64_musl_node_url() {
printf '%s\n' "$asset_url"
return 0
fi
done
log_error "未找到兼容的 ARM64 musl Node.js 资产" >&2
echo " 仓库: ${OPENCLAW_NODE_BINS_REPO}" >&2
echo " 最低要求: v${node_ver}" >&2
echo " Release API: ${NODE_RELEASE_API}" >&2
if [ -n "$NODE_RELEASE_API_FALLBACK" ] && [ "$NODE_RELEASE_API_FALLBACK" != "$NODE_RELEASE_API" ]; then
echo " Fallback API: ${NODE_RELEASE_API_FALLBACK}" >&2
fi
echo " Release 页面: ${NODE_RELEASE_PAGE}" >&2
if [ -n "$NODE_RELEASE_PAGE_FALLBACK" ] && [ "$NODE_RELEASE_PAGE_FALLBACK" != "$NODE_RELEASE_PAGE" ]; then
echo " Fallback 页面: ${NODE_RELEASE_PAGE_FALLBACK}" >&2
fi
echo " 请先发布 node-bins 中满足要求的 ARM64 musl 资产,或通过环境变量覆盖下载源" >&2
return 1
}
@@ -152,16 +159,26 @@ $ver_dir"
done
local d
echo "$search_dirs" | while read -r d; do
local found=""
while IFS= read -r d; do
[ -z "$d" ] && continue
if [ -f "${d}/openclaw.mjs" ]; then
echo "${d}/openclaw.mjs"
return
found="${d}/openclaw.mjs"
break
elif [ -f "${d}/dist/cli.js" ]; then
echo "${d}/dist/cli.js"
return
found="${d}/dist/cli.js"
break
fi
done
done <<EOF
$search_dirs
EOF
if [ -n "$found" ]; then
printf '%s\n' "$found"
return 0
fi
return 1
}
detect_arch() {
@@ -220,9 +237,18 @@ download_node() {
echo "=== 下载 Node.js v${node_ver} (${node_arch}, musl libc) ==="
if [ "$node_arch" = "linux-arm64" ]; then
# ARM64 musl: 从当前维护仓库的 node-bins release 动态选择兼容资产
arm64_musl_url=$(resolve_arm64_musl_node_url "$node_ver") || exit 1
mirror_list="${arm64_musl_url}"
# ARM64 musl: GitHub 直链优先Gitea 镜像兜底API 解析作为兼容补充
mirror_list="${NODE_SELF_HOST}/${musl_tarball}"
if [ -n "$NODE_SELF_HOST_FALLBACK" ] && [ "$NODE_SELF_HOST_FALLBACK" != "$NODE_SELF_HOST" ]; then
mirror_list="$mirror_list ${NODE_SELF_HOST_FALLBACK}/${musl_tarball}"
fi
arm64_musl_url=$(resolve_arm64_musl_node_url "$node_ver" 2>/dev/null || true)
if [ -n "$arm64_musl_url" ] && [ "$arm64_musl_url" != "${NODE_SELF_HOST}/${musl_tarball}" ]; then
case " $mirror_list " in
*" ${arm64_musl_url} "*) ;;
*) mirror_list="$mirror_list ${arm64_musl_url}" ;;
esac
fi
else
# x64 musl: unofficial-builds 提供
# 1) unofficial-builds

View File

@@ -28,19 +28,27 @@ grep -Fq 'verify_prefix /opt/openclaw/node' "$WORKFLOW" || fail "workflow should
grep -Fq 'verify_prefix /tmp/custom-openclaw-root/openclaw/node' "$WORKFLOW" || fail "workflow should verify custom install path"
grep -Fq 'oc_node_version_ge "$installed_ver" "$node_ver"' "$ENV_SCRIPT" || fail "installer should enforce minimum node version after extraction"
grep -Fq 'NODE_VERSION_V2="23.2.0"' "$ENV_SCRIPT" || fail "installer should default V2 to Node.js 23.2.0"
if grep -Fq 'mirror_list="$mirror_list ${NODE_SELF_HOST}/${v1_tarball}"' "$ENV_SCRIPT"; then
fail "installer should not auto-fallback from V2 to V1 tarball"
fi
grep -Fq 'OPENCLAW_GITHUB_REPO="${OPENCLAW_GITHUB_REPO:-hotwa/luci-app-openclaw}"' "$ENV_SCRIPT" || fail "installer should keep hotwa as primary app repo"
grep -Fq 'OPENCLAW_NODE_BINS_REPO="${OPENCLAW_NODE_BINS_REPO:-hotwa/luci-app-openclaw}"' "$ENV_SCRIPT" || fail "installer should default ARM64 musl node-bins to hotwa repo"
grep -Fq 'NODE_SELF_HOST="${NODE_SELF_HOST:-https://github.com/${OPENCLAW_NODE_BINS_REPO}/releases/download/node-bins}"' "$ENV_SCRIPT" || fail "installer should derive node-bins release URL from hotwa repo"
grep -Fq 'NODE_SELF_HOST_FALLBACK="${NODE_SELF_HOST_FALLBACK:-https://gitea.jmsu.top/lingyuzeng/luci-app-openclaw/releases/download/node-bins}"' "$ENV_SCRIPT" || fail "installer should define a Gitea mirror fallback for ARM64 musl downloads"
grep -Fq 'NODE_RELEASE_API="${NODE_RELEASE_API:-https://api.github.com/repos/${OPENCLAW_NODE_BINS_REPO}/releases/tags/node-bins}"' "$ENV_SCRIPT" || fail "installer should derive node-bins release API from hotwa repo"
grep -Fq 'NODE_RELEASE_API_FALLBACK="${NODE_RELEASE_API_FALLBACK:-https://gitea.jmsu.top/api/v1/repos/lingyuzeng/luci-app-openclaw/releases/tags/node-bins}"' "$ENV_SCRIPT" || fail "installer should define a Gitea release API fallback"
grep -Fq 'NODE_RELEASE_PAGE_FALLBACK="${NODE_RELEASE_PAGE_FALLBACK:-https://gitea.jmsu.top/lingyuzeng/luci-app-openclaw/releases/tag/node-bins}"' "$ENV_SCRIPT" || fail "installer should define a Gitea release page fallback"
grep -Fq 'for release_api in "$NODE_RELEASE_API" "$NODE_RELEASE_API_FALLBACK"; do' "$ENV_SCRIPT" || fail "installer should retry ARM64 musl release API using the Gitea mirror"
grep -Fq 'oc_select_node_release_asset_url' "$ENV_SCRIPT" || fail "installer should dynamically select ARM64 musl asset"
grep -Fq 'oc_node_requires_opt_compat "$NODE_BIN"' "$ENV_SCRIPT" || fail "installer should detect legacy opt-bound ARM64 musl node assets"
grep -Fq 'oc_ensure_opt_compat_link "$OC_ROOT"' "$ENV_SCRIPT" || fail "installer should create /opt compatibility symlink for legacy assets"
grep -Fq 'arm64_musl_url=$(resolve_arm64_musl_node_url "$node_ver") || exit 1' "$ENV_SCRIPT" || fail "installer should resolve ARM64 musl asset dynamically"
if grep -Fq 'mirror_list="${NODE_SELF_HOST}/${musl_tarball}"' "$ENV_SCRIPT"; then
fail "installer should not hardcode exact ARM64 musl asset path"
grep -Fq 'mirror_list="${NODE_SELF_HOST}/${musl_tarball}"' "$ENV_SCRIPT" || fail "installer should default ARM64 musl downloads to direct release asset URL"
grep -Fq 'mirror_list="$mirror_list ${NODE_SELF_HOST_FALLBACK}/${musl_tarball}"' "$ENV_SCRIPT" || fail "installer should try the Gitea mirror after GitHub"
grep -Fq 'arm64_musl_url=$(resolve_arm64_musl_node_url "$node_ver" 2>/dev/null || true)' "$ENV_SCRIPT" || fail "installer should keep API-based ARM64 musl asset discovery as fallback"
grep -Fq 'while IFS= read -r d; do' "$ENV_SCRIPT" || fail "installer should traverse OpenClaw entry candidates without a pipeline subshell"
if grep -Fq 'echo "$search_dirs" | while read -r d; do' "$ENV_SCRIPT"; then
fail "installer should not rely on a pipeline subshell for OpenClaw entry lookup"
fi
grep -Fq 'openclaw-paths.sh' "$MAKEFILE" || fail "package makefile should install path helper"

View File

@@ -18,10 +18,10 @@ if oc_normalize_node_version "broken-version" >/dev/null 2>&1; then
fail "invalid version should not normalize"
fi
oc_node_version_ge "22.16.0" "22.16.0" || fail "exact version should satisfy requirement"
oc_node_version_ge "22.16.1" "22.16.0" || fail "newer patch should satisfy requirement"
oc_node_version_ge "23.0.0" "22.16.0" || fail "newer major should satisfy requirement"
if oc_node_version_ge "22.15.1" "22.16.0"; then
oc_node_version_ge "23.2.0" "23.2.0" || fail "exact version should satisfy requirement"
oc_node_version_ge "23.2.1" "23.2.0" || fail "newer patch should satisfy requirement"
oc_node_version_ge "24.0.0" "23.2.0" || fail "newer major should satisfy requirement"
if oc_node_version_ge "22.15.1" "23.2.0"; then
fail "older minor version should not satisfy requirement"
fi
@@ -82,9 +82,24 @@ cat > "$tmpdir/node-bins-release.json" <<'EOF'
}
EOF
selected_url=$(oc_select_node_release_asset_url "$tmpdir/node-bins-release.json" "linux-arm64" "22.16.0") || fail "select compatible ARM64 musl asset"
selected_url=$(oc_select_node_release_asset_url "$tmpdir/node-bins-release.json" "linux-arm64" "23.2.0") || fail "select compatible ARM64 musl asset"
[ "$selected_url" = "https://github.com/hotwa/luci-app-openclaw/releases/download/node-bins/node-v23.2.0-linux-arm64-musl.tar.xz" ] || fail "selected asset should be newest compatible ARM64 musl release"
cat > "$tmpdir/gitea-node-bins-release.json" <<'EOF'
{
"tag_name": "node-bins",
"assets": [
{
"name": "node-v23.2.0-linux-arm64-musl.tar.xz",
"browser_download_url": "http://100.64.0.27:8418/lingyuzeng/luci-app-openclaw/releases/download/node-bins/node-v23.2.0-linux-arm64-musl.tar.xz"
}
]
}
EOF
gitea_selected_url=$(oc_select_node_release_asset_url "$tmpdir/gitea-node-bins-release.json" "linux-arm64" "23.2.0") || fail "select compatible ARM64 musl asset from Gitea release JSON"
[ "$gitea_selected_url" = "http://100.64.0.27:8418/lingyuzeng/luci-app-openclaw/releases/download/node-bins/node-v23.2.0-linux-arm64-musl.tar.xz" ] || fail "selected Gitea asset should preserve browser_download_url"
if oc_select_node_release_asset_url "$tmpdir/node-bins-release.json" "linux-arm64" "24.0.0" >/dev/null 2>&1; then
fail "asset selection should fail when no compatible version exists"
fi