mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-16 13:03:31 +08:00
Windows releases were shipping both NSIS exe and MSI bundles, which made the release page harder to understand and increased the chance that users would pick the wrong asset. Restricting Windows output to MSI narrows the installer surface while the release asset naming now spells out platform, architecture, and bundle type directly in every published filename. Constraint: Remote desktop packaging is triggered by GitHub Actions releases, not local uploads Constraint: Updater metadata must keep latest.json stable for existing clients Rejected: Keep publishing both NSIS and MSI with better docs | still leaves the higher-risk installer on the release page Rejected: Rename assets manually after upload | easy to drift from workflow output and updater metadata Confidence: high Scope-risk: moderate Reversibility: clean Directive: If Windows exe bundles are reintroduced later, reassess SmartScreen and AV impact before publishing them again Tested: YAML parse for both desktop workflows; git diff --check on modified files; manual review of PowerShell changes Not-tested: End-to-end GitHub Actions release run; PowerShell parser validation on a Windows host
246 lines
10 KiB
YAML
246 lines
10 KiB
YAML
name: Build Desktop (Dev)
|
||
|
||
# 开发阶段构建 — 不创建 Release,只上传 Artifacts 供下载测试
|
||
on:
|
||
workflow_dispatch:
|
||
inputs:
|
||
platforms:
|
||
description: 'Build platforms'
|
||
required: true
|
||
default: 'all'
|
||
type: choice
|
||
options:
|
||
- all
|
||
- macos-arm64
|
||
- macos-x64
|
||
- windows-x64
|
||
- linux-x64
|
||
- linux-arm64
|
||
|
||
permissions:
|
||
contents: read
|
||
|
||
concurrency:
|
||
group: build-desktop-dev-${{ github.ref }}
|
||
cancel-in-progress: true
|
||
|
||
jobs:
|
||
# ── 动态生成构建矩阵 ──────────────────────────────────────
|
||
prepare:
|
||
runs-on: ubuntu-latest
|
||
outputs:
|
||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||
steps:
|
||
- id: set-matrix
|
||
run: |
|
||
ALL='[{"platform":"macos-latest","rust_target":"aarch64-apple-darwin","tauri_args":"--target aarch64-apple-darwin","bundles":"app,dmg","label":"macOS-ARM64","artifact_name":"macos-arm64","asset_platform":"macos","asset_arch":"arm64"},{"platform":"macos-latest","rust_target":"x86_64-apple-darwin","tauri_args":"--target x86_64-apple-darwin","bundles":"app,dmg","label":"macOS-x64","artifact_name":"macos-x64","asset_platform":"macos","asset_arch":"x64"},{"platform":"windows-latest","rust_target":"x86_64-pc-windows-msvc","tauri_args":"","bundles":"msi","label":"Windows-x64","artifact_name":"windows-x64","asset_platform":"windows","asset_arch":"x64"},{"platform":"ubuntu-22.04","rust_target":"x86_64-unknown-linux-gnu","tauri_args":"","bundles":"deb","label":"Linux-x64","artifact_name":"linux-x64","asset_platform":"linux","asset_arch":"x64"},{"platform":"ubuntu-22.04-arm","rust_target":"aarch64-unknown-linux-gnu","tauri_args":"","bundles":"deb","label":"Linux-ARM64","artifact_name":"linux-arm64","asset_platform":"linux","asset_arch":"arm64"}]'
|
||
|
||
SELECTED="${{ inputs.platforms }}"
|
||
if [ "$SELECTED" = "all" ]; then
|
||
MATRIX=$(echo "$ALL" | jq -c '{include: .}')
|
||
else
|
||
MATRIX=$(echo "$ALL" | jq -c --arg sel "$SELECTED" '{include: [.[] | select(
|
||
($sel == "macos-arm64" and .label == "macOS-ARM64") or
|
||
($sel == "macos-x64" and .label == "macOS-x64") or
|
||
($sel == "windows-x64" and .label == "Windows-x64") or
|
||
($sel == "linux-x64" and .label == "Linux-x64") or
|
||
($sel == "linux-arm64" and .label == "Linux-ARM64")
|
||
)]}')
|
||
fi
|
||
echo "matrix=$MATRIX" >> "$GITHUB_OUTPUT"
|
||
|
||
# ── 构建 ────────────────────────────────────────────────────
|
||
build:
|
||
needs: prepare
|
||
strategy:
|
||
fail-fast: false
|
||
matrix: ${{ fromJson(needs.prepare.outputs.matrix) }}
|
||
|
||
runs-on: ${{ matrix.platform }}
|
||
name: Build (${{ matrix.label }})
|
||
|
||
steps:
|
||
- name: Checkout
|
||
uses: actions/checkout@v4
|
||
|
||
# ── 读取版本号 ───────────────────────────────────────────
|
||
- name: Read version
|
||
id: version
|
||
shell: bash
|
||
run: |
|
||
VERSION=$(jq -r '.version' desktop/src-tauri/tauri.conf.json)
|
||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||
|
||
# ── 系统依赖 (Linux) ─────────────────────────────────────
|
||
# libfuse2 是 AppImage 运行时依赖:linuxdeploy 工具链本身是 AppImage 格式,
|
||
# 运行时需要 libfuse2,Ubuntu 22.04 默认未安装。
|
||
- name: Install Linux dependencies
|
||
if: contains(matrix.platform, 'ubuntu')
|
||
run: |
|
||
sudo apt-get update
|
||
sudo apt-get install -y \
|
||
build-essential curl wget file \
|
||
libxdo-dev libssl-dev \
|
||
libwebkit2gtk-4.1-dev \
|
||
libayatana-appindicator3-dev \
|
||
librsvg2-dev patchelf \
|
||
libfuse2
|
||
|
||
# ── Bun ──────────────────────────────────────────────────
|
||
- name: Setup Bun
|
||
uses: oven-sh/setup-bun@v2
|
||
with:
|
||
bun-version: latest
|
||
|
||
# ── Node.js ──────────────────────────────────────────────
|
||
- name: Setup Node.js
|
||
uses: actions/setup-node@v4
|
||
with:
|
||
node-version: 20
|
||
|
||
# ── Rust ─────────────────────────────────────────────────
|
||
- name: Setup Rust
|
||
uses: dtolnay/rust-toolchain@stable
|
||
with:
|
||
targets: ${{ matrix.rust_target }}
|
||
|
||
- name: Rust cache
|
||
uses: swatinem/rust-cache@v2
|
||
with:
|
||
workspaces: 'desktop/src-tauri -> target'
|
||
shared-key: ${{ matrix.rust_target }}
|
||
|
||
# ── 安装依赖 ─────────────────────────────────────────────
|
||
- name: Install root dependencies
|
||
run: bun install
|
||
|
||
- name: Install desktop dependencies
|
||
working-directory: desktop
|
||
run: bun install
|
||
|
||
- name: Install adapter dependencies
|
||
working-directory: adapters
|
||
run: bun install
|
||
|
||
# ── 构建 sidecars ────────────────────────────────────────
|
||
- name: Build sidecars
|
||
working-directory: desktop
|
||
env:
|
||
TAURI_ENV_TARGET_TRIPLE: ${{ matrix.rust_target }}
|
||
run: bun run build:sidecars
|
||
|
||
# ── 构建 Tauri (无签名、无 updater) ──────────────────────
|
||
- name: Build Tauri app
|
||
working-directory: desktop
|
||
env:
|
||
TAURI_ENV_TARGET_TRIPLE: ${{ matrix.rust_target }}
|
||
run: |
|
||
# 开发构建: 禁用 updater artifacts (不需要签名密钥)
|
||
echo '{"bundle":{"createUpdaterArtifacts":false}}' > /tmp/dev-build.json
|
||
|
||
ARGS=(bunx tauri build --bundles ${{ matrix.bundles }} --ci --config /tmp/dev-build.json)
|
||
|
||
if [ -n "${{ matrix.tauri_args }}" ]; then
|
||
ARGS+=(${{ matrix.tauri_args }})
|
||
fi
|
||
|
||
"${ARGS[@]}"
|
||
shell: bash
|
||
|
||
# ── 收集产物 ─────────────────────────────────────────────
|
||
- name: Collect artifacts
|
||
id: collect
|
||
shell: bash
|
||
run: |
|
||
BUNDLE_DIR="desktop/src-tauri/target/${{ matrix.rust_target }}/release/bundle"
|
||
FALLBACK_DIR="desktop/src-tauri/target/release/bundle"
|
||
|
||
# 优先使用带 target 的路径
|
||
if [ -d "$BUNDLE_DIR" ]; then
|
||
SEARCH_DIR="$BUNDLE_DIR"
|
||
else
|
||
SEARCH_DIR="$FALLBACK_DIR"
|
||
fi
|
||
|
||
STAGING="desktop/build-artifacts/ci-Claude-Code-Haha-v${{ steps.version.outputs.version }}-${{ matrix.artifact_name }}"
|
||
mkdir -p "$STAGING"
|
||
|
||
echo "Searching for artifacts in: $SEARCH_DIR"
|
||
if [ -d "$SEARCH_DIR" ]; then
|
||
find "$SEARCH_DIR" \
|
||
\( -type f \( \
|
||
-name "*.dmg" -o -name "*.msi" -o \
|
||
-name "*.deb" -o -name "*.AppImage" -o -name "*.zip" \
|
||
\) \) -o \
|
||
\( -type d -name "*.app" \) | while read -r f; do
|
||
base="$(basename "$f")"
|
||
bundle="artifact"
|
||
ext=""
|
||
|
||
case "$base" in
|
||
*.app)
|
||
bundle="app"
|
||
ext=".app"
|
||
;;
|
||
*.dmg)
|
||
bundle="dmg"
|
||
ext=".dmg"
|
||
;;
|
||
*.msi)
|
||
bundle="msi"
|
||
ext=".msi"
|
||
;;
|
||
*.deb)
|
||
bundle="deb"
|
||
ext=".deb"
|
||
;;
|
||
*.AppImage)
|
||
bundle="appimage"
|
||
ext=".AppImage"
|
||
;;
|
||
*.zip)
|
||
bundle="zip"
|
||
ext=".zip"
|
||
;;
|
||
*)
|
||
ext=""
|
||
;;
|
||
esac
|
||
|
||
target="Claude-Code-Haha_${{ steps.version.outputs.version }}_${{ matrix.asset_platform }}_${{ matrix.asset_arch }}_${bundle}${ext}"
|
||
echo " Copying: ${base} -> ${target}"
|
||
cp -R "$f" "$STAGING/$target"
|
||
done
|
||
fi
|
||
|
||
echo "staging_dir=$STAGING" >> "$GITHUB_OUTPUT"
|
||
echo "=== Collected artifacts ==="
|
||
ls -lh "$STAGING/" 2>/dev/null || echo "(empty)"
|
||
|
||
# ── 上传为 GitHub Artifact ───────────────────────────────
|
||
- name: Upload artifacts
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: Claude-Code-Haha-v${{ steps.version.outputs.version }}-${{ matrix.artifact_name }}
|
||
path: ${{ steps.collect.outputs.staging_dir }}
|
||
retention-days: 7
|
||
if-no-files-found: warn
|
||
|
||
# ── 构建完成汇总 ────────────────────────────────────────────
|
||
summary:
|
||
needs: build
|
||
runs-on: ubuntu-latest
|
||
if: always()
|
||
steps:
|
||
- name: Build summary
|
||
run: |
|
||
echo "## Desktop Dev Build Summary" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "| Platform | Status |" >> $GITHUB_STEP_SUMMARY
|
||
echo "|----------|--------|" >> $GITHUB_STEP_SUMMARY
|
||
echo "Branch: \`${{ github.ref_name }}\`" >> $GITHUB_STEP_SUMMARY
|
||
echo "Commit: \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "📦 Artifacts are available for download from the **Artifacts** section above." >> $GITHUB_STEP_SUMMARY
|
||
echo "Artifacts will be retained for **7 days**." >> $GITHUB_STEP_SUMMARY
|