Skip to content

fix(ci): 释放 Linux release job 磁盘空间避免 musl CLI 构建 ENOSPC #15

fix(ci): 释放 Linux release job 磁盘空间避免 musl CLI 构建 ENOSPC

fix(ci): 释放 Linux release job 磁盘空间避免 musl CLI 构建 ENOSPC #15

Workflow file for this run

# Zap 发布流水线 — 在 openWarp 分支上 push tag (v*) 即触发
#
# 与上游 create_release.yml 的差异:
# - 仅 macOS arm64 + macOS Intel + Windows x64 + Linux x86_64,
# Web/CLI/Universal/Win-arm64 全砍
# (macOS 双架构分别产单架构 DMG 与 CLI tarball;Linux 产 AppImage/deb/rpm
# 以及尽力而为的 Arch 包,不发布上游 Zap 仓库源或签名 key)
# - 单 channel: preview(由 release_configurations.json 提供配置)
# - 不签名:不传 --read-passwords-from-env(macOS) / 不设 SIGN_TOOL_CMD(Windows)
# - 不上传 GCS / 第三方 crash 平台 / Slack / changelog,不调 channel-versions repository_dispatch
# - 复用 ./.github/actions/{prepare_environment,get_channel_config}
#
# 流水线结构(先打包后发布,避免出现空 Release):
# prepare_metadata → release_{macos,windows,linux} (上传成 workflow artifact)
# → publish_release (全部 build 成功后下载 artifact 并创建 Release)
# 任意 build job 失败 → publish_release 因 needs 跳过 → 不会留下没有安装包的 Release。
name: Zap Release
# PR 验证由 .github/workflows/pr-check.yml 负责(Linux cargo check)。
# 本 workflow 只在 push tag / 手动 dispatch 时跑全量三平台打包,避免 PR 跑 ~3h 浪费。
on:
push:
tags:
- "v*"
workflow_dispatch:
# 创建 release + 上传 asset 需要写权限。默认 GITHUB_TOKEN 在 fork/受限仓库下是只读,
# 这里显式声明 contents: write 兜底 403 "Resource not accessible by integration"。
# actions: write 用于 publish_release 末尾删除本次 run 的 workflow artifact(释放 Actions storage)。
permissions:
contents: write
actions: write
env:
CARGO_TERM_COLOR: always
CONFIG_FILE: ".github/workflows/release_configurations.json"
# Zap fork 用 oss channel(对应 app/src/bin/oss.rs 内联 ChannelConfig,
# 不依赖 warp-channel-config 私有二进制),preview 等内部 channel 走
# channel_config::load_config!() 宏 → build.rs 调 warp-channel-config 失败 →
# *_config.json 不生成 → include_str! 编译失败。
CHANNEL: oss
jobs:
prepare_metadata:
name: Prepare metadata
runs-on: ubuntu-latest
outputs:
release_tag: ${{ steps.compute_tag.outputs.tag }}
release_branch: ${{ steps.compute_tag.outputs.branch }}
release_name: ${{ steps.get-config.outputs.release_base_name }} ${{ steps.compute_tag.outputs.tag }}
steps:
# fetch-depth: 0 让 git-cliff 能看到完整 tag/commit 历史;
# shallow clone 下 `git describe` 找不到上一个 tag,会退化成空 release notes。
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Get channel configuration
id: get-config
uses: ./.github/actions/get_channel_config/
with:
config_file: ${{ env.CONFIG_FILE }}
channel: ${{ env.CHANNEL }}
- name: Compute release tag and branch
id: compute_tag
shell: bash
run: |
# tag-触发场景:GITHUB_REF=refs/tags/<tag>
# workflow_dispatch:GITHUB_REF=refs/heads/<branch>,无 tag,生成临时 tag
if [[ "$GITHUB_REF" == refs/tags/* ]]; then
TAG="${GITHUB_REF#refs/tags/}"
BRANCH="$TAG"
else
TAG="v0.$(date +%Y.%m.%d.%H%M)"
BRANCH="${GITHUB_REF#refs/heads/}"
fi
echo "tag=$TAG" >> $GITHUB_OUTPUT
echo "branch=$BRANCH" >> $GITHUB_OUTPUT
echo "Release tag: $TAG / build ref: $BRANCH"
# 找上一个 release tag(匹配 v*),用于限定 git-cliff 的 commit 范围。
# tag-触发:HEAD == 当前 tag,要从 HEAD^ 起找最近的 v* tag。
# dispatch:HEAD 不是 tag,直接从 HEAD 起找。
# 找不到(首次发布)时输出空字符串,后面 git-cliff 不限定范围。
- name: Compute previous release tag
id: prev_tag
shell: bash
run: |
if [[ "$GITHUB_REF" == refs/tags/* ]]; then
PREV=$(git describe --tags --abbrev=0 --match='v*' HEAD^ 2>/dev/null || echo "")
else
PREV=$(git describe --tags --abbrev=0 --match='v*' HEAD 2>/dev/null || echo "")
fi
echo "prev=$PREV" >> $GITHUB_OUTPUT
echo "Previous tag: ${PREV:-<none, first release>}"
# 用官方推荐的 orhun/git-cliff-action 生成「上个 tag 到 HEAD」的变更说明。
# --strip header 去掉模板顶部空 header;--tag 把 unreleased 段标记为本次发布版本。
# 范围参数 `<prev>..HEAD` 通过三元表达式注入:有 prev 时限定范围,无 prev 时让
# git-cliff 输出全部历史(首次发布场景)。
- name: Generate release notes via git-cliff
uses: orhun/git-cliff-action@98c93442bb05a455a77bee982867857ae748eeea # v4.5.1
with:
config: cliff.toml
args: >-
--strip header
--tag ${{ steps.compute_tag.outputs.tag }}
${{ steps.prev_tag.outputs.prev != '' && format('{0}..HEAD', steps.prev_tag.outputs.prev) || '' }}
env:
OUTPUT: release-notes.md
GITHUB_REPO: ${{ github.repository }}
# 把 release_configurations.json 里的一句固定说明拼到 git-cliff 输出之前,
# 形成最终的 release body。后续 publish_release 用 body_path 注入到 GitHub Release。
- name: Assemble final release body
shell: bash
env:
RELEASE_BODY_TEXT: ${{ steps.get-config.outputs.release_body_text }}
PREV_TAG: ${{ steps.prev_tag.outputs.prev }}
THIS_TAG: ${{ steps.compute_tag.outputs.tag }}
run: |
{
echo "$RELEASE_BODY_TEXT"
echo
if [[ -n "$PREV_TAG" ]]; then
echo "## 自 \`$PREV_TAG\` 以来的更新"
else
echo "## 首发版本变更"
fi
echo
cat release-notes.md
} > release-body.md
echo "---- release-body.md ----"
cat release-body.md
- name: Upload release body artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: release-body
path: release-body.md
if-no-files-found: error
retention-days: 7
release_macos:
name: Build Release (macOS ${{ matrix.dmg_name_suffix }})
runs-on: ${{ matrix.runner }}
needs: prepare_metadata
# macos-26 / macos-26-intel(Pro standard)无 sccache,full cargo build + bundle + create-dmg
# 耗时高;Intel 构建历史上超过 180min,这里放宽到 GitHub-hosted job 6h 执行上限。
timeout-minutes: 360
strategy:
fail-fast: false
matrix:
include:
- arch: aarch64
dmg_name_suffix: arm64
runner: macos-26 # Pro standard arm64 (M2 Pro)
- arch: x86_64
dmg_name_suffix: intel
runner: macos-26-intel # Pro standard Intel
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
ref: ${{ needs.prepare_metadata.outputs.release_branch }}
- uses: ./.github/actions/prepare_environment
with:
target_os: macos
cache_key: macos-${{ matrix.arch }}
is_self_hosted: false
install_release_deps: true
- name: Ensure rust target is installed
run: rustup target add ${{ matrix.arch }}-apple-darwin
shell: bash
- name: Check ${{ matrix.arch }} release compile
run: |
script/bundle --check-only --channel "$CHANNEL" --arch ${{ matrix.arch }} --dmg-name-suffix "${{ matrix.dmg_name_suffix }}" --selfsign
shell: bash
env:
GIT_RELEASE_TAG: ${{ needs.prepare_metadata.outputs.release_tag }}
- name: Setup Go
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
with:
go-version: stable
- name: Install cargo-bundle
run: script/install_cargo_bundle
- name: Install create-dmg
run: brew install create-dmg
# 用 --selfsign 走 ad-hoc 签名(无 Apple Developer cert 时 fallback 到 `-`):
# 1. 让 .app 拥有 cdhash → UNUserNotificationCenter 才肯把 Zap 注册到
# System Settings → Notifications(否则桌面通知静默失效,见 issue #40)。
# 2. ad-hoc + Hardened Runtime + Debug-Entitlements.plist(disable-library-validation
# + get-task-allow)是合法组合,可在 macos-26 runner 上无凭证完成。
# 3. notarize 整段被 `script/macos/bundle` 的 CODESIGN=false 分支跳过;DMG 从
# BUNDLE_DIR 直接 create-dmg,不进 codesign / staple 步骤。
# 4. 用户首次打开仍会触发 Gatekeeper 的「未识别开发者」对话框(无 Developer ID
# notarize 的固有限制);issue #51 提供的 `xattr -rd com.apple.quarantine`
# 自助方案继续有效。
- name: Build ${{ matrix.arch }} bundle (ad-hoc signed)
id: bundle_app
run: |
script/bundle --channel "$CHANNEL" --arch ${{ matrix.arch }} --dmg-name-suffix "${{ matrix.dmg_name_suffix }}" --selfsign
shell: bash
env:
GIT_RELEASE_TAG: ${{ needs.prepare_metadata.outputs.release_tag }}
- name: Upload DMG artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: zap-macos-${{ matrix.dmg_name_suffix }}
path: ${{ steps.bundle_app.outputs.dmg_path }}
if-no-files-found: error
retention-days: 7
- name: Build CLI
id: bundle_cli
run: |
script/bundle --channel "$CHANNEL" --arch ${{ matrix.arch }} --artifact cli --nosign
shell: bash
env:
GIT_RELEASE_TAG: ${{ needs.prepare_metadata.outputs.release_tag }}
- name: Package CLI tarball
run: |
cp "${{ steps.bundle_cli.outputs.binary_path }}" zap-oss
tar czf zap-macos-${{ matrix.arch }}.tar.gz \
zap-oss \
-C "$(dirname "${{ steps.bundle_cli.outputs.bundled_resources_dir }}")" resources
shell: bash
- name: Upload CLI artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: zap-cli-macos-${{ matrix.arch }}
path: zap-macos-${{ matrix.arch }}.tar.gz
if-no-files-found: error
retention-days: 7
release_windows:
name: Build Release (Windows x64)
runs-on: windows-latest
needs: prepare_metadata
timeout-minutes: 180
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
ref: ${{ needs.prepare_metadata.outputs.release_branch }}
- uses: ./.github/actions/prepare_environment
with:
target_os: windows
cache_key: x64
is_self_hosted: false
install_release_deps: true
- name: Build binary (unsigned)
id: build_binary
run: script/bundle -Channel $CHANNEL -skip_build_installer --arch x64
shell: bash
env:
GIT_RELEASE_TAG: ${{ needs.prepare_metadata.outputs.release_tag }}
- name: Bundle app (unsigned installer)
id: bundle_app
run: script/bundle -Channel $CHANNEL -skip_build_binary --arch x64
shell: bash
env:
GIT_RELEASE_TAG: ${{ needs.prepare_metadata.outputs.release_tag }}
- name: Upload installer artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: zap-windows-x64
path: ${{ steps.bundle_app.outputs.installer_path }}
if-no-files-found: error
retention-days: 7
release_linux:
name: Build Release (Linux x86_64)
runs-on: ubuntu-22.04
needs: prepare_metadata
# 用 22.04 (glibc 2.35) 而不是 ubuntu-latest (24.04, glibc 2.39),
# AppImage 用 host glibc 链接,22.04 产物能在更多旧发行版上跑
# (Debian 11 / Ubuntu 20.04 + 等)。
timeout-minutes: 180
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
ref: ${{ needs.prepare_metadata.outputs.release_branch }}
# GitHub-hosted ubuntu runner 的 / 余量有限,而本 job 先后在同一磁盘产出
# release-lto(GUI/AppImage/deb/rpm/arch)与 release-cli(musl CLI)两份完整
# target,叠加 cargo registry / docker 镜像 / zig 工具链后会撑爆磁盘,musl CLI
# 步骤报 "No space left on device"(见 run 27593938453)。先删掉与本构建无关的
# 预装工具链(Android SDK / .NET / GHC / CodeQL / Swift),腾出 ~25GB。
- name: Free up disk space
shell: bash
run: |
sudo rm -rf /usr/local/lib/android /usr/share/dotnet /opt/ghc \
/usr/local/.ghcup /opt/hostedtoolcache/CodeQL /usr/share/swift || true
df -h /
- uses: ./.github/actions/prepare_environment
with:
target_os: linux
is_self_hosted: false
install_release_deps: true
- name: Install extra dependencies for deb/rpm and build
run: |
sudo apt-get update
# `rpm` 包提供 /usr/bin/rpmbuild,给后面的 RPM 打包步骤用。
sudo apt-get install -y libdbus-1-dev fakeroot rpm
shell: bash
- name: Ensure rust target is installed
run: rustup target add x86_64-unknown-linux-gnu
shell: bash
- name: Check Linux release compile
run: script/bundle --check-only --channel "$CHANNEL" --arch x86_64 --packages appimage,deb
shell: bash
env:
GIT_RELEASE_TAG: ${{ needs.prepare_metadata.outputs.release_tag }}
- name: Install linuxdeploy
# script/linux/install_linuxdeploy 不被 install_build_deps 调用,需手动跑;
# 它把 linuxdeploy AppImage 放到 ~/.local/bin,加到 PATH 里。
run: |
./script/linux/install_linuxdeploy
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
shell: bash
- name: Build AppImage (unsigned)
id: bundle_app
run: script/bundle --channel "$CHANNEL" --arch x86_64 --packages appimage,deb
shell: bash
env:
GIT_RELEASE_TAG: ${{ needs.prepare_metadata.outputs.release_tag }}
# ubuntu-22.04 默认有 libfuse2 但 24.04 没有;统一开 EXTRACT_AND_RUN
# 让 linuxdeploy/appimagetool 不依赖 FUSE 内核模块,跨 runner 版本都稳。
APPIMAGE_EXTRACT_AND_RUN: 1
# RPM 包:复用上一步 release-lto 已经 strip 过的 `target/release-lto/zap-oss`,
# 不重新 `cargo build`。`--skip-build` 让 `script/bundle` 跳过编译与 strip,
# 直接进入 staging(`bundle_install` → 复制二进制 + resources)+ rpmbuild。
# 与 deb 同一台 ubuntu-22.04 runner 上跑,共享 host glibc 链接的产物;
# 用 Fedora 26+ / RHEL 8+ 上的 RPM 4.13+ 安装(spec 用了 boolean dep 语法)。
# continue-on-error: 即便 rpmbuild 失败也不应阻塞 AppImage/deb 已经成功的发布。
- name: Build RPM package (reuse release-lto binary)
continue-on-error: true
run: script/bundle --skip-build --channel "$CHANNEL" --arch x86_64 --packages rpm
shell: bash
env:
GIT_RELEASE_TAG: ${{ needs.prepare_metadata.outputs.release_tag }}
# Arch 包:复用上一步 release-lto 已经 strip 过的 `target/release-lto/zap-oss`,
# 不重新 `cargo build` 主二进制 —— `--skip-build` 让 `script/bundle` 跳过编译与 strip,
# 直接进入 staging(`bundle_install` → 复制二进制 + resources)+ makepkg。
#
# 为什么放容器里:`makepkg` 是 Arch 独有,Ubuntu runner 没有。
# 容器里只装 Arch 自带的 `rust` 和 `cargo-about`:
# - SKIP_SETTINGS_SCHEMA=1 后,不再跑 `cargo run --bin generate_settings_schema`,
# 所以容器里 rustc 版本跟项目锁定版(1.92.x) 不一致也无所谓。
# - `cargo about generate` 只读 Cargo.lock 元数据生成第三方 license,
# 不触发任何 Rust 代码编译。
# makepkg 拒绝 root 运行(EUID==0),必须切到非 root 用户。
# continue-on-error: Arch 工具链炸了不影响 AppImage/deb 发布。
- name: Build Arch package (reuse release-lto binary)
continue-on-error: true
run: |
set -euo pipefail
# 用 host runner 用户的 uid/gid 在容器里建 builder,免去 chown 整棵
# /work 与 ~/.cargo 的开销(makepkg 拒绝 root,但 uid != 0 即可,
# 用什么名字、什么具体 uid 都行)。
HOST_UID=$(id -u)
HOST_GID=$(id -g)
# 注意:不要把 GITHUB_ACTIONS=true 透传进容器。
# script/bundle 看到该变量后会 `echo ... >> "$GITHUB_OUTPUT"`,
# 而容器里没有 GITHUB_OUTPUT,redirect 到空字符串触发 `set -e` 退出,
# Arch 包根本就构建不出来(见 run 26153630745)。
# 我们也不需要该步骤的 step outputs —— 它 continue-on-error,
# packages_dir 由前面 AppImage 步骤的 bundle_app.outputs 提供。
docker run --rm \
-v "$PWD:/work" \
-v "$HOME/.cargo:/cargo-home" \
-w /work \
-e GIT_RELEASE_TAG="${{ needs.prepare_metadata.outputs.release_tag }}" \
-e SKIP_SETTINGS_SCHEMA=1 \
-e HOST_UID="$HOST_UID" \
-e HOST_GID="$HOST_GID" \
archlinux:latest bash -euxc '
# 预装 PKGBUILD `depends` 里的运行时依赖,避免 makepkg -s
# 在容器内调 `sudo pacman -S` 装缺包(builder 没有免密 sudo,
# 会因为读不到密码退出 8,Arch 包就此漏掉,见 run 26267606877)。
# `opengl-driver` 在官方仓库里不存在(NixOS 概念 / AUR 虚拟包),
# 单独用 --assume-installed 让依赖检查跳过它。
pacman -Sy --noconfirm --needed \
base-devel git sudo rust cargo-about \
curl default-cursors fontconfig libegl libx11 libxcb \
libxcursor libxi libxkbcommon-x11 xdg-utils zlib &&
# 用 host uid/gid 建用户,挂进来的 /work 与 /cargo-home owner 就是它,
# 不用 chown,直接 sudo -u 即可读写。
groupadd -g "$HOST_GID" builder 2>/dev/null || true
useradd -u "$HOST_UID" -g "$HOST_GID" -m builder
# 显式给 HOME=/home/builder,否则 `sudo -E` 会保留外层 HOME=/root,
# 导致 `git config --global` 试图写 /root/.gitconfig 报 Permission denied。
sudo -u builder -E env \
HOME=/home/builder \
CARGO_HOME=/cargo-home \
PATH=/cargo-home/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin \
bash -c "
git config --global --add safe.directory /work
cd /work
# 依赖已在外层 pacman 装好;告诉 makepkg `opengl-driver`
# 视为已安装,避免它去 pacman -S 一个仓库里没有的包。
# 另外带 --noconfirm:容器里没透传 GITHUB_ACTIONS,
# bundle_arch 里原生的那个分支不会生效。
MAKEPKG_EXTRA_ARGS='\''--noconfirm --assume-installed opengl-driver'\'' \
script/bundle --skip-build --channel oss --arch x86_64 --packages arch
"
'
shell: bash
- name: Upload package artifacts
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: zap-linux-x86_64
# packages_dir 是 target/release-lto/bundle/linux,AppImage/deb/Arch 都落在这里
path: ${{ steps.bundle_app.outputs.packages_dir }}
if-no-files-found: error
retention-days: 7
# release-lto 产物(GUI/deb/rpm/arch)已由上一步 "Upload package artifacts"
# 上传为 workflow artifact,本地不再需要;下面的 musl CLI 走独立的 release-cli
# profile,删掉 release-lto 给它腾磁盘,避免 "No space left on device"。
- name: Reclaim disk before musl CLI build
shell: bash
run: |
rm -rf target/release-lto
df -h /
# CLI/remote-server tarball 用静态 musl 链接,产物不依赖宿主 glibc,
# 可在任意 Linux x86_64 主机(含 CentOS 7 / Amazon Linux 2 等旧 glibc
# 以及 Alpine 等 musl 发行版)上运行。GUI AppImage/deb 仍走上面的
# glibc 链接构建,不受影响。
#
# 用 `cargo zigbuild` 做 musl 交叉编译:zig 自带完整的 C/C++ musl
# 工具链(`zig cc` / `zig c++`),不依赖宿主的 `musl-gcc` 或手写的
# `musl-g++` wrapper —— 历史上为 freetype-sys / harfbuzz-sys 等 *-sys
# 依赖准备的「宿主 g++ + musl specs」hack 因此整条移除。
# 本地 dev 自动构建路径(`ssh_transport.rs`)也优先用 zigbuild,两边
# 工具链统一。
- name: Install zig + cargo-zigbuild for static musl CLI build
run: |
set -euo pipefail
rustup target add x86_64-unknown-linux-musl
# zig:用官方预编译 tarball,固定版本以保证构建可复现。
# 0.13.0 与 cargo-zigbuild >= 0.19 兼容。
ZIG_VERSION="0.13.0"
ZIG_DIR="$HOME/.local/zig-${ZIG_VERSION}"
if [ ! -x "${ZIG_DIR}/zig" ]; then
mkdir -p "${ZIG_DIR}"
curl -fsSL "https://ziglang.org/download/${ZIG_VERSION}/zig-linux-x86_64-${ZIG_VERSION}.tar.xz" \
| tar -xJ -C "${ZIG_DIR}" --strip-components=1
fi
echo "${ZIG_DIR}" >> "$GITHUB_PATH"
# cargo-zigbuild:走 cargo install,首次安装在缓存里之后会复用。
cargo install --locked cargo-zigbuild --version ^0.19
shell: bash
- name: Build CLI (static musl via zigbuild)
id: bundle_cli
run: |
script/bundle --channel "$CHANNEL" --arch x86_64 --artifact cli --packages none \
--target x86_64-unknown-linux-musl
shell: bash
env:
GIT_RELEASE_TAG: ${{ needs.prepare_metadata.outputs.release_tag }}
APPIMAGE_EXTRACT_AND_RUN: 1
# 让 script/linux/bundle 把 `cargo build` 切到 `cargo zigbuild`。
USE_ZIGBUILD: "true"
# libc(musl)被 +crt-static 静态链接进二进制 —— 这是让产物摆脱
# 宿主 glibc 下限的关键。`libdbus-sys` 现在通过 keyring 的
# `vendored` feature 从源码内嵌编译(见 Cargo.toml),不再用 pkg-config
# 探测宿主 `dbus-1`;`PKG_CONFIG_ALLOW_CROSS=1` 保留作兜底,
# 万一某个新引入的 -sys crate 还在用 pkg-config 也不会卡。
PKG_CONFIG_ALLOW_CROSS: 1
- name: Package CLI tarball
run: |
cp "${{ steps.bundle_cli.outputs.executable_path }}" zap-oss
tar czf zap-linux-x86_64.tar.gz \
zap-oss \
-C "$(dirname "${{ steps.bundle_cli.outputs.bundled_resources_dir }}")" resources
shell: bash
- name: Upload CLI artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: zap-cli-linux-x86_64
path: zap-linux-x86_64.tar.gz
if-no-files-found: error
retention-days: 7
publish_release:
name: Publish GitHub Release
runs-on: ubuntu-latest
# 必须等所有平台都 build 成功才发布;任一失败 → 此 job 跳过 → 不会出现空 Release。
needs:
- prepare_metadata
- release_macos
- release_windows
- release_linux
steps:
- name: Download all artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
path: dist
merge-multiple: true
# release-body artifact 是给 GitHub Release 描述用的,不是要挂到 Release 资产列表的产物。
# 提前从 dist/ 移到独立路径,避免 `files: dist/*` 把它当成 asset 上传。
- name: Extract release body from artifacts
shell: bash
run: |
mv dist/release-body.md ./release-body.md
echo "---- release-body.md ----"
cat ./release-body.md
- name: List downloaded files
run: ls -lh dist
shell: bash
- name: Create GitHub release with all assets
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2
with:
name: ${{ needs.prepare_metadata.outputs.release_name }}
tag_name: ${{ needs.prepare_metadata.outputs.release_tag }}
body_path: ./release-body.md
draft: false
prerelease: false
make_latest: "true"
files: dist/*
token: ${{ secrets.GITHUB_TOKEN }}
# 发布成功后立刻删本次 run 的 workflow artifact,释放 Actions storage 配额。
# 安装包已经挂到 GitHub Release(独立存储,不占 Actions storage),
# workflow artifact 只是 build job → publish job 的中间传递管道,留着没用。
# 仅在 Release 创建成功后执行(if: success()),失败保留 artifact 方便复盘。
- name: Delete workflow artifacts to free Actions storage
if: success()
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
ids=$(gh api "repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts" --jq '.artifacts[].id')
for id in $ids; do
echo "Deleting artifact $id"
gh api -X DELETE "repos/${{ github.repository }}/actions/artifacts/$id"
done
shell: bash