Files
lunar-mini/.gitea/workflows/miniapp-preview.yml
T
gouki 297747041a
Publish Mini Program Dev Version / publish (push) Failing after 11s
fix(ci): Node下载增加npmmirror镜像源+gzip校验+二进制验证
1826/1827连续失败:hk runner下载musl版node时拿到错误产物
(glibc版node在musl环境报libstdc++.so.6缺失)。
加固:musl下载增加npmmirror镜像fallback;下载后校验gzip魔数;
解压后验证node可执行,失败则清除缓存避免污染后续run
2026-08-09 23:47:23 +00:00

185 lines
8.4 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: Publish Mini Program Dev Version
on:
workflow_dispatch:
push:
branches:
- main
paths:
- "mini/**"
- ".gitea/workflows/miniapp-preview.yml"
jobs:
publish:
# 标准标签:hk / bt-runner 均带 ubuntu-latest,任一空闲 runner 接单
runs-on: ubuntu-latest
steps:
# 精简 runnerAlpine)无 node,无法跑 action-checkout;直接用 git 浅克隆
- name: Checkout
env:
REPO_URL: ${{ gitea.server_url }}/${{ gitea.repository }}
REF_NAME: ${{ gitea.ref_name }}
run: |
git init -q .
git remote add origin "$REPO_URL"
git fetch -q --depth 20 origin "$REF_NAME"
git checkout -q FETCH_HEAD
git log --oneline -3
- name: Prepare Node toolchain
run: |
# 优先复用 runner 宿主机缓存的工具链(工作目录持久化)
TOOLDIR="$RUNNER_WORKSPACE/.lunar-toolchain"
mkdir -p "$TOOLDIR"
if [ -x "$TOOLDIR/node/bin/node" ] && "$TOOLDIR/node/bin/node" --version >/dev/null 2>&1; then
echo "复用缓存 Node 工具链"
else
# 清理旧缓存:Alpine busybox mv 遇已存在目录会合并而非替换,
# 残留的 glibc 版 node 会污染 musl 环境导致 symbol not found
rm -rf "$TOOLDIR"
mkdir -p "$TOOLDIR"
# 探测 libcAlpine(musl) 用 unofficial musl 构建,其余用官方 glibc 构建(tar.gzbusybox tar 不支持 xz
if ldd --version 2>&1 | grep -qi musl || [ ! -e /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 ]; then
NODE_DIST="node-v22.12.0-linux-x64-musl"
# 多源下载:unofficial-builds 海外源 + npmmirror 镜像(busybox wget 自动跟随 302
wget -q --tries=2 --timeout=120 -O "$TOOLDIR/node.tgz" \
"https://unofficial-builds.nodejs.org/download/release/v22.12.0/$NODE_DIST.tar.gz" \
|| wget -q --tries=2 --timeout=120 -O "$TOOLDIR/node.tgz" \
"https://registry.npmmirror.com/-/binary/node-unofficial-builds/v22.12.0/$NODE_DIST.tar.gz"
else
NODE_DIST="node-v22.12.0-linux-x64"
wget -q --tries=2 --timeout=120 -O "$TOOLDIR/node.tgz" \
"https://nodejs.org/dist/v22.12.0/$NODE_DIST.tar.gz" \
|| wget -q --tries=2 --timeout=120 -O "$TOOLDIR/node.tgz" \
"https://mirrors.aliyun.com/nodejs-release/v22.12.0/$NODE_DIST.tar.gz"
fi
# 校验下载结果:文件存在且是 gzip 格式(防止半截下载/错误页残留污染缓存)
test -s "$TOOLDIR/node.tgz"
head -c 2 "$TOOLDIR/node.tgz" | od -An -tx1 | grep -q "1f 8b"
tar -C "$TOOLDIR" -xzf "$TOOLDIR/node.tgz"
mv "$TOOLDIR/$NODE_DIST" "$TOOLDIR/node"
rm -f "$TOOLDIR/node.tgz"
fi
# 验证二进制可执行,失败则清缓存并报错(避免坏缓存被后续 run 复用)
if ! "$TOOLDIR/node/bin/node" --version; then
echo "::error::Node 二进制无法执行,请检查下载源与 libc 匹配"
rm -rf "$TOOLDIR"
exit 1
fi
echo "PATH=$TOOLDIR/node/bin:$PATH" >> "$GITEA_ENV"
- name: Verify Node runtime
run: node --version
- name: Install dependencies
working-directory: mini
run: npm ci
- name: Run tests
working-directory: mini
run: npm test
- name: Configure production API and app version
working-directory: mini
env:
MINIAPP_BUILD_NUMBER: ${{ gitea.run_number }}
GITEA_SHA: ${{ gitea.sha }}
run: |
test -n "$MINIAPP_BUILD_NUMBER"
VERSION="$(node -e 'const {resolveVersion}=require("./ci/resolve-version.cjs"); process.stdout.write(resolveVersion(process.cwd()))')"
test -n "$VERSION"
mkdir -p ci-artifacts
printf '%s\n' "$VERSION" > ci-artifacts/resolved-version.txt
echo "Resolved Mini Program version for build+upload: $VERSION"
# 注入版本号到 utils/version.js
BUILD_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
COMMIT_SHORT="${GITEA_SHA:0:7}"
cat > utils/version.js <<EOF
/**
* 版本号配置文件
* 此文件由 CI 构建时自动生成,请勿手动修改
*/
module.exports = {
version: "$VERSION",
buildNumber: "$MINIAPP_BUILD_NUMBER",
buildTime: "$BUILD_TIME",
commitSha: "$COMMIT_SHORT",
};
EOF
echo "Version info injected into utils/version.js:"
cat utils/version.js
- name: Materialize the upload key
env:
WECHAT_CI_PRIVATE_KEY: ${{ secrets.WECHAT_CI_PRIVATE_KEY }}
run: |
test -n "$WECHAT_CI_PRIVATE_KEY"
umask 077
printf '%s' "$WECHAT_CI_PRIVATE_KEY" > "$RUNNER_TEMP/wechat-ci.key"
- name: Upload WeChat development version
working-directory: mini
env:
MINIAPP_APPID: ${{ vars.MINIAPP_APPID }}
MINIAPP_ROBOT: ${{ vars.MINIAPP_ROBOT }}
# Prefer the version resolved before build so UI label matches WeChat upload.
MINIAPP_BUILD_NUMBER: ${{ gitea.run_number }}
WECHAT_CI_PRIVATE_KEY_PATH: ${{ runner.temp }}/wechat-ci.key
MINIAPP_UPLOAD_RESULT: ${{ gitea.workspace }}/mini/ci-artifacts/upload-result.json
MINIAPP_VERSION_LABEL: ${{ gitea.sha }}
MINIAPP_UPLOAD_DESC_ITEMS: "3"
MINIAPP_UPLOAD_DESC_MAX: "100"
run: |
test -n "$MINIAPP_APPID"
test -n "$MINIAPP_BUILD_NUMBER"
test -s ci-artifacts/resolved-version.txt
RESOLVED_VERSION="$(tr -d '\n' < ci-artifacts/resolved-version.txt)"
# Force upload to the same version that was baked into the JS bundle.
export MINIAPP_VERSION_OVERRIDE="$RESOLVED_VERSION"
mkdir -p ci-artifacts
node -e 'const c=require("./project.config.json"); if(c.appid!==process.env.MINIAPP_APPID){console.error("MINIAPP_APPID mismatch with project.config.json", process.env.MINIAPP_APPID, c.appid); process.exit(1)}'
node -e 'const {resolveVersion}=require("./ci/resolve-version.cjs"); console.log("Resolved Mini Program version:", resolveVersion(process.cwd()))'
node -e 'const {resolveUploadDesc}=require("./ci/resolve-upload-desc.cjs"); console.log("Resolved upload remark:", resolveUploadDesc({repoRoot:require("path").resolve(".."), versionLabel:process.env.MINIAPP_VERSION_LABEL}))'
# Normalize PEM newlines that may be flattened when stored in Secrets.
# 用 node 处理(部分 runner 无 python3
node - <<'JS'
const fs = require("fs");
const p = process.env.WECHAT_CI_PRIVATE_KEY_PATH;
let t = fs.readFileSync(p, "utf8");
if (t.includes("\\n") && t.includes("BEGIN")) t = t.split("\\n").join("\n");
t = t.split("\r\n").join("\n").trim() + "\n";
fs.writeFileSync(p, t);
if (!/PRIVATE KEY/.test(t)) { console.error("WECHAT_CI_PRIVATE_KEY is not a PEM private key"); process.exit(1); }
console.log("private_key_lines=", t.split("\n").length);
JS
node ci/upload-ci.cjs
test -s ci-artifacts/upload-result.json
cat ci-artifacts/upload-result.json
- name: Send success notification
if: success()
env:
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
run: |
VERSION="$(tr -d '\n' < mini/ci-artifacts/resolved-version.txt)"
bash .gitea/scripts/notify.sh success "小程序开发版上传成功" "版本: ${VERSION}" || echo "通知发送失败,不影响主流程"
- name: Send failure notification
if: failure()
env:
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
run: |
bash .gitea/scripts/notify.sh failure \
"小程序开发版上传失败" \
"请检查 Actions 日志了解失败原因" || echo "通知发送失败"
- name: Remove temporary credentials
if: always()
run: rm -f "$RUNNER_TEMP/wechat-ci.key"