From e73a574db020d1804f92e473a5975da1e02d8399 Mon Sep 17 00:00:00 2001 From: mm644706215 Date: Sun, 22 Mar 2026 23:30:57 +0800 Subject: [PATCH] fix: add gitea fallback for arm64 musl node downloads --- .github/workflows/build-node-musl.yml | 12 ++-- root/usr/bin/openclaw-env | 86 +++++++++++++++++---------- tests/test_node_packaging_contract.sh | 14 ++++- tests/test_openclaw_node.sh | 25 ++++++-- 4 files changed, 93 insertions(+), 44 deletions(-) diff --git a/.github/workflows/build-node-musl.yml b/.github/workflows/build-node-musl.yml index c059777..0ed92d7 100644 --- a/.github/workflows/build-node-musl.yml +++ b/.github/workflows/build-node-musl.yml @@ -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 元数据解析。 diff --git a/root/usr/bin/openclaw-env b/root/usr/bin/openclaw-env index 1ce2e53..0136c50 100755 --- a/root/usr/bin/openclaw-env +++ b/root/usr/bin/openclaw-env @@ -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,32 +85,36 @@ 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" + continue + fi + + asset_url=$(oc_select_node_release_asset_url "$release_json" "linux-arm64" "$node_ver" || true) 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 - fi - asset_url=$(oc_select_node_release_asset_url "$release_json" "linux-arm64" "$node_ver" || true) - rm -f "$release_json" - - if [ -n "$asset_url" ]; then - printf '%s\n' "$asset_url" - return 0 - fi + if [ -n "$asset_url" ]; then + 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 </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 mirror_list="${NODE_MUSL_MIRROR}/v${node_ver}/${musl_tarball}" diff --git a/tests/test_node_packaging_contract.sh b/tests/test_node_packaging_contract.sh index 7fda0f6..b0959a3 100644 --- a/tests/test_node_packaging_contract.sh +++ b/tests/test_node_packaging_contract.sh @@ -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" diff --git a/tests/test_openclaw_node.sh b/tests/test_openclaw_node.sh index 3830e69..663a217 100644 --- a/tests/test_openclaw_node.sh +++ b/tests/test_openclaw_node.sh @@ -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