Files
qiming/qimingclaw/.github/workflows/release-electron-dev.yml

537 lines
24 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.
# Electron 桌面客户端 — 预发布版本构建
# 通过 prerelease-v* tag 触发,构建全平台安装包并创建 GitHub Draft Release
# 自动同步到阿里云 OSS 并更新 beta/latest.json供开发测试使用。
#
# 触发方式:
# - 推送 tag 匹配 prerelease-v*(例如 prerelease-v0.8.0)→ 构建 → 自动上传 OSS → 更新 beta/latest.json
#
# 支持平台:
# - macOS arm64macos-latest
# - macOS x64macos-latest, cross-compile
# - Windows x64msi
# - Linux x64AppImage + deb
# - Linux arm64AppImage + deb
#
# 使用的 Secrets可与 Tauri 共用 Apple 相关,也可单独配置):
# - GH_PAT可选创建 Release、上传资产未配置时自动回退到 github.token需 Contents: Write
# - macOS 签名/公证(未配置时 Mac 构建为无签名包,用户打开会提示「已损坏」):
# - APPLE_TEAM_ID / APPLE_SIGNING_IDENTITY / APPLE_CERTIFICATE.p12 Base64/ APPLE_CERTIFICATE_PASSWORD
# - 公证APPLE_API_KEY.p8 Base64/ APPLE_API_KEY_ID / APPLE_ISSUER_ID
# - Windows本 workflow 仅构建产物,不在 CI 内签名;签名在本地 WindowsSimplySign手动完成
# - OSS_ACCESS_KEY_ID / OSS_ACCESS_KEY_SECRET上传到阿里云 OSS
#
# 产物目录crates/agent-electron-client/release/${version}/(由 package.json directories.output 决定)
name: Release Electron App (Prerelease)
on:
push:
tags:
- "prerelease-v*"
permissions:
contents: write
jobs:
prepare:
name: Prepare release
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Get version from tag
id: version
run: |
VERSION="${GITHUB_REF_NAME#prerelease-v}"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "Electron prerelease version: $VERSION"
- name: Read release notes
id: notes
run: |
VERSION="${{ steps.version.outputs.version }}"
TAG="${{ github.ref_name }}"
NOTES_FILE="release-notes/${TAG}.md"
if [ -f "$NOTES_FILE" ]; then
echo "Using release notes from $NOTES_FILE"
cp "$NOTES_FILE" release_notes.txt
else
echo "QimingClaw ${VERSION} (Prerelease)。请在 Assets 中下载对应平台安装包。" > release_notes.txt
fi
- name: Create GitHub Release
env:
GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
run: |
TAG="${{ github.ref_name }}"
if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" 2>/dev/null; then
echo "Release $TAG already exists"
else
gh release create "$TAG" \
--title "QimingClaw (Electron) ${{ steps.version.outputs.version }} - Prerelease" \
--notes-file release_notes.txt \
--draft \
--prerelease \
--repo "$GITHUB_REPOSITORY"
echo "Created release $TAG"
fi
build-electron:
name: Build Electron (${{ matrix.platform }} ${{ matrix.arch }})
needs: prepare
strategy:
fail-fast: false
matrix:
include:
- platform: macos-latest
arch: arm64
dist_cmd: dist:mac:arm64
- platform: macos-latest
arch: x64
dist_cmd: dist:mac:x64
- platform: windows-latest
arch: x64
dist_cmd: dist:win
- platform: ubuntu-24.04
arch: x64
dist_cmd: dist:linux:x64
- platform: ubuntu-24.04-arm
arch: arm64
dist_cmd: dist:linux:arm64
runs-on: ${{ matrix.platform }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set version in package.json
shell: bash
working-directory: crates/agent-electron-client
run: |
VERSION="${{ needs.prepare.outputs.version }}"
npm pkg set version="$VERSION"
echo "package.json version: $(npm pkg get version)"
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: lts/*
# 安装 pnpm用于 workspace 管理,版本由根 package.json packageManager 字段指定)
- name: Install pnpm
uses: pnpm/action-setup@v4
# Python 3.12+ 移除了 distutilsnode-gypbetter-sqlite3 等 native 模块)依赖它;安装 setuptools 以提供 distutils
- name: Install setuptools for node-gyp (Python 3.12+)
shell: bash
run: python3 -m pip install setuptools --break-system-packages 2>/dev/null || python3 -m pip install setuptools
# Linux 构建 deb/rpm 包需要 rpm 工具arm64 runner 需要系统 fpm内置 fpm 仅 x86
- name: Install Linux build tools
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y rpm ruby ruby-dev
sudo gem install fpm
echo "USE_SYSTEM_FPM=true" >> "$GITHUB_ENV"
# pnpm install 会建立 workspace 链接qiming-mcp-stdio-proxy 通过 prepare 脚本自动构建
- name: Install workspace dependencies
run: pnpm install --filter @qiming-ai/qimingclaw...
# 为 Electron 内嵌 Node 重编 better-sqlite3避免 Linux arm64 等平台运行时 "cannot open shared object file"
- name: Rebuild native modules for Electron
working-directory: crates/agent-electron-client
run: npm run electron-rebuild
# 缓存内置 Node.js所有平台、Git仅 Windows、uv所有平台和 qimingcode所有平台
- name: Cache bundled Node.js
uses: actions/cache@v4
with:
path: crates/agent-electron-client/resources/node
key: bundled-node-24-${{ matrix.platform }}-${{ matrix.arch }}-${{ hashFiles('crates/agent-electron-client/package.json') }}
- name: Cache bundled Git (Windows only)
if: matrix.platform == 'windows-latest'
uses: actions/cache@v4
with:
path: crates/agent-electron-client/resources/git
key: bundled-git-2.47.1-windows-${{ hashFiles('crates/agent-electron-client/package.json') }}
- name: Cache uv
uses: actions/cache@v4
with:
path: crates/agent-electron-client/resources/uv
key: bundled-uv-v2-${{ matrix.platform }}-${{ matrix.arch }}-${{ hashFiles('crates/agent-electron-client/scripts/prepare/prepare-uv.js') }}
- name: Cache qimingcode
uses: actions/cache@v4
with:
path: crates/agent-electron-client/resources/qimingcode
key: bundled-qimingcode-v1-${{ matrix.platform }}-${{ matrix.arch }}-${{ hashFiles('crates/agent-electron-client/scripts/prepare/prepare-qimingcode.js') }}
- name: Prepare bundled resources (uv, node, git, qimingcode)
working-directory: crates/agent-electron-client
env:
TARGET_ARCH: ${{ matrix.arch }}
run: npm run prepare:all
timeout-minutes: 15
# ---- macOS导入证书并配置公证可选 ----
- name: Import Apple certificate (macOS)
if: runner.os == 'macOS'
env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
run: |
if [ -z "${APPLE_CERTIFICATE:-}" ]; then
echo "APPLE_CERTIFICATE not set, signing will be skipped"
exit 0
fi
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
KEYCHAIN_PASSWORD=actions
echo -n "$APPLE_CERTIFICATE" | base64 --decode -o "$CERTIFICATE_PATH"
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security import "$CERTIFICATE_PATH" -k "$KEYCHAIN_PATH" -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign -T /usr/bin/security
security list-keychain -d user -s "$KEYCHAIN_PATH"
rm -f "$CERTIFICATE_PATH"
echo "CSC_KEYCHAIN=$KEYCHAIN_PATH" >> "$GITHUB_ENV"
- name: Prepare Apple notarization key (macOS)
if: runner.os == 'macOS'
env:
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
run: |
if [ -z "${APPLE_API_KEY:-}" ] || [ -z "${APPLE_API_KEY_ID:-}" ]; then
echo "Apple notarization secrets not set, notarization will be skipped"
exit 0
fi
if [ -z "${APPLE_ISSUER_ID:-}" ]; then
echo "APPLE_ISSUER_ID required for notarization"
exit 0
fi
mkdir -p "$RUNNER_TEMP/apple-api-key"
echo -n "$APPLE_API_KEY" | base64 --decode -o "$RUNNER_TEMP/apple-api-key/AuthKey.p8"
echo "APPLE_API_KEY=$RUNNER_TEMP/apple-api-key/AuthKey.p8" >> "$GITHUB_ENV"
echo "APPLE_API_KEY_ID=$APPLE_API_KEY_ID" >> "$GITHUB_ENV"
echo "APPLE_API_ISSUER=$APPLE_ISSUER_ID" >> "$GITHUB_ENV"
echo "APPLE_ISSUER_ID=$APPLE_ISSUER_ID" >> "$GITHUB_ENV"
# 若用户看到「已损坏」:请确认已配置 APPLE_CERTIFICATE / APPLE_SIGNING_IDENTITY 及公证用 APPLE_API_KEY 等,且构建日志中有签名与公证成功
# Windows 签名已废弃,改为本地手签方案
- name: Clean previous build artifacts
shell: bash
working-directory: crates/agent-electron-client
run: |
rm -rf release node_modules/.cache
echo "Cleaned release and cache directories"
- name: Build Electron app
shell: bash
working-directory: crates/agent-electron-client
env:
TARGET_ARCH: ${{ matrix.arch }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
CSC_NAME: ${{ secrets.APPLE_SIGNING_IDENTITY }}
run: |
echo "Building Electron app for ${{ runner.os }} (${{ matrix.arch }})"
npm run ${{ matrix.dist_cmd }} -- --publish never
- name: Upload artifacts to Release
shell: bash
env:
GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
run: |
TAG="${{ github.ref_name }}"
VERSION="${{ needs.prepare.outputs.version }}"
OUT_DIR="crates/agent-electron-client/release/${VERSION}"
if [ ! -d "$OUT_DIR" ]; then
echo "::error::Output directory not found: $OUT_DIR"
exit 1
fi
for f in "${OUT_DIR}"/*; do
[ -e "$f" ] || continue
[ -f "$f" ] || continue
echo "Uploading $(basename "$f") ..."
gh release upload "$TAG" "$f" --clobber --repo "$GITHUB_REPOSITORY"
done
# ==================== 同步到 MinIO S3构建产物和阿里云 OSSlatest.json ====================
# prerelease-v* tag 推送触发后,构建完成即自动同步到 MinIO S3 并更新 beta/latest.json
sync-to-minio:
name: Sync prerelease to MinIO S3 (beta)
needs: build-electron
runs-on: ubuntu-latest
continue-on-error: true
env:
# MinIO S3 配置(存放构建产物和 yml 文件)
S3_ENDPOINT: "https://s3.qiming.com:9443"
S3_REGION: "us-east-1"
S3_BUCKET: "qimingclaw"
S3_CDN_BASE: "https://s3.qiming.com:9443/qimingclaw"
# 阿里云 OSS 配置(仅存放 latest.json
OSS_ENDPOINT: "https://oss-rg-china-mainland.aliyuncs.com"
OSS_REGION: "rg-china-mainland"
OSS_BUCKET: "oss://qiming-packages"
OSS_CDN_BASE: "https://qiming-packages.oss-rg-china-mainland.aliyuncs.com"
RELEASE_TAG: ${{ github.ref_name }}
steps:
- name: Ensure awscli v2 (for S3)
run: |
if aws --version 2>/dev/null; then
echo "AWS CLI already installed"
else
curl -fSL -o /tmp/awscliv2.zip \
"https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip"
unzip -q /tmp/awscliv2.zip -d /tmp
sudo /tmp/aws/install --bin-dir /usr/local/bin
fi
aws --version
- name: Install ossutil v2 (for latest.json)
run: |
curl -fSL -o /tmp/ossutil.zip \
"https://gosspublic.alicdn.com/ossutil/v2/2.2.0/ossutil-2.2.0-linux-amd64.zip"
unzip -q /tmp/ossutil.zip -d /tmp
sudo mv /tmp/ossutil-2.2.0-linux-amd64/ossutil /usr/local/bin/
ossutil version
- name: Configure AWS credentials for S3
env:
AWS_ACCESS_KEY_ID: ${{ secrets.MINIO_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.MINIO_SECRET_ACCESS_KEY }}
run: |
aws configure set aws_access_key_id "$AWS_ACCESS_KEY_ID"
aws configure set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY"
aws configure set default.region "$S3_REGION"
aws configure set default.s3.addressing_style path
aws configure set endpoint_url "$S3_ENDPOINT"
- name: Download all release assets
env:
GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
run: |
TAG="${RELEASE_TAG}"
mkdir -p /tmp/release-assets
gh release download "$TAG" --repo "$GITHUB_REPOSITORY" --dir /tmp/release-assets
echo "==> Downloaded assets:"
ls -lh /tmp/release-assets/
- name: Generate latest.json and platform yml from assets
env:
GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
run: |
TAG="${RELEASE_TAG}"
VERSION="${TAG#prerelease-v}"
S3_URL_PREFIX="${S3_CDN_BASE}/qimingclaw-electron/beta-build/${TAG}"
ASSETS_DIR="/tmp/release-assets"
# semver MVP guard: only allow numeric x.y.z
if ! echo "$VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "::error::Invalid version '${VERSION}'. MVP only supports numeric x.y.z"
exit 1
fi
# 删除 GitHub 自带的 yml仅保留由 latest.json 派生的 yml
rm -f "${ASSETS_DIR}"/*.yml
# 获取 release notes 与 pub_date
RELEASE_JSON=$(gh release view "$TAG" --repo "$GITHUB_REPOSITORY" --json body,createdAt 2>/dev/null || echo '{}')
NOTES=$(echo "$RELEASE_JSON" | jq -r '.body // "QimingClaw 功能优化和问题修复。建议更新到最新版本以获得更好的体验。"' | head -c 500)
PUB_DATE=$(echo "$RELEASE_JSON" | jq -r '.createdAt // empty')
if [ -z "$PUB_DATE" ]; then
PUB_DATE=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")
fi
add_platform() {
local key="$1" file="$2"
local filepath="${ASSETS_DIR}/${file}"
if [ -f "$filepath" ]; then
local sig size
sig=$(sha512sum "$filepath" | awk '{print $1}' | xxd -r -p | base64 -w0)
if [ -z "$sig" ]; then
echo " Skipped: ${key} -> ${file} (signature generation failed)"
return 0
fi
size=$(stat -c%s "$filepath" 2>/dev/null || stat -f%z "$filepath")
PLATFORMS=$(echo "$PLATFORMS" | jq \
--arg k "$key" \
--arg u "${S3_URL_PREFIX}/${file}" \
--arg s "$sig" \
--argjson sz "$size" \
'. + {($k): {"url": $u, "signature": $s, "size": $sz}}')
echo " Added: ${key} -> ${file} (${size} bytes)"
fi
}
PLATFORMS="{}"
echo "==> Scanning release assets for platforms..."
add_platform "darwin-aarch64" "QimingClaw-${VERSION}-arm64.dmg"
add_platform "darwin-aarch64-zip" "QimingClaw-${VERSION}-arm64-mac.zip"
add_platform "darwin-x86_64" "QimingClaw-${VERSION}.dmg"
add_platform "darwin-x86_64-zip" "QimingClaw-${VERSION}-mac.zip"
add_platform "windows-x86_64" "QimingClaw-Setup-${VERSION}-unsigned.exe"
add_platform "windows-x86_64-nsis" "QimingClaw-Setup-${VERSION}-unsigned.exe"
add_platform "windows-x86_64-msi" "QimingClaw-${VERSION}-unsigned.msi"
add_platform "linux-x86_64" "QimingClaw-${VERSION}.AppImage"
add_platform "linux-x86_64-appimage" "QimingClaw-${VERSION}.AppImage"
add_platform "linux-x86_64-deb" "QimingClaw-${VERSION}-amd64.deb"
add_platform "linux-x86_64-rpm" "QimingClaw-${VERSION}-x86_64.rpm"
add_platform "linux-aarch64" "QimingClaw-${VERSION}-arm64.AppImage"
add_platform "linux-aarch64-appimage" "QimingClaw-${VERSION}-arm64.AppImage"
add_platform "linux-aarch64-deb" "QimingClaw-${VERSION}-arm64.deb"
add_platform "linux-aarch64-rpm" "QimingClaw-${VERSION}-aarch64.rpm"
if [ "$(echo "$PLATFORMS" | jq 'length')" = "0" ]; then
echo "::warning::No exact filename matches, falling back to fuzzy scan"
for file in "${ASSETS_DIR}"/*; do
filename=$(basename "$file")
case "$filename" in
*.dmg|*.zip|*.exe|*.msi|*.AppImage|*.deb|*.rpm)
key=""
case "$filename" in
*arm64*mac*|*arm64*.dmg) key="darwin-aarch64" ;;
*x64*mac*|*x64*.dmg) key="darwin-x86_64" ;;
*Setup*.exe|*setup*.exe) key="windows-x86_64" ;;
*.msi) key="windows-x86_64-msi" ;;
*arm64*.AppImage) key="linux-aarch64" ;;
*amd64*.AppImage|*x64*.AppImage|*.AppImage) key="linux-x86_64" ;;
*arm64*.deb) key="linux-aarch64-deb" ;;
*amd64*.deb|*x64*.deb) key="linux-x86_64-deb" ;;
*aarch64*.rpm) key="linux-aarch64-rpm" ;;
*x86_64*.rpm|*x64*.rpm) key="linux-x86_64-rpm" ;;
esac
[ -n "$key" ] && add_platform "$key" "$filename"
;;
esac
done
fi
gen_yml() {
local channel="$1"
local keys="$2"
local first_key first_file
first_key=$(echo "$PLATFORMS" | jq -r --argjson keys "$keys" 'limit(1; $keys[] as $k | select(.[$k] != null) | $k)')
[ -z "$first_key" ] || [ "$first_key" = "null" ] && return 0
first_file=$(echo "$PLATFORMS" | jq -r --arg k "$first_key" '.[$k].url' | sed 's|.*/||')
{
echo "version: $VERSION"
echo "path: $first_file"
echo "sha512: $(echo "$PLATFORMS" | jq -r --arg k "$first_key" '.[$k].signature')"
echo "releaseDate: $PUB_DATE"
echo "files:"
echo "$PLATFORMS" | jq -r --argjson keys "$keys" '
[ $keys[] as $k | select(.[$k] != null) | .[$k] |
" - url: " + (.url | split("/") | last) + "\n sha512: " + .signature + "\n size: " + (.size | tostring)
] | join("\n")
'
} > "${ASSETS_DIR}/${channel}.yml"
echo " Generated ${channel}.yml (primary: $first_file)"
}
DARWIN_KEYS='["darwin-aarch64-zip","darwin-x86_64-zip","darwin-aarch64","darwin-x86_64"]'
LINUX_KEYS='["linux-x86_64-appimage","linux-aarch64-appimage","linux-x86_64","linux-aarch64","linux-x86_64-deb","linux-aarch64-deb","linux-x86_64-rpm","linux-aarch64-rpm"]'
LINUX_ARM64_KEYS='["linux-aarch64-appimage","linux-aarch64","linux-aarch64-deb","linux-aarch64-rpm"]'
LINUX_X64_KEYS='["linux-x86_64-appimage","linux-x86_64","linux-x86_64-deb","linux-x86_64-rpm"]'
WIN_KEYS='["windows-x86_64","windows-x86_64-nsis","windows-x86_64-msi"]'
gen_yml "latest-mac" "$DARWIN_KEYS"
gen_yml "latest-linux" "$LINUX_KEYS"
gen_yml "latest-linux-arm64" "$LINUX_ARM64_KEYS"
gen_yml "latest-linux-x64" "$LINUX_X64_KEYS"
gen_yml "latest" "$WIN_KEYS"
echo "==> Platform yml written to ${ASSETS_DIR}"
# 构建 yml 文件的完整 S3 URL供客户端 electron-updater 直接使用)
YML_URLS=$(jq -n \
--arg darwin "${S3_URL_PREFIX}/latest-mac.yml" \
--arg linux "${S3_URL_PREFIX}/latest-linux.yml" \
--arg win "${S3_URL_PREFIX}/latest.yml" \
'{darwin: $darwin, linux: $linux, win: $win}')
LATEST_JSON=$(jq -n \
--arg version "$VERSION" \
--arg notes "$NOTES" \
--arg pub_date "$PUB_DATE" \
--argjson platforms "$PLATFORMS" \
--argjson yml "$YML_URLS" \
'{version: $version, notes: $notes, pub_date: $pub_date, platforms: $platforms, yml: $yml}')
echo "$LATEST_JSON" > /tmp/latest.json
echo "==> Generated latest.json"
echo "$LATEST_JSON" | jq .
- name: Upload all assets to MinIO S3
env:
AWS_ACCESS_KEY_ID: ${{ secrets.MINIO_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.MINIO_SECRET_ACCESS_KEY }}
run: |
TAG="${RELEASE_TAG}"
S3_PREFIX="qimingclaw-electron/beta-build/${TAG}"
for file in /tmp/release-assets/*; do
filename=$(basename "$file")
echo "Uploading to S3: ${filename}"
aws s3 cp "$file" "s3://${S3_BUCKET}/${S3_PREFIX}/${filename}" \
--endpoint-url "$S3_ENDPOINT"
done
# 同步 latest.json 到 S3版本化路径 + beta 滚动指针)
echo "Uploading latest.json to S3..."
aws s3 cp /tmp/latest.json "s3://${S3_BUCKET}/${S3_PREFIX}/latest.json" \
--endpoint-url "$S3_ENDPOINT"
aws s3 cp /tmp/latest.json "s3://${S3_BUCKET}/qimingclaw-electron/beta/latest.json" \
--endpoint-url "$S3_ENDPOINT"
- name: Verify S3 upload
run: |
TAG="${RELEASE_TAG}"
VERIFY_URL="${S3_CDN_BASE}/qimingclaw-electron/beta-build/${TAG}/latest-mac.yml"
HTTP_STATUS=$(curl -sS -o /dev/null -w "%{http_code}" "$VERIFY_URL")
if [ "$HTTP_STATUS" = "200" ]; then
echo "==> S3 upload verified: latest-mac.yml (HTTP ${HTTP_STATUS})"
else
echo "::error::S3 upload verification failed: latest-mac.yml (HTTP ${HTTP_STATUS})"
exit 1
fi
- name: Upload latest.json to Alibaba OSS (beta channel)
env:
OSS_ACCESS_KEY_ID: ${{ secrets.OSS_ACCESS_KEY_ID }}
OSS_ACCESS_KEY_SECRET: ${{ secrets.OSS_ACCESS_KEY_SECRET }}
run: |
TAG="${RELEASE_TAG}"
echo "==> Publishing latest.json to beta channel on OSS"
# 写入版本化路径
ossutil cp --force /tmp/latest.json "${OSS_BUCKET}/qimingclaw-electron/beta-build/${TAG}/latest.json" \
--endpoint "$OSS_ENDPOINT" \
--region "$OSS_REGION" \
--access-key-id "$OSS_ACCESS_KEY_ID" \
--access-key-secret "$OSS_ACCESS_KEY_SECRET"
# 写入 beta/latest.json供 beta 通道用户检查更新)
ossutil cp --force /tmp/latest.json "${OSS_BUCKET}/qimingclaw-electron/beta/latest.json" \
--endpoint "$OSS_ENDPOINT" \
--region "$OSS_REGION" \
--access-key-id "$OSS_ACCESS_KEY_ID" \
--access-key-secret "$OSS_ACCESS_KEY_SECRET"
echo "==> Uploaded latest.json to OSS beta/latest.json (stable pointer untouched)"
- name: Verify OSS upload
run: |
VERIFY_URL="${OSS_CDN_BASE}/qimingclaw-electron/beta/latest.json"
HTTP_STATUS=$(curl -sS -o /tmp/oss-latest.json -w "%{http_code}" "$VERIFY_URL")
if [ "$HTTP_STATUS" = "200" ]; then
echo "==> beta/latest.json: OK (HTTP ${HTTP_STATUS})"
cat /tmp/oss-latest.json | jq .
else
echo "::error::beta/latest.json not found on OSS (HTTP ${HTTP_STATUS})"
exit 1
fi