#!/usr/bin/env bash set -euo pipefail # Reusable bootstrap for Gitea workflows: # 1) checkout target commit # 2) ensure Node version (install from domestic mirror if missing/mismatch) # 3) ensure Yarn is available (and optionally pin version) # 通用准备脚本:用于 CI/Deploy 前的代码检出、Node 准备、Yarn 准备。 REPO_URL="${1:?repo url required}" GIT_SHA="${2:?git sha required}" # 优先使用精确版本 NODE_VERSION;未指定时按 NODE_MAJOR 自动解析最新小版本。 NODE_MAJOR="${NODE_MAJOR:-22}" NODE_VERSION="${NODE_VERSION:-}" YARN_VERSION="${YARN_VERSION:-stable}" # 默认使用国内镜像,减少下载失败概率。 NODEJS_MIRROR="${NODEJS_MIRROR:-https://npmmirror.com/mirrors/node}" NPM_REGISTRY="${NPM_REGISTRY:-https://registry.npmmirror.com}" # 安装到用户目录,避免依赖 /opt 写权限。 NODE_INSTALL_ROOT="${NODE_INSTALL_ROOT:-$HOME/.local/node-ci}" resolve_node_version() { # 指定了精确版本时,直接使用。 if [ -n "${NODE_VERSION}" ]; then echo "${NODE_VERSION#v}" return fi # 未指定精确版本时,从镜像索引中选定 NODE_MAJOR 对应的最新版本。 local resolved resolved="$(curl -fsSL "${NODEJS_MIRROR}/index.tab" | awk -F'\t' -v major="${NODE_MAJOR}" ' NR > 1 && $1 ~ ("^v" major "\\.") { print substr($1, 2); exit } ')" if [ -z "${resolved}" ]; then echo "failed to resolve latest Node ${NODE_MAJOR}.x from ${NODEJS_MIRROR}" exit 1 fi echo "${resolved}" } detect_arch() { # 仅支持常见 Linux 架构;其他架构显式失败,避免下载错误包。 case "$(uname -m)" in x86_64) echo "x64" ;; aarch64 | arm64) echo "arm64" ;; *) echo "unsupported architecture: $(uname -m)" exit 1 ;; esac } install_node() { local target_version="$1" local arch name url tarball install_dir bindir arch="$(detect_arch)" name="node-v${target_version}-linux-${arch}" url="${NODEJS_MIRROR}/v${target_version}/${name}.tar.xz" tarball="/tmp/${name}.tar.xz" install_dir="${NODE_INSTALL_ROOT}/${name}" bindir="${install_dir}/bin" if [ ! -x "${bindir}/node" ]; then # 下载并解压 Node 二进制包到本地缓存目录。 mkdir -p "${NODE_INSTALL_ROOT}" curl -fsSL "${url}" -o "${tarball}" tar -xJf "${tarball}" -C "${NODE_INSTALL_ROOT}" rm -f "${tarball}" fi export PATH="${bindir}:${PATH}" } ensure_node() { local target_version node_version target_version="$(resolve_node_version)" # 版本完全一致则直接复用,避免重复下载。 if command -v node >/dev/null 2>&1; then node_version="$(node -v | sed 's/^v//')" if [ "${node_version}" = "${target_version}" ]; then return fi fi install_node "${target_version}" node_version="$(node -v | sed 's/^v//')" if [ "${node_version}" != "${target_version}" ]; then echo "failed to switch to Node ${target_version}, current=${node_version}" exit 1 fi } # 首次执行时检出目标提交;已存在仓库则更新并强制切到指定 SHA。 if [ ! -d .git ]; then git clone "${REPO_URL}" . fi git fetch --all --tags --prune git checkout -f "${GIT_SHA}" ensure_node # Use domestic npm mirror for package-manager metadata/download. npm config set registry "${NPM_REGISTRY}" >/dev/null 2>&1 || true if ! command -v yarn >/dev/null 2>&1; then # 通过 corepack 激活指定 Yarn 版本。 corepack enable export COREPACK_NPM_REGISTRY="${NPM_REGISTRY}" corepack prepare "yarn@${YARN_VERSION}" --activate fi echo "Node: $(node -v)" echo "Yarn: $(yarn -v)"