mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-07-06 05:55:28 +08:00
ci(v2-preview): add daily preview build
Signed-off-by: kangfenmao <kangfenmao@qq.com>
This commit is contained in:
384
.github/workflows/v2-daily-preview-build.yml
vendored
Normal file
384
.github/workflows/v2-daily-preview-build.yml
vendored
Normal file
@@ -0,0 +1,384 @@
|
||||
name: v2 Daily Preview Build
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "0 11 * * *" # 19:00 BJ Time
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
actions: write
|
||||
|
||||
jobs:
|
||||
check-repository:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
should_run: ${{ github.repository == 'CherryHQ/cherry-studio' }}
|
||||
steps:
|
||||
- name: Check if running in main repository
|
||||
run: |
|
||||
echo "Running in repository: ${{ github.repository }}"
|
||||
echo "Should run: ${{ github.repository == 'CherryHQ/cherry-studio' }}"
|
||||
|
||||
cleanup-artifacts:
|
||||
needs: check-repository
|
||||
if: needs.check-repository.outputs.should_run == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Delete old preview artifacts
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
REPO: ${{ github.repository }}
|
||||
run: |
|
||||
cutoff_date=$(date -d "14 days ago" +%Y-%m-%d)
|
||||
|
||||
gh api repos/$REPO/actions/artifacts --paginate | \
|
||||
jq -r '.artifacts[] | select(.name | startswith("cherry-studio-next-v2-preview-")) | select(.created_at < "'$cutoff_date'") | .id' | \
|
||||
while read artifact_id; do
|
||||
echo "Deleting artifact $artifact_id"
|
||||
gh api repos/$REPO/actions/artifacts/$artifact_id -X DELETE
|
||||
done
|
||||
|
||||
metadata:
|
||||
needs: check-repository
|
||||
if: needs.check-repository.outputs.should_run == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
date: ${{ steps.meta.outputs.date }}
|
||||
sha: ${{ steps.meta.outputs.sha }}
|
||||
short_sha: ${{ steps.meta.outputs.short_sha }}
|
||||
steps:
|
||||
- name: Check out v2 branch
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: v2
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Resolve build metadata
|
||||
id: meta
|
||||
shell: bash
|
||||
run: |
|
||||
SHA=$(git rev-parse HEAD)
|
||||
echo "sha=$SHA" >> $GITHUB_OUTPUT
|
||||
echo "short_sha=${SHA:0:7}" >> $GITHUB_OUTPUT
|
||||
echo "date=$(TZ=Asia/Shanghai date +'%Y%m%d')" >> $GITHUB_OUTPUT
|
||||
echo "Building v2 at $SHA"
|
||||
|
||||
preview-build:
|
||||
needs:
|
||||
- check-repository
|
||||
- metadata
|
||||
if: needs.check-repository.outputs.should_run == 'true'
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- name: Check out v2 branch
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ needs.metadata.outputs.sha }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version-file: ".node-version"
|
||||
|
||||
- name: macos-latest dependencies fix
|
||||
if: matrix.os == 'macos-latest'
|
||||
run: |
|
||||
brew install python-setuptools
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v5
|
||||
|
||||
- name: Get pnpm store directory
|
||||
id: pnpm-cache
|
||||
shell: bash
|
||||
run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache pnpm dependencies
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-
|
||||
|
||||
- name: Install Dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Patch preview app identity
|
||||
shell: bash
|
||||
run: |
|
||||
node <<'NODE'
|
||||
const fs = require('fs')
|
||||
const replacements = [
|
||||
{
|
||||
path: 'electron-builder.yml',
|
||||
replace: (content) =>
|
||||
content
|
||||
.replace(/^appId: .+$/m, 'appId: com.cherryai.cherrystudio')
|
||||
.replace(/^productName: .+$/m, 'productName: Cherry Studio Next')
|
||||
},
|
||||
{
|
||||
path: 'scripts/notarize.js',
|
||||
replace: (content) => content.replaceAll('com.kangfenmao.CherryStudio', 'com.cherryai.cherrystudio')
|
||||
},
|
||||
{
|
||||
path: 'src/main/index.ts',
|
||||
replace: (content) => content.replaceAll('com.kangfenmao.CherryStudio', 'com.cherryai.cherrystudio')
|
||||
},
|
||||
{
|
||||
path: 'src/main/services/selection/SelectionService.ts',
|
||||
replace: (content) => content.replaceAll('com.kangfenmao.CherryStudio', 'com.cherryai.cherrystudio')
|
||||
}
|
||||
]
|
||||
|
||||
for (const item of replacements) {
|
||||
const original = fs.readFileSync(item.path, 'utf8')
|
||||
const updated = item.replace(original)
|
||||
if (updated === original) {
|
||||
throw new Error(`Preview identity replacement made no changes in ${item.path}`)
|
||||
}
|
||||
fs.writeFileSync(item.path, updated)
|
||||
console.log(`Patched ${item.path}`)
|
||||
}
|
||||
|
||||
const builderConfig = fs.readFileSync('electron-builder.yml', 'utf8')
|
||||
console.log(builderConfig.split('\n').slice(0, 2).join('\n'))
|
||||
NODE
|
||||
|
||||
- name: Build Linux
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
sudo apt-get install -y rpm libevdev-dev libxtst-dev libx11-dev libxfixes-dev libwayland-dev
|
||||
pnpm build:linux
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NODE_OPTIONS: --max-old-space-size=8192
|
||||
MAIN_VITE_CHERRYAI_CLIENT_SECRET: ${{ secrets.MAIN_VITE_CHERRYAI_CLIENT_SECRET }}
|
||||
MAIN_VITE_MINERU_API_KEY: ${{ secrets.MAIN_VITE_MINERU_API_KEY }}
|
||||
RENDERER_VITE_AIHUBMIX_SECRET: ${{ secrets.RENDERER_VITE_AIHUBMIX_SECRET }}
|
||||
RENDERER_VITE_PPIO_APP_SECRET: ${{ secrets.RENDERER_VITE_PPIO_APP_SECRET }}
|
||||
|
||||
- name: Build Mac
|
||||
if: matrix.os == 'macos-latest'
|
||||
run: |
|
||||
pnpm build:mac
|
||||
env:
|
||||
CSC_LINK: ${{ secrets.CSC_LINK }}
|
||||
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NODE_OPTIONS: --max-old-space-size=8192
|
||||
MAIN_VITE_CHERRYAI_CLIENT_SECRET: ${{ secrets.MAIN_VITE_CHERRYAI_CLIENT_SECRET }}
|
||||
MAIN_VITE_MINERU_API_KEY: ${{ secrets.MAIN_VITE_MINERU_API_KEY }}
|
||||
RENDERER_VITE_AIHUBMIX_SECRET: ${{ secrets.RENDERER_VITE_AIHUBMIX_SECRET }}
|
||||
RENDERER_VITE_PPIO_APP_SECRET: ${{ secrets.RENDERER_VITE_PPIO_APP_SECRET }}
|
||||
|
||||
- name: Build Windows
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: |
|
||||
pnpm build:win
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NODE_OPTIONS: --max-old-space-size=8192
|
||||
MAIN_VITE_CHERRYAI_CLIENT_SECRET: ${{ secrets.MAIN_VITE_CHERRYAI_CLIENT_SECRET }}
|
||||
MAIN_VITE_MINERU_API_KEY: ${{ secrets.MAIN_VITE_MINERU_API_KEY }}
|
||||
RENDERER_VITE_AIHUBMIX_SECRET: ${{ secrets.RENDERER_VITE_AIHUBMIX_SECRET }}
|
||||
RENDERER_VITE_PPIO_APP_SECRET: ${{ secrets.RENDERER_VITE_PPIO_APP_SECRET }}
|
||||
|
||||
- name: Rename artifacts with preview format
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p renamed-artifacts
|
||||
DATE="${{ needs.metadata.outputs.date }}"
|
||||
SHORT_SHA="${{ needs.metadata.outputs.short_sha }}"
|
||||
PREFIX="cherry-studio-next-v2-preview-${DATE}-${SHORT_SHA}"
|
||||
|
||||
copy_first() {
|
||||
local pattern="$1"
|
||||
local target="$2"
|
||||
local source
|
||||
source=$(find dist -name "$pattern" -type f -print -quit)
|
||||
if [ -n "$source" ]; then
|
||||
cp "$source" "renamed-artifacts/$target"
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "${{ matrix.os }}" = "windows-latest" ]; then
|
||||
copy_first "*-x64-setup.exe" "${PREFIX}-x64-setup.exe"
|
||||
copy_first "*-arm64-setup.exe" "${PREFIX}-arm64-setup.exe"
|
||||
copy_first "*-x64-portable.exe" "${PREFIX}-x64-portable.exe"
|
||||
copy_first "*-arm64-portable.exe" "${PREFIX}-arm64-portable.exe"
|
||||
fi
|
||||
|
||||
if [ "${{ matrix.os }}" = "macos-latest" ]; then
|
||||
copy_first "*-arm64.dmg" "${PREFIX}-arm64.dmg"
|
||||
copy_first "*-x64.dmg" "${PREFIX}-x64.dmg"
|
||||
copy_first "*-arm64.zip" "${PREFIX}-arm64.zip"
|
||||
copy_first "*-x64.zip" "${PREFIX}-x64.zip"
|
||||
fi
|
||||
|
||||
if [ "${{ matrix.os }}" = "ubuntu-latest" ]; then
|
||||
copy_first "*-x86_64.AppImage" "${PREFIX}-x86_64.AppImage"
|
||||
copy_first "*-arm64.AppImage" "${PREFIX}-arm64.AppImage"
|
||||
copy_first "*-amd64.deb" "${PREFIX}-amd64.deb"
|
||||
copy_first "*-arm64.deb" "${PREFIX}-arm64.deb"
|
||||
copy_first "*-x86_64.rpm" "${PREFIX}-x86_64.rpm"
|
||||
copy_first "*-arm64.rpm" "${PREFIX}-arm64.rpm"
|
||||
fi
|
||||
|
||||
cp dist/latest*.yml renamed-artifacts/ 2>/dev/null || true
|
||||
cp dist/*.blockmap renamed-artifacts/ 2>/dev/null || true
|
||||
|
||||
- name: Generate SHA256 checksums (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
shell: pwsh
|
||||
run: |
|
||||
cd renamed-artifacts
|
||||
echo "# SHA256 checksums for Windows - $(Get-Date -Format 'yyyy-MM-dd')" > SHA256SUMS.txt
|
||||
Get-ChildItem -File | Where-Object { $_.Name -ne 'SHA256SUMS.txt' } | ForEach-Object {
|
||||
$file = $_.Name
|
||||
$hash = (Get-FileHash -Algorithm SHA256 $file).Hash.ToLower()
|
||||
Add-Content -Path SHA256SUMS.txt -Value "$hash $file"
|
||||
}
|
||||
cat SHA256SUMS.txt
|
||||
|
||||
- name: Generate SHA256 checksums (macOS/Linux)
|
||||
if: runner.os != 'Windows'
|
||||
shell: bash
|
||||
run: |
|
||||
cd renamed-artifacts
|
||||
echo "# SHA256 checksums for ${{ runner.os }} - $(date +'%Y-%m-%d')" > SHA256SUMS.txt
|
||||
if command -v shasum &>/dev/null; then
|
||||
shasum -a 256 * 2>/dev/null | grep -v SHA256SUMS.txt >> SHA256SUMS.txt || echo "No files to hash" >> SHA256SUMS.txt
|
||||
else
|
||||
sha256sum * 2>/dev/null | grep -v SHA256SUMS.txt >> SHA256SUMS.txt || echo "No files to hash" >> SHA256SUMS.txt
|
||||
fi
|
||||
cat SHA256SUMS.txt
|
||||
|
||||
- name: List files to be uploaded
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Files to upload:"
|
||||
if [ -x "$(command -v tree)" ]; then
|
||||
tree renamed-artifacts
|
||||
elif [ "$RUNNER_OS" = "Windows" ]; then
|
||||
dir renamed-artifacts
|
||||
else
|
||||
ls -la renamed-artifacts
|
||||
fi
|
||||
echo "Total: $(find renamed-artifacts -type f | wc -l) files"
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: cherry-studio-next-v2-preview-${{ needs.metadata.outputs.date }}-${{ needs.metadata.outputs.short_sha }}-${{ matrix.os }}
|
||||
path: renamed-artifacts/*
|
||||
retention-days: 7
|
||||
compression-level: 8
|
||||
|
||||
build-summary:
|
||||
needs:
|
||||
- check-repository
|
||||
- metadata
|
||||
- preview-build
|
||||
if: always() && needs.check-repository.outputs.should_run == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out workflow scripts
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ needs.metadata.outputs.sha }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version-file: ".node-version"
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v5
|
||||
|
||||
- name: Install notification dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
path: all-artifacts
|
||||
merge-multiple: false
|
||||
continue-on-error: true
|
||||
|
||||
- name: Create summary report
|
||||
shell: bash
|
||||
env:
|
||||
BUILD_RESULT: ${{ needs.preview-build.result }}
|
||||
BUILD_DATE: ${{ needs.metadata.outputs.date }}
|
||||
BUILD_SHA: ${{ needs.metadata.outputs.sha }}
|
||||
SHORT_SHA: ${{ needs.metadata.outputs.short_sha }}
|
||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
run: |
|
||||
echo "## Cherry Studio Next v2 Preview Build" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- Branch: \`v2\`" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- Commit: \`${SHORT_SHA}\`" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- Date: \`${BUILD_DATE}\`" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- Status: \`${BUILD_RESULT}\`" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- Download: [Actions artifacts](${RUN_URL})" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
for platform in windows-latest macos-latest ubuntu-latest; do
|
||||
artifact_dir="all-artifacts/cherry-studio-next-v2-preview-${BUILD_DATE}-${SHORT_SHA}-${platform}"
|
||||
echo "### ${platform}" >> $GITHUB_STEP_SUMMARY
|
||||
if [ -d "$artifact_dir" ] && [ -f "$artifact_dir/SHA256SUMS.txt" ]; then
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
cat "$artifact_dir/SHA256SUMS.txt" >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
else
|
||||
echo "Build did not produce artifacts for this platform." >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
done
|
||||
|
||||
- name: Send Feishu notification
|
||||
if: always()
|
||||
shell: bash
|
||||
env:
|
||||
FEISHU_WEBHOOK_URL: ${{ secrets.FEISHU_WEBHOOK_URL }}
|
||||
FEISHU_WEBHOOK_SECRET: ${{ secrets.FEISHU_WEBHOOK_SECRET }}
|
||||
BUILD_RESULT: ${{ needs.preview-build.result }}
|
||||
BUILD_DATE: ${{ needs.metadata.outputs.date }}
|
||||
BUILD_SHA: ${{ needs.metadata.outputs.sha }}
|
||||
SHORT_SHA: ${{ needs.metadata.outputs.short_sha }}
|
||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
run: |
|
||||
case "$BUILD_RESULT" in
|
||||
success)
|
||||
STATUS_TEXT="succeeded"
|
||||
COLOR="green"
|
||||
;;
|
||||
cancelled)
|
||||
STATUS_TEXT="cancelled"
|
||||
COLOR="orange"
|
||||
;;
|
||||
*)
|
||||
STATUS_TEXT="failed"
|
||||
COLOR="red"
|
||||
;;
|
||||
esac
|
||||
|
||||
DESCRIPTION=$(printf "**Branch:** v2\n\n**Commit:** %.7s\n\n**Date:** %s\n\n**Status:** %s\n\n**Download:** [Actions Artifacts](%s)" "$BUILD_SHA" "$BUILD_DATE" "$STATUS_TEXT" "$RUN_URL")
|
||||
|
||||
pnpm tsx scripts/feishu-notify.ts send \
|
||||
-t "Cherry Studio Next v2 preview build ${STATUS_TEXT}" \
|
||||
-d "$DESCRIPTION" \
|
||||
-c "$COLOR"
|
||||
Reference in New Issue
Block a user