fix: artifact 改为单文件 tar 传递(v3 逐文件上传时 Gitea finalize 500)

实测 run #56:upload-artifact@v3 传 public/ 目录时会逐文件上传 3216 个
blob(376MB),文件全部传完后 finalize 调用被 Gitea 拒绝:
  Finalize artifact upload - Attempt 1..5 of 5 failed: Request timeout
  ::error::Finalize artifact upload failed: Artifact service responded with 500
整轮 build 白跑约 30 分钟(v3 已越过 v4 的 'not supported on GHES' 报错点,
这是另一个独立问题)。

改法:build 侧先把 public/ 打成单个 public.tar.zst(无 zstd 时退 gzip),
只上传这 1 个文件 -> 上传是 1 次 PUT、finalize 常数级开销。
deploy-edgeone 侧下载后解包,产物结构因此完全确定(不再有「多一层
public/」的歧义),原 Normalize 步骤随之删除。

配套:中转机 sync.sh.new 增加「artifact 内 tar 包二次解包」(已上传服务器,
未生效)。
This commit is contained in:
zqlit committed 2026-10-04 11:08:40 +08:00
1 parent ed38f9384b
commit 1f568bbfd1
1 file changed
+47 -18
+47 -18
View File
@@ -226,21 +226,44 @@ jobs:
echo "file_count=${FILE_COUNT}" >> $GITHUB_OUTPUT echo "file_count=${FILE_COUNT}" >> $GITHUB_OUTPUT
echo "total_size=${TOTAL_SIZE}" >> $GITHUB_OUTPUT echo "total_size=${TOTAL_SIZE}" >> $GITHUB_OUTPUT
- name: Upload build artifact (public/) - name: Pack build output (single tarball)
id: pack
# ★ 必须打成「单文件」再上传,不能让 upload-artifact 直接传 public/ 目录。
#
# run #56 实测(2026-10-04):archive v3 收目录时会「逐文件」上传 ——
# 3216 个文件、376MB 全部传完(日志可见 Processed file #3216 / 100%),
# 但紧接着的 finalize 调用被 Gitea 拒绝:
# Finalize artifact upload - Attempt 1..5 of 5 failed: Request timeout
# ::error::Finalize artifact upload failed: Artifact service responded with 500
# 于是整轮 build 白跑约 30 分钟。文件一多,Gitea 侧的合并/登记就扛不住。
# 打包成 1 个文件后,上传是 1 次 PUT、finalize 是常数级开销。
# 顺带:tar.zst 也正是原 COS 链路用过的形态,中转机侧解包逻辑可直接复用。
run: |
if command -v zstd >/dev/null 2>&1; then
tar -c public | zstd -3 -T0 -o public.tar.zst
F=public.tar.zst
else
# 兜底:万一 runner 镜像没带 zstd(gzip 一定在)
tar -czf public.tar.gz public
F=public.tar.gz
fi
echo "file=$F" >> $GITHUB_OUTPUT
ls -lh "$F"
- name: Upload build artifact
# 2026-10-04 起产物不再上传腾讯云 COS,改用 Gitea artifact 传递: # 2026-10-04 起产物不再上传腾讯云 COS,改用 Gitea artifact 传递:
# - deploy-edgeone 用 actions/download-artifact 直接拿(同 runner,零跨境) # - deploy-edgeone 用 actions/download-artifact 直接拿(同 runner,零跨境)
# - 国内中转机用 Gitea API 下载 artifact zip(替代原先的「从 COS 下载」) # - 国内中转机用 Gitea API 下载 artifact(替代原先的「从 COS 下载」)
# #
# ★ 必须用 v3,不能用 v4:实测 v4 在 Gitea 上直接失败 —— # ★ 必须用 v3,不能用 v4:实测 v4 在 Gitea 上直接失败 ——
# "@actions/artifact v2.0.0+, upload-artifact@v4+ and download-artifact@v4+ # "@actions/artifact v2.0.0+, upload-artifact@v4+ and download-artifact@v4+
# are not currently supported on GHES."(Gitea 被识别为 GHES,未实现新版 # are not currently supported on GHES."(Gitea 被识别为 GHES,未实现新版
# artifact 服务)。v3 走的是 Gitea 已实现的旧 artifact API。 # artifact 服务)。v3 走的是 Gitea 已实现的旧 artifact API。
# v3 也没有 include-hidden-files 选项;隐藏文件能不能进 artifact 不可靠, # ★ path 只指向上一步打好的那 1 个文件(见上方 finalize 500 的教训)。
# 所以 hash 另外写了一份非隐藏的 public/build_hash.txt 兜底。
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: hugo-public name: hugo-public
path: public/ path: ${{ steps.pack.outputs.file }}
retention-days: 7 retention-days: 7
- name: Report deploy status (built) - name: Report deploy status (built)
@@ -430,28 +453,34 @@ jobs:
- name: Download build artifact - name: Download build artifact
id: download-files id: download-files
# 从 Gitea artifact 下载 public/(build job 上传的,同 runner 零跨境、零费用) # 从 Gitea artifact 下载(build job 上传的,同 runner 零跨境、零费用)
# ★ 必须与上传端同为 v3:v4 在 Gitea(被识别为 GHES)上不受支持。 # ★ 必须与上传端同为 v3:v4 在 Gitea(被识别为 GHES)上不受支持。
uses: actions/download-artifact@v3 uses: actions/download-artifact@v3
with: with:
name: hugo-public name: hugo-public
path: public/ path: .
- name: Normalize artifact layout - name: Unpack build artifact
# upload-artifact 对「目录路径」的打包语义存在版本/实现差异: # artifact 里只有 1 个打包文件(public.tar.zst / .tar.gz),解出来就是
# 解出来的可能是 public/index.html(内容直接在根),也可能是 # public/index.html 在根。不再有 upload-artifact「目录语义」导致的
# public/public/index.html(多一层目录)。这里统一拍平成 public/index.html, # 「多一层 public/」问题,产物结构完全确定。
# 免得 EdgeOne 部署时找不到入口、或站点多出一层 /public/ 前缀。
run: | run: |
if [ ! -f public/index.html ] && [ -f public/public/index.html ]; then set -o pipefail
echo "ℹ️ 检测到产物多一层 public/,已拍平" T=$(find . -maxdepth 1 -type f \( -name 'public.tar.zst' -o -name 'public.tar.gz' \) -print -quit)
mv public/public public__flat if [ -z "$T" ]; then
rm -rf public echo "❌ artifact 里没找到 public.tar.zst / public.tar.gz"
mv public__flat public ls -la
exit 1
fi fi
echo "ℹ️ 解包 $T ($(du -h "$T" | cut -f1))"
rm -rf public
case "$T" in
*.zst) zstd -dc "$T" | tar -x ;;
*) tar -xzf "$T" ;;
esac
if [ ! -f public/index.html ]; then if [ ! -f public/index.html ]; then
echo "❌ 产物结构异常:public/index.html 不存在" echo "❌ 产物结构异常:public/index.html 不存在"
find public -maxdepth 2 | head -20 find . -maxdepth 2 | head -20
exit 1 exit 1
fi fi
echo "✅ public/index.html 就位,文件数 $(find public -type f | wc -l)" echo "✅ public/index.html 就位,文件数 $(find public -type f | wc -l)"