Skip to content

Dev (#5)

Dev (#5) #15

Workflow file for this run

---
name: CLI-UI Build & Release
# 🚀 CLI-UI 桌面应用构建和发布说明:
# 1. 构建 Duck CLI GUI 桌面应用,内置 nuwax-cli 作为 sidecar
# 2. 基于 CLI-UI 版本变化自动触发构建和发布
# 3. nuwax-cli 仅作为内嵌组件构建,不单独发布
# 4. 使用官方 tauri-action 简化构建流程,自动处理签名和更新
# 5. 支持跨平台:Linux, Windows, macOS (Intel & Apple Silicon)
# 6. 🖥️ 自定义Runner配置:
# - Windows: [self-hosted, Windows, X64] - 使用SODDY runner
# - macOS: [self-hosted, macOS, ARM64] - 使用soddys-Mac-mini runner
# - Linux: 继续使用GitHub托管的ubuntu runner
on:
push:
branches: [main]
paths:
- 'nuwax-cli/**'
- 'client-core/**'
- 'cli-ui/**'
- '.github/workflows/cli-ui-build.yml'
pull_request:
branches: [main]
paths:
- 'duck-cli/**'
- 'client-core/**'
- 'cli-ui/**'
- '.github/workflows/cli-ui-build.yml'
workflow_dispatch:
inputs:
force_cli_ui_release:
description: 'Force release CLI-UI even if version unchanged'
required: false
default: false
type: boolean
# 添加必要的权限配置
permissions:
contents: write # 需要写权限来创建 release
actions: read
env:
CARGO_TERM_COLOR: always
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD || '' }}
jobs:
# 检查版本变化和决定发布策略
check-versions:
name: Check Versions & Release Strategy
runs-on: ubuntu-latest
outputs:
# CLI-UI 相关输出
cli_ui_version: ${{ steps.cli_ui_check.outputs.version }}
cli_ui_tag_name: ${{ steps.cli_ui_check.outputs.tag_name }}
cli_ui_should_release: ${{ steps.cli_ui_check.outputs.should_release }}
# 构建策略
should_build: ${{ steps.build_strategy.outputs.should_build }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0 # 获取完整历史以检查现有 tags
- name: Check CLI-UI version
id: cli_ui_check
if: ${{ github.ref == 'refs/heads/main' }}
run: |
# 从 cli-ui/src-tauri/tauri.conf.json 读取版本号
VERSION=$(cat cli-ui/src-tauri/tauri.conf.json | grep '"version"' | head -1 | sed 's/.*"version": "\(.*\)".*/\1/')
TAG_NAME="cli-ui-v${VERSION}"
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "tag_name=${TAG_NAME}" >> $GITHUB_OUTPUT
echo "📋 检测到 CLI-UI 版本: ${VERSION}"
echo "📋 对应标签: ${TAG_NAME}"
# 检查这个版本的 tag 是否已经存在
if git tag -l | grep -q "^${TAG_NAME}$"; then
echo "⚠️ CLI-UI 标签 ${TAG_NAME} 已存在"
if [[ "${{ github.event.inputs.force_cli_ui_release }}" == "true" ]]; then
echo "🔧 强制发布 CLI-UI (手动触发)"
echo "should_release=true" >> $GITHUB_OUTPUT
else
echo "📦 CLI-UI 版本 ${VERSION} 已发布,跳过"
echo "should_release=false" >> $GITHUB_OUTPUT
fi
else
echo "✅ 发现 CLI-UI 新版本 ${VERSION},准备发布"
echo "should_release=true" >> $GITHUB_OUTPUT
fi
- name: Determine build strategy
id: build_strategy
run: |
# 如果是 main 分支且 CLI-UI 需要发布,或者是 PR,都需要构建
if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
if [[ "${{ steps.cli_ui_check.outputs.should_release }}" == "true" ]]; then
echo "should_build=true" >> $GITHUB_OUTPUT
echo "🚀 Main 分支检测到 CLI-UI 新版本,开始构建"
else
echo "should_build=false" >> $GITHUB_OUTPUT
echo "📦 Main 分支无 CLI-UI 新版本,跳过构建"
fi
else
echo "should_build=true" >> $GITHUB_OUTPUT
echo "🔧 PR 或其他分支,执行构建用于测试"
fi
# 构建 Duck CLI 二进制文件
build-nuwax-cli:
name: Build Duck CLI for ${{ matrix.platform.name }}
runs-on: ${{ matrix.platform.os }}
needs: check-versions
if: needs.check-versions.outputs.should_build == 'true'
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
platform:
- name: Linux-x86_64
os: ubuntu-22.04
rust_target: x86_64-unknown-linux-gnu
duck_cli_bin: nuwax-cli
duck_cli_archive: nuwax-cli-linux-amd64.tar.gz
cross: false
- name: Linux-aarch64
os: ubuntu-22.04
rust_target: aarch64-unknown-linux-gnu
duck_cli_bin: nuwax-cli
duck_cli_archive: nuwax-cli-linux-arm64.tar.gz
cross: true
- name: Windows-x86_64
os: [self-hosted, Windows, X64]
rust_target: x86_64-pc-windows-msvc
duck_cli_bin: nuwax-cli.exe
duck_cli_archive: nuwax-cli-windows-amd64.zip
cross: false
- name: Windows-aarch64
os: [self-hosted, Windows, X64]
rust_target: aarch64-pc-windows-msvc
duck_cli_bin: nuwax-cli.exe
duck_cli_archive: nuwax-cli-windows-arm64.zip
cross: false
- name: macOS-x86_64
os: macos-13 # 使用 GitHub 托管的 Intel macOS runner
rust_target: x86_64-apple-darwin
duck_cli_bin: nuwax-cli
duck_cli_archive: nuwax-cli-macos-amd64.tar.gz
cross: false
- name: macOS-aarch64
os: [self-hosted, macOS, ARM64]
rust_target: aarch64-apple-darwin
duck_cli_bin: nuwax-cli
duck_cli_archive: nuwax-cli-macos-arm64.tar.gz
cross: false
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Linux dependencies (for Duck CLI build)
if: matrix.platform.name == 'Linux-x86_64' || matrix.platform.name == 'Linux-aarch64'
run: |
echo "Installing Linux dependencies for Duck CLI build"
# Update package lists
sudo apt-get update
# Install basic build dependencies
sudo apt-get install -y \
curl \
wget \
file \
build-essential \
libc6-dev \
m4 \
pkg-config \
libglib2.0-dev \
libglib2.0-0 \
libglib2.0-data \
libglib2.0-bin \
glib-networking \
glib-networking-common \
glib-networking-services
# Set PKG_CONFIG_PATH
echo "PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig:/usr/share/pkgconfig:/usr/lib/pkgconfig:$PKG_CONFIG_PATH" >> $GITHUB_ENV
# Verify GLib installation
echo "Verifying GLib dependencies..."
pkg-config --exists glib-2.0 && echo "✅ glib-2.0 found" || echo "❌ glib-2.0 not found"
- name: Setup WSL Ubuntu (for Linux builds on Windows)
if: matrix.platform.use_wsl == true
run: |
Write-Host "Setting up WSL Ubuntu environment for Linux builds"
# Enable WSL feature if not already enabled
Write-Host "Enabling WSL feature..."
try {
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux -NoRestart -All
Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform -NoRestart -All
} catch {
Write-Host "WSL features may already be enabled or require restart"
}
# Set WSL 2 as default
Write-Host "Setting WSL 2 as default..."
wsl --set-default-version 2
# Install Ubuntu if not present
Write-Host "Checking for Ubuntu distribution..."
$distributions = wsl --list --quiet 2>$null
if (-not $distributions -or $distributions -notcontains "Ubuntu") {
Write-Host "Installing Ubuntu distribution..."
# Use winget to install Ubuntu if available
try {
winget install Canonical.Ubuntu.2204 --silent --accept-source-agreements --accept-package-agreements
} catch {
Write-Host "Winget failed, trying direct installation..."
wsl --install Ubuntu --no-launch
}
} else {
Write-Host "Ubuntu distribution found"
}
# Wait for WSL to be ready
Start-Sleep -Seconds 10
# Initialize Ubuntu (create default user if needed)
Write-Host "Initializing Ubuntu..."
try {
wsl -d Ubuntu -- bash -c 'echo "Ubuntu initialized"'
} catch {
Write-Host "Ubuntu initialization may need interactive setup"
# Try to run Ubuntu without user creation for CI
wsl -d Ubuntu -u root -- bash -c 'echo "Running as root"'
}
# Update package lists
Write-Host "Updating package lists..."
wsl -d Ubuntu -u root -- bash -c 'export DEBIAN_FRONTEND=noninteractive && apt-get update'
# Install basic dependencies
Write-Host "Installing basic dependencies..."
wsl -d Ubuntu -u root -- bash -c 'apt-get install -y curl build-essential pkg-config sudo'
# Install Tauri Linux dependencies
Write-Host "Installing Tauri dependencies..."
wsl -d Ubuntu -u root -- bash -c 'apt-get install -y libwebkit2gtk-4.1-dev libwebkit2gtk-4.0-dev libjavascriptcoregtk-4.1-dev libjavascriptcoregtk-4.0-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev patchelf'
# Install Rust
Write-Host "Installing Rust..."
wsl -d Ubuntu -u root -- bash -c 'curl --proto "=https" --tlsv1.2 -sSf https://sh.rustup.rs -o rustup.sh && chmod +x rustup.sh && ./rustup.sh -y && rm rustup.sh'
# Add target architecture
Write-Host "Adding target architecture..."
wsl -d Ubuntu -u root -- bash -c 'source /root/.cargo/env && rustup target add ${{ matrix.platform.rust_target }}'
# Verify installation
Write-Host "Verifying installation..."
wsl -d Ubuntu -u root -- bash -c 'source /root/.cargo/env && rustc --version && cargo --version'
shell: powershell
- name: Setup Windows Environment
if: matrix.platform.use_wsl != true && runner.os == 'Windows'
run: |
Write-Host "Setting up Windows build environment"
# Check and setup Git Bash environment
if (Test-Path "C:\Program Files\Git\bin\bash.exe") {
Write-Host "Found Git Bash: C:\Program Files\Git\bin\bash.exe"
echo "C:\Program Files\Git\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
} elseif (Test-Path "C:\Program Files (x86)\Git\bin\bash.exe") {
Write-Host "Found Git Bash: C:\Program Files (x86)\Git\bin\bash.exe"
echo "C:\Program Files (x86)\Git\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
} else {
Write-Host "Git Bash not found, using PowerShell instead"
}
# Verify bash availability
try {
$bashVersion = & bash --version 2>$null
Write-Host "Bash version: $bashVersion"
} catch {
Write-Host "Bash not available, will use PowerShell for building"
}
shell: powershell
- name: Install Visual Studio Build Tools (Windows - Duck CLI stage)
if: matrix.platform.use_wsl != true && runner.os == 'Windows'
run: |
Write-Host "=== Duck CLI 阶段:安装 Visual Studio Build Tools ==="
# Check if Visual Studio is already installed
$vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
$vsFound = $false
if (Test-Path $vsWhere) {
$vs = & $vsWhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
if ($vs) {
Write-Host "✅ Visual Studio found: $vs"
$vsFound = $true
# Setup environment for MSVC
$vcvarsPath = "$vs\VC\Auxiliary\Build\vcvars64.bat"
if (Test-Path $vcvarsPath) {
Write-Host "Setting up MSVC environment with: $vcvarsPath"
# Get environment variables from vcvars
$vcvarsOutput = cmd /c "`"$vcvarsPath`" && set" 2>$null
foreach ($line in $vcvarsOutput) {
if ($line -match "^([^=]+)=(.*)$") {
$name = $matches[1]
$value = $matches[2]
[Environment]::SetEnvironmentVariable($name, $value, "Process")
}
}
# Verify critical environment variables
Write-Host "Verifying MSVC environment variables..."
Write-Host "INCLUDE: $env:INCLUDE"
Write-Host "LIB: $env:LIB"
Write-Host "PATH additions: $($env:PATH -split ';' | Where-Object { $_ -like '*Visual Studio*' -or $_ -like '*VC*' -or $_ -like '*SDK*' })"
Write-Host "✅ MSVC environment configured"
}
}
}
if (-not $vsFound) {
Write-Host "Installing Visual Studio Build Tools..."
# Download VS Build Tools installer
$installerPath = "$env:TEMP\vs_buildtools.exe"
Write-Host "Downloading Visual Studio Build Tools installer..."
Invoke-WebRequest -Uri "https://aka.ms/vs/17/release/vs_buildtools.exe" -OutFile $installerPath
# Install with required components
Write-Host "Installing Visual Studio Build Tools with MSVC support..."
$installArgs = @(
"--quiet",
"--wait",
"--add", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
"--add", "Microsoft.VisualStudio.Component.VC.Tools.x64",
"--add", "Microsoft.VisualStudio.Component.Windows11SDK.22000",
"--add", "Microsoft.VisualStudio.Component.Windows10SDK.19041",
"--add", "Microsoft.VisualStudio.Component.VC.Redist.14.Latest",
"--add", "Microsoft.VisualStudio.Component.VC.CMake.Project"
)
# Add ARM64 support if building for ARM64
if ("${{ matrix.platform.rust_target }}" -eq "aarch64-pc-windows-msvc") {
$installArgs += "--add", "Microsoft.VisualStudio.Component.VC.Tools.ARM64"
$installArgs += "--add", "Microsoft.VisualStudio.Component.VC.Tools.ARM64EC"
}
Start-Process -FilePath $installerPath -ArgumentList $installArgs -Wait
Write-Host "✅ Visual Studio Build Tools installation completed"
# Setup environment for newly installed MSVC
Write-Host "Setting up MSVC environment for newly installed tools..."
$vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
if (Test-Path $vsWhere) {
$vs = & $vsWhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
if ($vs) {
$vcvarsPath = "$vs\VC\Auxiliary\Build\vcvars64.bat"
if (Test-Path $vcvarsPath) {
Write-Host "Setting up MSVC environment with: $vcvarsPath"
# Get environment variables from vcvars
$vcvarsOutput = cmd /c "`"$vcvarsPath`" && set" 2>$null
foreach ($line in $vcvarsOutput) {
if ($line -match "^([^=]+)=(.*)$") {
$name = $matches[1]
$value = $matches[2]
[Environment]::SetEnvironmentVariable($name, $value, "Process")
}
}
# Verify critical environment variables
Write-Host "Verifying MSVC environment variables..."
Write-Host "INCLUDE: $env:INCLUDE"
Write-Host "LIB: $env:LIB"
Write-Host "PATH additions: $($env:PATH -split ';' | Where-Object { $_ -like '*Visual Studio*' -or $_ -like '*VC*' -or $_ -like '*SDK*' })"
Write-Host "✅ MSVC environment configured"
}
}
}
}
# Verify MSVC tools availability
Write-Host "Verifying MSVC tools..."
try {
$clPath = Get-Command cl.exe -ErrorAction Stop
Write-Host "✅ cl.exe found: $($clPath.Source)"
$libPath = Get-Command lib.exe -ErrorAction Stop
Write-Host "✅ lib.exe found: $($libPath.Source)"
$linkPath = Get-Command link.exe -ErrorAction Stop
Write-Host "✅ link.exe found: $($linkPath.Source)"
} catch {
Write-Host "❌ MSVC tools not found in PATH"
Write-Host "Attempting to locate tools manually..."
# Try to find tools manually
$possiblePaths = @(
"${env:ProgramFiles}\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\*\bin\Hostx64\x64",
"${env:ProgramFiles}\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\*\bin\Hostx64\x64",
"${env:ProgramFiles}\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\*\bin\Hostx64\x64",
"${env:ProgramFiles}\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\*\bin\Hostx64\x64"
)
foreach ($pattern in $possiblePaths) {
$toolDirs = Get-ChildItem $pattern -ErrorAction SilentlyContinue
if ($toolDirs) {
$toolDir = $toolDirs | Sort-Object Name -Descending | Select-Object -First 1
Write-Host "Found MSVC tools at: $($toolDir.FullName)"
$env:PATH = "$($toolDir.FullName);$env:PATH"
break
}
}
# Re-verify after manual path addition
try {
$clPath = Get-Command cl.exe -ErrorAction Stop
Write-Host "✅ cl.exe found after manual search: $($clPath.Source)"
$libPath = Get-Command lib.exe -ErrorAction Stop
Write-Host "✅ lib.exe found after manual search: $($libPath.Source)"
} catch {
Write-Error "❌ Could not locate MSVC tools even after manual search"
exit 1
}
}
Write-Host "✅ Visual Studio Build Tools setup completed for Duck CLI stage"
shell: powershell
- name: Install Rust toolchain (Windows)
if: matrix.platform.use_wsl != true && runner.os == 'Windows'
run: |
Write-Host "Installing Rust toolchain"
# Download and install Rust
$rustupPath = Join-Path $env:TEMP "rustup-init.exe"
try {
# Use PowerShell to download and install Rust
Write-Host "Downloading Rust installer..."
Invoke-WebRequest -Uri "https://win.rustup.rs" -OutFile $rustupPath
Write-Host "Installing Rust..."
& $rustupPath -y --default-toolchain stable --default-host x86_64-pc-windows-msvc
# Refresh environment variables
$cargoPath = Join-Path $env:USERPROFILE ".cargo\bin"
$env:PATH = "$cargoPath;$env:PATH"
# Add target architecture
Write-Host "Adding target architecture..."
$rustupExe = Join-Path $cargoPath "rustup.exe"
& $rustupExe target add ${{ matrix.platform.rust_target }}
# Verify installation
Write-Host "Verifying installation..."
$rustcExe = Join-Path $cargoPath "rustc.exe"
$cargoExe = Join-Path $cargoPath "cargo.exe"
& $rustcExe --version
& $cargoExe --version
Write-Host "Rust toolchain installed successfully"
} catch {
Write-Host "Rust installation failed: $_"
throw
}
shell: powershell
- name: Install Rust toolchain (Linux)
if: matrix.platform.name == 'Linux-x86_64' || matrix.platform.name == 'Linux-aarch64'
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.platform.rust_target }}
- name: Install Rust toolchain (macOS)
if: matrix.platform.use_wsl != true && runner.os == 'macOS'
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.platform.rust_target }}
- name: Setup macOS native environment (Duck CLI stage)
if: matrix.platform.use_wsl != true && runner.os == 'macOS'
run: |
echo "=== Duck CLI阶段:设置macOS原生编译环境 ==="
# 确保Xcode工具
if ! xcode-select -p &> /dev/null; then
echo "Installing Xcode command line tools..."
sudo xcode-select --install 2>/dev/null || echo "Xcode installation initiated"
sleep 30
fi
# 加载Rust环境
source ~/.cargo/env 2>/dev/null || true
echo "Duck CLI stage - System: $(uname -m) -> Target: ${{ matrix.platform.rust_target }}"
echo "Rust: $(rustc --version)"
# 安装目标
if ! rustup target list --installed | grep -q "${{ matrix.platform.rust_target }}"; then
echo "Installing target ${{ matrix.platform.rust_target }}..."
rustup target add ${{ matrix.platform.rust_target }}
fi
# 验证目标安装成功
if rustup target list --installed | grep -q "${{ matrix.platform.rust_target }}"; then
echo "✅ Target ${{ matrix.platform.rust_target }} confirmed for Duck CLI"
else
echo "❌ FATAL: Cannot install target for Duck CLI build"
exit 1
fi
# 设置环境变量
echo "MACOSX_DEPLOYMENT_TARGET=10.15" >> $GITHUB_ENV
echo "✅ Duck CLI macOS环境就绪"
shell: bash
- name: Install cross (for cross compilation - WSL)
if: matrix.platform.cross && matrix.platform.use_wsl == true
run: |
Write-Host "Installing cross tool in WSL"
wsl -d Ubuntu -u root -- bash -c 'source /root/.cargo/env && cargo install cross --git https://github.com/cross-rs/cross'
Write-Host "Cross tool installed successfully"
shell: powershell
- name: Install cross (for cross compilation - Windows)
if: matrix.platform.cross && matrix.platform.use_wsl != true && runner.os == 'Windows'
run: |
Write-Host "Installing cross tool"
# Set environment variables
$cargoPath = Join-Path $env:USERPROFILE ".cargo\bin"
$env:PATH = "$cargoPath;$env:PATH"
# Install cross tool
Write-Host "Installing cross tool..."
$cargoExe = Join-Path $cargoPath "cargo.exe"
& $cargoExe install cross --git https://github.com/cross-rs/cross
Write-Host "Cross tool installed successfully"
shell: powershell
- name: Install cross (for cross compilation - Linux)
if: matrix.platform.cross && (matrix.platform.name == 'Linux-x86_64' || matrix.platform.name == 'Linux-aarch64')
run: |
echo "Installing cross tool for Linux"
cargo install cross --git https://github.com/cross-rs/cross
shell: bash
- name: Install cross (for cross compilation - macOS)
if: matrix.platform.cross && matrix.platform.use_wsl != true && runner.os == 'macOS'
run: |
echo "Installing cross tool for macOS"
cargo install cross --git https://github.com/cross-rs/cross
shell: bash
- name: Cache cargo (WSL)
if: matrix.platform.use_wsl == true
uses: actions/cache@v4
with:
path: |
~/cargo-cache-wsl
key: ${{ runner.os }}-wsl-${{ matrix.platform.rust_target }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo (Windows)
if: matrix.platform.use_wsl != true
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-${{ matrix.platform.rust_target }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Build Duck CLI binary (WSL)
if: matrix.platform.use_wsl == true
run: |
Write-Host "Building Duck CLI in WSL Ubuntu"
# Get current workspace path in WSL format
$currentPath = Get-Location
$wslPath = $currentPath.Path -replace 'C:\\', '/mnt/c/' -replace '\\', '/'
if ('${{ matrix.platform.cross }}' -eq 'true') {
Write-Host "Using cross tool to build Duck CLI"
wsl -d Ubuntu -u root -- bash -c "source /root/.cargo/env && cd '$wslPath' && cross build --release --target ${{ matrix.platform.rust_target }} -p nuwax-cli"
} else {
Write-Host "Building Duck CLI locally"
wsl -d Ubuntu -u root -- bash -c "source /root/.cargo/env && cd '$wslPath' && cargo build --release --target ${{ matrix.platform.rust_target }} -p nuwax-cli"
}
Write-Host "Duck CLI build completed"
shell: powershell
- name: Build Duck CLI binary (Windows)
if: matrix.platform.use_wsl != true && runner.os == 'Windows'
run: |
Write-Host "Building Duck CLI binary with MSVC"
# Set environment variables
$cargoPath = Join-Path $env:USERPROFILE ".cargo\bin"
$env:PATH = "$cargoPath;$env:PATH"
# Ensure MSVC tools and include paths are properly configured
Write-Host "Verifying MSVC tools and environment before build..."
try {
$clPath = Get-Command cl.exe -ErrorAction Stop
Write-Host "✅ cl.exe available: $($clPath.Source)"
$libPath = Get-Command lib.exe -ErrorAction Stop
Write-Host "✅ lib.exe available: $($libPath.Source)"
} catch {
Write-Host "❌ MSVC tools not found, attempting to fix PATH..."
# Try to find and add MSVC tools to PATH
$possiblePaths = @(
"${env:ProgramFiles}\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\*\bin\Hostx64\x64",
"${env:ProgramFiles}\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\*\bin\Hostx64\x64",
"${env:ProgramFiles}\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\*\bin\Hostx64\x64",
"${env:ProgramFiles}\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\*\bin\Hostx64\x64"
)
foreach ($pattern in $possiblePaths) {
$toolDirs = Get-ChildItem $pattern -ErrorAction SilentlyContinue
if ($toolDirs) {
$toolDir = $toolDirs | Sort-Object Name -Descending | Select-Object -First 1
Write-Host "Adding MSVC tools to PATH: $($toolDir.FullName)"
$env:PATH = "$($toolDir.FullName);$env:PATH"
break
}
}
}
# Verify and fix INCLUDE and LIB paths if needed
Write-Host "Checking INCLUDE and LIB environment variables..."
if (-not $env:INCLUDE -or $env:INCLUDE -eq "") {
Write-Host "❌ INCLUDE path not set, attempting to fix..."
# Find Visual Studio installation and setup environment
$vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
if (Test-Path $vsWhere) {
$vs = & $vsWhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
if ($vs) {
Write-Host "Re-running vcvars64.bat to fix environment..."
$vcvarsPath = "$vs\VC\Auxiliary\Build\vcvars64.bat"
if (Test-Path $vcvarsPath) {
# Re-run vcvars and apply environment
$vcvarsOutput = cmd /c "`"$vcvarsPath`" && set" 2>$null
foreach ($line in $vcvarsOutput) {
if ($line -match "^([^=]+)=(.*)$") {
$name = $matches[1]
$value = $matches[2]
[Environment]::SetEnvironmentVariable($name, $value, "Process")
}
}
}
}
}
}
Write-Host "Final environment check:"
Write-Host "INCLUDE: $env:INCLUDE"
Write-Host "LIB: $env:LIB"
if (-not $env:INCLUDE) {
Write-Error "❌ INCLUDE environment variable is still not set. This will cause C compilation to fail."
exit 1
}
# Set Rust environment variables for MSVC
Write-Host "Configuring Rust for MSVC..."
$env:CC = "cl.exe"
$env:CXX = "cl.exe"
$env:AR = "lib.exe"
# Additional environment variables for Windows compilation
if ("${{ matrix.platform.rust_target }}" -eq "aarch64-pc-windows-msvc") {
Write-Host "Configuring for ARM64 target"
$env:CARGO_TARGET_AARCH64_PC_WINDOWS_MSVC_LINKER = "rust-lld.exe"
# For ARM64, we need to ensure we use the right vcvars script
$vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
if (Test-Path $vsWhere) {
$vs = & $vsWhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
if ($vs) {
$vcvarsARM64Path = "$vs\VC\Auxiliary\Build\vcvarsx86_arm64.bat"
if (Test-Path $vcvarsARM64Path) {
Write-Host "Setting up ARM64 cross-compilation environment with: $vcvarsARM64Path"
$vcvarsOutput = cmd /c "`"$vcvarsARM64Path`" && set" 2>$null
foreach ($line in $vcvarsOutput) {
if ($line -match "^([^=]+)=(.*)$") {
$name = $matches[1]
$value = $matches[2]
[Environment]::SetEnvironmentVariable($name, $value, "Process")
}
}
Write-Host "ARM64 cross-compilation environment configured"
}
}
}
}
# Choose build method
if ('${{ matrix.platform.cross }}' -eq 'true') {
Write-Host "Using cross tool to build Duck CLI"
$crossExe = Join-Path $cargoPath "cross.exe"
& $crossExe build --release --target ${{ matrix.platform.rust_target }} -p nuwax-cli
} else {
Write-Host "Building Duck CLI locally with target: ${{ matrix.platform.rust_target }}"
$cargoExe = Join-Path $cargoPath "cargo.exe"
& $cargoExe build --release --target ${{ matrix.platform.rust_target }} -p nuwax-cli
}
# Verify the built binary
$binaryPath = "target\${{ matrix.platform.rust_target }}\release\${{ matrix.platform.duck_cli_bin }}"
if (Test-Path $binaryPath) {
Write-Host "✅ Duck CLI binary built successfully: $binaryPath"
$binaryInfo = Get-Item $binaryPath
Write-Host "Binary size: $($binaryInfo.Length) bytes"
} else {
Write-Error "❌ Duck CLI binary not found at expected path: $binaryPath"
exit 1
}
Write-Host "Duck CLI build completed"
shell: powershell
- name: Build Duck CLI binary (Linux)
if: matrix.platform.name == 'Linux-x86_64' || matrix.platform.name == 'Linux-aarch64'
run: |
echo "Building Duck CLI for Linux"
# Set environment variables for Linux builds
export PKG_CONFIG_PATH="/usr/lib/x86_64-linux-gnu/pkgconfig:/usr/share/pkgconfig:/usr/lib/pkgconfig:$PKG_CONFIG_PATH"
export PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=1
export PKG_CONFIG_ALLOW_SYSTEM_LIBS=1
# Verify glib dependencies
echo "Verifying glib dependencies..."
pkg-config --exists glib-2.0 && echo "✅ glib-2.0 available" || echo "❌ glib-2.0 not found"
# Choose build method
if [ "${{ matrix.platform.cross }}" = "true" ]; then
echo "Using cross tool for cross compilation"
echo "Target architecture: ${{ matrix.platform.rust_target }}"
cross build --release --target ${{ matrix.platform.rust_target }} -p nuwax-cli
else
echo "Building natively for ${{ matrix.platform.rust_target }}"
cargo build --release --target ${{ matrix.platform.rust_target }} -p nuwax-cli
fi
echo "Duck CLI build completed successfully"
shell: bash
- name: Build Duck CLI binary (macOS)
if: matrix.platform.use_wsl != true && runner.os == 'macOS'
run: |
echo "Building Duck CLI for macOS"
# Environment variables should already be set in previous step, but let's verify and set them again if needed
if [ "${{ matrix.platform.rust_target }}" = "x86_64-apple-darwin" ]; then
echo "Configuring ARM64 -> x86_64 cross-compilation"
export MACOSX_DEPLOYMENT_TARGET=10.15
export CARGO_TARGET_X86_64_APPLE_DARWIN_LINKER=clang
export CC_x86_64_apple_darwin=clang
export CXX_x86_64_apple_darwin=clang++
export AR_x86_64_apple_darwin=ar
export CFLAGS_x86_64_apple_darwin="-arch x86_64"
export CXXFLAGS_x86_64_apple_darwin="-arch x86_64"
# Verify cross-compilation environment
echo "Cross-compilation environment:"
echo "MACOSX_DEPLOYMENT_TARGET: $MACOSX_DEPLOYMENT_TARGET"
echo "CARGO_TARGET_X86_64_APPLE_DARWIN_LINKER: $CARGO_TARGET_X86_64_APPLE_DARWIN_LINKER"
else
echo "Configuring native ARM64 compilation"
export MACOSX_DEPLOYMENT_TARGET=11.0
echo "MACOSX_DEPLOYMENT_TARGET: $MACOSX_DEPLOYMENT_TARGET"
fi
# Verify target is available
echo "Verifying target availability..."
if rustup target list --installed | grep -q "${{ matrix.platform.rust_target }}"; then
echo "✅ Target ${{ matrix.platform.rust_target }} is available"
else
echo "❌ Target ${{ matrix.platform.rust_target }} is not available"
echo "Installed targets:"
rustup target list --installed
exit 1
fi
# Test cross-compilation setup
echo "Testing cross-compilation setup..."
rustc --print cfg --target ${{ matrix.platform.rust_target }}
# Build Duck CLI
echo "Building Duck CLI for target: ${{ matrix.platform.rust_target }}"
cargo build --release --target ${{ matrix.platform.rust_target }} -p nuwax-cli
echo "Duck CLI build completed successfully"
shell: bash
- name: Package Duck CLI binary (Windows)
if: matrix.platform.name == 'Windows-x86_64' || matrix.platform.name == 'Windows-aarch64'
run: |
# 进入构建目录
Push-Location "target/${{ matrix.platform.rust_target }}/release"
# 使用 PowerShell 内置压缩功能代替 7z
Write-Host "Compressing ${{ matrix.platform.duck_cli_bin }} to ${{ matrix.platform.duck_cli_archive }}"
Compress-Archive -Path ${{ matrix.platform.duck_cli_bin }} -DestinationPath "../../../${{ matrix.platform.duck_cli_archive }}" -Force
# 返回原目录
Pop-Location
# 验证文件创建
if (Test-Path "${{ matrix.platform.duck_cli_archive }}") {
Write-Host "Archive created successfully: ${{ matrix.platform.duck_cli_archive }}"
Get-Item "${{ matrix.platform.duck_cli_archive }}" | Format-List Name, Length
} else {
Write-Error "Failed to create archive: ${{ matrix.platform.duck_cli_archive }}"
exit 1
}
shell: powershell
- name: Package Duck CLI binary (Linux)
if: matrix.platform.name == 'Linux-x86_64' || matrix.platform.name == 'Linux-aarch64'
run: |
cd target/${{ matrix.platform.rust_target }}/release
tar czf ../../../${{ matrix.platform.duck_cli_archive }} ${{ matrix.platform.duck_cli_bin }}
cd -
shell: bash
- name: Package Duck CLI binary (macOS)
if: matrix.platform.name == 'macOS-x86_64' || matrix.platform.name == 'macOS-aarch64'
run: |
cd target/${{ matrix.platform.rust_target }}/release
tar czf ../../../${{ matrix.platform.duck_cli_archive }} ${{ matrix.platform.duck_cli_bin }}
cd -
shell: bash
- name: Upload Duck CLI artifact (for sidecar)
uses: actions/upload-artifact@v4
with:
name: nuwax-cli-${{ matrix.platform.name }}
path: ${{ matrix.platform.duck_cli_archive }}
retention-days: 1
# 使用官方 tauri-action 构建 CLI-UI 桌面应用
build-cli-ui:
name: Build CLI-UI for ${{ matrix.platform.name }}
runs-on: ${{ matrix.platform.os }}
needs: [check-versions, build-nuwax-cli]
if: needs.check-versions.outputs.should_build == 'true'
strategy:
fail-fast: false
matrix:
platform:
- name: Linux-x86_64
os: ubuntu-22.04
rust_target: x86_64-unknown-linux-gnu
duck_cli_artifact: nuwax-cli-Linux-x86_64
- name: Windows-x86_64
os: [self-hosted, Windows, X64]
rust_target: x86_64-pc-windows-msvc
duck_cli_artifact: nuwax-cli-Windows-x86_64
- name: macOS-x86_64
os: macos-13 # 使用 GitHub 托管的 Intel macOS runner
rust_target: x86_64-apple-darwin
duck_cli_artifact: nuwax-cli-macOS-x86_64
- name: macOS-aarch64
os: [self-hosted, macOS, ARM64]
rust_target: aarch64-apple-darwin
duck_cli_artifact: nuwax-cli-macOS-aarch64
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 'lts/*'
cache: 'yarn'
cache-dependency-path: cli-ui/yarn.lock
- name: Install Linux dependencies
if: matrix.platform.name == 'Linux-x86_64' || matrix.platform.name == 'Linux-aarch64'
run: |
sudo apt-get update
sudo apt-get install -y \
libwebkit2gtk-4.1-dev \
libwebkit2gtk-4.0-dev \
libjavascriptcoregtk-4.1-dev \
libjavascriptcoregtk-4.0-dev \
libgtk-3-dev \
libayatana-appindicator3-dev \
librsvg2-dev \
patchelf
- name: Cache Linux dependencies
if: matrix.platform.name == 'Linux-x86_64' || matrix.platform.name == 'Linux-aarch64'
uses: actions/cache@v4
with:
path: /var/cache/apt
key: ${{ runner.os }}-apt-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-apt-
- name: Setup WSL Ubuntu (for Linux builds on Windows)
if: matrix.platform.use_wsl == true
run: |
Write-Host "Setting up WSL Ubuntu environment for Linux GUI builds"
# WSL should already be set up in Duck CLI build stage, here we just need to install Node.js
Write-Host "Checking and installing Node.js..."
$nodeInstalled = wsl -d Ubuntu -u root -- bash -c 'command -v node > /dev/null 2>&1 && echo "installed" || echo "not-installed"'
if ($nodeInstalled -eq "not-installed") {
Write-Host "Installing Node.js..."
wsl -d Ubuntu -u root -- bash -c 'curl -fsSL https://deb.nodesource.com/setup_lts.x -o nodesource_setup.sh'
wsl -d Ubuntu -u root -- bash -c 'bash nodesource_setup.sh'
wsl -d Ubuntu -u root -- bash -c 'apt-get install -y nodejs'
wsl -d Ubuntu -u root -- bash -c 'rm nodesource_setup.sh'
} else {
Write-Host "Node.js already installed"
}
# Install Yarn
Write-Host "Checking and installing Yarn..."
$yarnInstalled = wsl -d Ubuntu -u root -- bash -c 'command -v yarn > /dev/null 2>&1 && echo "installed" || echo "not-installed"'
if ($yarnInstalled -eq "not-installed") {
Write-Host "Installing Yarn..."
wsl -d Ubuntu -u root -- bash -c 'npm install -g yarn'
} else {
Write-Host "Yarn already installed"
}
# Verify installation
Write-Host "Verifying installation..."
wsl -d Ubuntu -u root -- bash -c 'node --version'
wsl -d Ubuntu -u root -- bash -c 'yarn --version'
wsl -d Ubuntu -u root -- bash -c 'source /root/.cargo/env && rustc --version'
shell: powershell
- name: Install Rust toolchain (Windows/macOS)
if: matrix.platform.use_wsl != true
run: |
echo "=== Installing Rust Toolchain ==="
# 使用 dtolnay/rust-toolchain action 已经安装了 Rust,只需要验证
if command -v rustup &> /dev/null; then
echo "Rust toolchain already installed"
else
echo "Installing fresh Rust toolchain..."
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile default
source ~/.cargo/env
fi
# 安装目标
echo "Installing target: ${{ matrix.platform.rust_target }}"
rustup target add ${{ matrix.platform.rust_target }}
# 验证安装
echo "=== Verification ==="
echo "Rust: $(rustc --version)"
echo "Installed targets:"
rustup target list --installed
if rustup target list --installed | grep -q "${{ matrix.platform.rust_target }}"; then
echo "✅ Target ${{ matrix.platform.rust_target }} confirmed!"
else
echo "❌ Target verification failed!"
exit 1
fi
echo "✅ Rust toolchain ready!"
shell: bash
- name: Setup macOS environment (CLI-UI stage)
if: matrix.platform.name == 'macOS-x86_64'
run: |
echo "=== macOS 原生编译环境准备 ==="
# 加载Rust环境
source ~/.cargo/env 2>/dev/null || true
echo "System: $(uname -m) -> Target: x86_64"
echo "Rust: $(rustc --version)"
# 确保目标已安装
if ! rustup target list --installed | grep -q "x86_64-apple-darwin"; then
echo "Installing x86_64-apple-darwin target..."
rustup target add x86_64-apple-darwin
fi
# 验证目标安装
if rustup target list --installed | grep -q "x86_64-apple-darwin"; then
echo "✅ x86_64-apple-darwin target confirmed"
else
echo "❌ Target installation failed!"
exit 1
fi
# 设置环境变量
echo "MACOSX_DEPLOYMENT_TARGET=10.15" >> $GITHUB_ENV
echo "✅ macOS环境准备完成!"
- name: Setup macOS native environment (CLI-UI stage)
if: matrix.platform.name == 'macOS-aarch64'
run: |
echo "Setting up native ARM64 compilation for CLI-UI build"
# Verify Xcode command line tools
if ! xcode-select -p &> /dev/null; then
echo "Installing Xcode command line tools..."
xcode-select --install
sleep 30
fi
# Ensure target architecture is installed
echo "Installing aarch64-apple-darwin target..."
rustup target add aarch64-apple-darwin
# Verify target installation
if rustup target list --installed | grep -q "aarch64-apple-darwin"; then
echo "✅ aarch64-apple-darwin target successfully installed"
else
echo "❌ aarch64-apple-darwin target installation failed"
exit 1
fi
# Set environment variables for native ARM64
echo "MACOSX_DEPLOYMENT_TARGET=11.0" >> $GITHUB_ENV
echo "Native ARM64 environment ready"
echo "Current system architecture: $(uname -m)"
echo "Target architecture: aarch64"
echo "Rust target: aarch64-apple-darwin"
echo "Rust toolchain: $(rustc --version)"
- name: Cache Rust dependencies
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
cli-ui/src-tauri/target
key: ${{ runner.os }}-${{ matrix.platform.rust_target }}-cargo-cli-ui-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-${{ matrix.platform.rust_target }}-cargo-cli-ui-
${{ runner.os }}-${{ matrix.platform.rust_target }}-cargo-
- name: Install frontend dependencies (Linux)
if: matrix.platform.name == 'Linux-x86_64'
run: |
echo "Installing frontend dependencies (Linux environment)"
cd cli-ui
yarn install
echo "Frontend dependencies installed successfully"
shell: bash
- name: Install Visual Studio Build Tools for ARM64
if: matrix.platform.name == 'Windows-aarch64'
run: |
Write-Host "Checking for Visual Studio Build Tools..."
# Check if Visual Studio is already installed
$vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
$vsFound = $false
if (Test-Path $vsWhere) {
$vs = & $vsWhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
if ($vs) {
Write-Host "✅ Visual Studio found: $vs"
$vsFound = $true
}
}
if (-not $vsFound) {
Write-Host "Installing Visual Studio Build Tools..."
# Download VS Build Tools installer
$installerPath = "$env:TEMP\vs_buildtools.exe"
Invoke-WebRequest -Uri "https://aka.ms/vs/17/release/vs_buildtools.exe" -OutFile $installerPath
# Install with ARM64 support
Write-Host "Installing Visual Studio Build Tools with ARM64 support..."
Start-Process -FilePath $installerPath -ArgumentList @(
"--quiet",
"--wait",
"--add", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
"--add", "Microsoft.VisualStudio.Component.VC.Tools.ARM64",
"--add", "Microsoft.VisualStudio.Component.Windows10SDK.19041"
) -Wait
Write-Host "✅ Visual Studio Build Tools installation completed"
}
shell: powershell
- name: Setup Windows ARM64 cross-compilation
if: matrix.platform.name == 'Windows-aarch64'
run: |
Write-Host "Setting up Windows ARM64 cross-compilation"
# Setup Visual Studio Environment for ARM64 cross-compilation
Write-Host "Setting up Visual Studio environment for ARM64..."
# Find Visual Studio installation
$vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
if (Test-Path $vsWhere) {
$vs = & $vsWhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
if ($vs) {
Write-Host "✅ Visual Studio found: $vs"
# Setup environment for x64 host, ARM64 target
$vcvarsPath = "$vs\VC\Auxiliary\Build\vcvarsx86_arm64.bat"
if (-not (Test-Path $vcvarsPath)) {
$vcvarsPath = "$vs\VC\Auxiliary\Build\vcvars64.bat"
}
if (Test-Path $vcvarsPath) {
Write-Host "Setting up MSVC environment with: $vcvarsPath"
# Get environment variables from vcvars
$vcvarsOutput = cmd /c "`"$vcvarsPath`" && set" 2>$null
foreach ($line in $vcvarsOutput) {
if ($line -match "^([^=]+)=(.*)$") {
$name = $matches[1]
$value = $matches[2]
[Environment]::SetEnvironmentVariable($name, $value, "Process")
}
}
Write-Host "✅ MSVC environment configured"
} else {
Write-Warning "vcvars script not found"
}
} else {
Write-Warning "Visual Studio not found"
}
} else {
Write-Warning "vswhere.exe not found"
}
# Add ARM64 target for Rust
Write-Host "Adding ARM64 Rust target..."
rustup target add aarch64-pc-windows-msvc
# Verify target installation
$installedTargets = rustup target list --installed
if ($installedTargets -match "aarch64-pc-windows-msvc") {
Write-Host "✅ aarch64-pc-windows-msvc target installed successfully"
} else {
Write-Error "❌ Failed to install aarch64-pc-windows-msvc target"
exit 1
}
# Set Rust environment variables for MSVC
Write-Host "Configuring Rust environment for MSVC..."
$env:CC = "cl.exe"
$env:CXX = "cl.exe"
$env:AR = "lib.exe"
# Verify compiler availability
Write-Host "Verifying compiler setup..."
try {
$clPath = Get-Command cl.exe -ErrorAction Stop
Write-Host "✅ MSVC compiler found: $($clPath.Source)"
# Test basic compilation
Write-Host "Testing compilation..."
$testResult = cl.exe 2>&1
Write-Host "Compiler test result: $testResult"
} catch {
Write-Host "❌ MSVC compiler not accessible"
Write-Host "PATH: $env:PATH"
# Try to find cl.exe manually
$possiblePaths = @(
"${env:ProgramFiles}\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\*\bin\Hostx64\x64\cl.exe",
"${env:ProgramFiles}\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\*\bin\Hostx64\x64\cl.exe",
"${env:ProgramFiles}\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\*\bin\Hostx64\x64\cl.exe",
"${env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\*\bin\Hostx64\x64\cl.exe"
)
foreach ($pattern in $possiblePaths) {
$found = Get-ChildItem $pattern -ErrorAction SilentlyContinue | Select-Object -First 1
if ($found) {
Write-Host "Found compiler at: $($found.FullName)"
$compilerDir = Split-Path $found.FullName
$env:PATH = "$compilerDir;$env:PATH"
break
}
}
}
Write-Host "Windows ARM64 cross-compilation environment ready"
shell: powershell
- name: Install frontend dependencies (Windows)
if: matrix.platform.use_wsl != true && runner.os == 'Windows'
run: |
Write-Host "Installing frontend dependencies"
cd cli-ui
yarn install
Write-Host "Frontend dependencies installed successfully"
shell: powershell
- name: Install frontend dependencies (macOS)
if: matrix.platform.use_wsl != true && runner.os == 'macOS'
run: |
cd cli-ui
yarn install
- name: Download Duck CLI artifact
uses: actions/download-artifact@v4
with:
name: ${{ matrix.platform.duck_cli_artifact }}
path: duck-cli-artifacts/
- name: Setup Duck CLI sidecar (Windows)
if: matrix.platform.name == 'Windows-x86_64' || matrix.platform.name == 'Windows-aarch64'
run: |
# Create sidecar directory
New-Item -ItemType Directory -Force -Path "cli-ui/src-tauri/binaries"
# Extract nuwax-cli to temporary directory
cd duck-cli-artifacts
# 使用 PowerShell 内置解压缩功能代替 7z
$zipFile = Get-ChildItem -Filter "*.zip" | Select-Object -First 1
Write-Host "Extracting $($zipFile.Name)"
Expand-Archive -Path $zipFile.FullName -DestinationPath "." -Force
# 移动二进制文件
Move-Item nuwax-cli.exe "../cli-ui/src-tauri/binaries/nuwax-cli-${{ matrix.platform.rust_target }}.exe"
# Verify sidecar files
Write-Host "Verifying sidecar files"
Get-ChildItem "../cli-ui/src-tauri/binaries/"
shell: powershell
- name: Setup Duck CLI sidecar (Linux)
if: matrix.platform.name == 'Linux-x86_64'
run: |
echo "Setting up Duck CLI sidecar (Linux environment)"
# Create sidecar directory
mkdir -p cli-ui/src-tauri/binaries
# Extract nuwax-cli to temporary directory
cd duck-cli-artifacts
tar -xzf *.tar.gz
mv nuwax-cli "../cli-ui/src-tauri/binaries/nuwax-cli-${{ matrix.platform.rust_target }}"
# Verify sidecar files
echo "Verifying sidecar files"
ls -la "../cli-ui/src-tauri/binaries/"
shell: bash
- name: Setup Duck CLI sidecar (macOS)
if: matrix.platform.name == 'macOS-x86_64' || matrix.platform.name == 'macOS-aarch64'
run: |
# Create sidecar directory
mkdir -p cli-ui/src-tauri/binaries
# Extract nuwax-cli to temporary directory
cd duck-cli-artifacts
tar -xzf *.tar.gz
mv nuwax-cli "../cli-ui/src-tauri/binaries/nuwax-cli-${{ matrix.platform.rust_target }}"
# Verify sidecar files
echo "Verifying sidecar files"
ls -la "../cli-ui/src-tauri/binaries/"
shell: bash
- name: Build CLI-UI with Tauri Action
uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD || '' }}
# 优化编译性能
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
CARGO_NET_RETRY: 10
# 减少日志输出以提升性能
RUST_BACKTRACE: short
# macOS 编译环境变量
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.platform.name == 'macOS-x86_64' && '10.15' || '11.0' }}
# 移除 debug 日志以减少 I/O 开销
# RUST_LOG: debug
with:
projectPath: cli-ui
# 移除 --verbose 参数减少日志输出
args: --target ${{ matrix.platform.rust_target }}
tagName: ${{ needs.check-versions.outputs.cli_ui_should_release == 'true' && needs.check-versions.outputs.cli_ui_tag_name || '' }}
releaseName: ${{ needs.check-versions.outputs.cli_ui_should_release == 'true' && format('Duck CLI GUI v{0}', needs.check-versions.outputs.cli_ui_version) || '' }}
releaseBody: ${{ needs.check-versions.outputs.cli_ui_should_release == 'true' && format('Duck CLI GUI {0} 发布说明', needs.check-versions.outputs.cli_ui_version) || '' }}
releaseDraft: false
prerelease: false
includeUpdaterJson: true
# 构建摘要
build-summary:
name: Build Summary
runs-on: ubuntu-latest
needs: [check-versions, build-nuwax-cli, build-cli-ui]
if: ${{ always() }}
steps:
- name: Generate build summary
run: |
echo "## 🚀 Unified Build & Release Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 📋 Version Information" >> $GITHUB_STEP_SUMMARY
echo "- **CLI-UI**: ${{ needs.check-versions.outputs.cli_ui_version || 'Not checked' }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 🔄 Build Status" >> $GITHUB_STEP_SUMMARY
echo "- Duck CLI build: ${{ needs.build-nuwax-cli.result == 'success' && '✅ Completed' || needs.build-nuwax-cli.result == 'skipped' && '⏭️ Skipped' || '❌ Failed' }}" >> $GITHUB_STEP_SUMMARY
echo "- CLI-UI build: ${{ needs.build-cli-ui.result == 'success' && '✅ Completed' || needs.build-cli-ui.result == 'skipped' && '⏭️ Skipped' || '❌ Failed' }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 📦 Release Status" >> $GITHUB_STEP_SUMMARY
if [[ "${{ needs.check-versions.outputs.cli_ui_should_release }}" == "true" ]]; then
echo "- 🖥️ **CLI-UI ${{ needs.check-versions.outputs.cli_ui_version }}** has been released!" >> $GITHUB_STEP_SUMMARY
echo " - 🔗 [Download CLI-UI](${{ github.server_url }}/${{ github.repository }}/releases/tag/${{ needs.check-versions.outputs.cli_ui_tag_name }})" >> $GITHUB_STEP_SUMMARY
echo " - 🔄 Automatic updates enabled in the app (via official Tauri updater)" >> $GITHUB_STEP_SUMMARY
echo " - 📝 Signatures automatically included by tauri-action" >> $GITHUB_STEP_SUMMARY
echo " - 🦆 Duck CLI integrated as sidecar binary" >> $GITHUB_STEP_SUMMARY
else
echo "- 🖥️ CLI-UI: No new version to release" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 🎯 Supported Platforms" >> $GITHUB_STEP_SUMMARY
echo "#### 🖥️ Duck CLI GUI (Desktop Application)" >> $GITHUB_STEP_SUMMARY
echo "- 🐧 Linux (x86_64) - AppImage" >> $GITHUB_STEP_SUMMARY
echo "- 🪟 Windows (x86_64, ARM64) - MSI Installer" >> $GITHUB_STEP_SUMMARY
echo "- 🍎 macOS (x86_64, Apple Silicon) - DMG Package" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Note**: Duck CLI is integrated as a sidecar binary and doesn't require separate installation." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 💡 Usage Instructions" >> $GITHUB_STEP_SUMMARY
echo "#### To release new versions:" >> $GITHUB_STEP_SUMMARY
echo "- **Update version**: Modify \`cli-ui/src-tauri/tauri.conf.json\`" >> $GITHUB_STEP_SUMMARY
echo "- **Commit and push**: Changes to main branch trigger automatic release" >> $GITHUB_STEP_SUMMARY
echo "- **Duck CLI**: Automatically built and integrated as sidecar" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "#### 🔄 Automatic Updates:" >> $GITHUB_STEP_SUMMARY
echo "- Built-in Tauri updater with signature verification" >> $GITHUB_STEP_SUMMARY
echo "- Updates checked and applied automatically within the app" >> $GITHUB_STEP_SUMMARY
echo "- Duck CLI updates included with GUI releases" >> $GITHUB_STEP_SUMMARY