fix(update): electron update function (#32)
This commit is contained in:
153
.github/workflows/release.yml
vendored
153
.github/workflows/release.yml
vendored
@@ -121,6 +121,9 @@ jobs:
|
|||||||
release/latest*.yml
|
release/latest*.yml
|
||||||
retention-days: 7
|
retention-days: 7
|
||||||
|
|
||||||
|
# ──────────────────────────────────────────────────────────────
|
||||||
|
# Job: Publish to GitHub Releases
|
||||||
|
# ──────────────────────────────────────────────────────────────
|
||||||
publish:
|
publish:
|
||||||
needs: release
|
needs: release
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -195,3 +198,153 @@ jobs:
|
|||||||
💬 Found an issue? Please submit an [Issue](https://github.com/${{ github.repository }}/issues)
|
💬 Found an issue? Please submit an [Issue](https://github.com/${{ github.repository }}/issues)
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
# ──────────────────────────────────────────────────────────────
|
||||||
|
# Job: Upload to Alibaba Cloud OSS
|
||||||
|
# Uploads all release artifacts to OSS for:
|
||||||
|
# - Official website downloads (via release-info.json)
|
||||||
|
# - electron-updater auto-update (via latest-*.yml)
|
||||||
|
#
|
||||||
|
# Directory structure on OSS:
|
||||||
|
# latest/ → always overwritten with the newest version
|
||||||
|
# releases/vX.Y.Z/ → permanent archive, never deleted
|
||||||
|
# ──────────────────────────────────────────────────────────────
|
||||||
|
upload-oss:
|
||||||
|
needs: release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Download all artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: release-artifacts
|
||||||
|
|
||||||
|
- name: Extract version
|
||||||
|
id: version
|
||||||
|
run: |
|
||||||
|
if [[ "${{ github.ref }}" == refs/tags/v* ]]; then
|
||||||
|
VERSION="${GITHUB_REF#refs/tags/v}"
|
||||||
|
else
|
||||||
|
VERSION="${{ github.event.inputs.version }}"
|
||||||
|
fi
|
||||||
|
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
||||||
|
echo "tag=v${VERSION}" >> $GITHUB_OUTPUT
|
||||||
|
echo "Detected version: ${VERSION}"
|
||||||
|
|
||||||
|
- name: Prepare upload directories
|
||||||
|
run: |
|
||||||
|
VERSION="${{ steps.version.outputs.version }}"
|
||||||
|
TAG="${{ steps.version.outputs.tag }}"
|
||||||
|
|
||||||
|
mkdir -p staging/latest
|
||||||
|
mkdir -p staging/releases/${TAG}
|
||||||
|
|
||||||
|
# Flatten all platform artifacts into staging directories
|
||||||
|
find release-artifacts/ -type f | while read file; do
|
||||||
|
filename=$(basename "$file")
|
||||||
|
cp "$file" "staging/latest/${filename}"
|
||||||
|
cp "$file" "staging/releases/${TAG}/${filename}"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "=== staging/latest/ ==="
|
||||||
|
ls -lh staging/latest/
|
||||||
|
echo ""
|
||||||
|
echo "=== staging/releases/${TAG}/ ==="
|
||||||
|
ls -lh staging/releases/${TAG}/
|
||||||
|
|
||||||
|
- name: Generate release-info.json
|
||||||
|
run: |
|
||||||
|
VERSION="${{ steps.version.outputs.version }}"
|
||||||
|
BASE_URL="https://valuecell-clawx.oss-cn-hangzhou.aliyuncs.com/latest"
|
||||||
|
|
||||||
|
jq -n \
|
||||||
|
--arg version "$VERSION" \
|
||||||
|
--arg date "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
||||||
|
--arg base "$BASE_URL" \
|
||||||
|
--arg changelog "https://github.com/${{ github.repository }}/releases/tag/v${VERSION}" \
|
||||||
|
'{
|
||||||
|
version: $version,
|
||||||
|
releaseDate: $date,
|
||||||
|
downloads: {
|
||||||
|
mac: {
|
||||||
|
x64: ($base + "/ClawX-" + $version + "-mac-x64.dmg"),
|
||||||
|
arm64: ($base + "/ClawX-" + $version + "-mac-arm64.dmg")
|
||||||
|
},
|
||||||
|
win: {
|
||||||
|
x64: ($base + "/ClawX-" + $version + "-win-x64.exe"),
|
||||||
|
arm64: ($base + "/ClawX-" + $version + "-win-arm64.exe")
|
||||||
|
},
|
||||||
|
linux: {
|
||||||
|
deb_amd64: ($base + "/ClawX-" + $version + "-linux-amd64.deb"),
|
||||||
|
deb_arm64: ($base + "/ClawX-" + $version + "-linux-arm64.deb"),
|
||||||
|
appimage_x64: ($base + "/ClawX-" + $version + "-linux-x86_64.AppImage"),
|
||||||
|
appimage_arm64: ($base + "/ClawX-" + $version + "-linux-arm64.AppImage"),
|
||||||
|
rpm_x64: ($base + "/ClawX-" + $version + "-linux-x86_64.rpm")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
changelog: $changelog
|
||||||
|
}' > staging/latest/release-info.json
|
||||||
|
|
||||||
|
echo "=== release-info.json ==="
|
||||||
|
cat staging/latest/release-info.json
|
||||||
|
|
||||||
|
- name: Install and configure ossutil
|
||||||
|
env:
|
||||||
|
OSS_ACCESS_KEY_ID: ${{ secrets.OSS_ACCESS_KEY_ID }}
|
||||||
|
OSS_ACCESS_KEY_SECRET: ${{ secrets.OSS_ACCESS_KEY_SECRET }}
|
||||||
|
run: |
|
||||||
|
curl -sL https://gosspublic.alicdn.com/ossutil/install.sh | sudo bash
|
||||||
|
|
||||||
|
# Write config file for non-interactive use
|
||||||
|
cat > $HOME/.ossutilconfig << EOF
|
||||||
|
[Credentials]
|
||||||
|
language=EN
|
||||||
|
endpoint=oss-cn-hangzhou.aliyuncs.com
|
||||||
|
accessKeyID=${OSS_ACCESS_KEY_ID}
|
||||||
|
accessKeySecret=${OSS_ACCESS_KEY_SECRET}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
ossutil --version
|
||||||
|
|
||||||
|
- name: "Upload to OSS: latest/ (overwrite)"
|
||||||
|
run: |
|
||||||
|
# Clean old latest/ to remove stale version files
|
||||||
|
ossutil rm -r -f oss://valuecell-clawx/latest/ || true
|
||||||
|
|
||||||
|
# Upload all files with no-cache so clients always get the freshest version
|
||||||
|
ossutil cp -r -f \
|
||||||
|
staging/latest/ \
|
||||||
|
oss://valuecell-clawx/latest/ \
|
||||||
|
--meta "Cache-Control:no-cache,no-store,must-revalidate"
|
||||||
|
|
||||||
|
echo "Uploaded to latest/"
|
||||||
|
|
||||||
|
- name: "Upload to OSS: releases/vX.Y.Z/ (archive)"
|
||||||
|
run: |
|
||||||
|
TAG="${{ steps.version.outputs.tag }}"
|
||||||
|
|
||||||
|
# Upload to permanent archive (long cache, immutable)
|
||||||
|
ossutil cp -r \
|
||||||
|
staging/releases/${TAG}/ \
|
||||||
|
oss://valuecell-clawx/releases/${TAG}/ \
|
||||||
|
--meta "Cache-Control:public,max-age=31536000,immutable"
|
||||||
|
|
||||||
|
echo "Uploaded to releases/${TAG}/"
|
||||||
|
|
||||||
|
- name: Verify OSS upload
|
||||||
|
run: |
|
||||||
|
TAG="${{ steps.version.outputs.tag }}"
|
||||||
|
|
||||||
|
echo "=== latest/ ==="
|
||||||
|
ossutil ls oss://valuecell-clawx/latest/ --short
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== releases/${TAG}/ ==="
|
||||||
|
ossutil ls oss://valuecell-clawx/releases/${TAG}/ --short
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Verify release-info.json ==="
|
||||||
|
curl -sL "https://valuecell-clawx.oss-cn-hangzhou.aliyuncs.com/latest/release-info.json" | jq .
|
||||||
|
|||||||
@@ -33,7 +33,12 @@ asarUnpack:
|
|||||||
- "**/*.node"
|
- "**/*.node"
|
||||||
|
|
||||||
# Auto-update configuration
|
# Auto-update configuration
|
||||||
|
# Primary: Alibaba Cloud OSS (fast for Chinese users, used for auto-update)
|
||||||
|
# Fallback: GitHub Releases (backup, used when OSS is unavailable)
|
||||||
publish:
|
publish:
|
||||||
|
- provider: generic
|
||||||
|
url: https://valuecell-clawx.oss-cn-hangzhou.aliyuncs.com/latest
|
||||||
|
useMultipleRangeRequest: false
|
||||||
- provider: github
|
- provider: github
|
||||||
owner: ValueCell-ai
|
owner: ValueCell-ai
|
||||||
repo: ClawX
|
repo: ClawX
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
/**
|
/**
|
||||||
* Auto-Updater Module
|
* Auto-Updater Module
|
||||||
* Handles automatic application updates using electron-updater
|
* Handles automatic application updates using electron-updater
|
||||||
|
*
|
||||||
|
* Update providers are configured in electron-builder.yml (OSS primary, GitHub fallback).
|
||||||
|
* electron-updater handles provider resolution automatically.
|
||||||
*/
|
*/
|
||||||
import { autoUpdater, UpdateInfo, ProgressInfo, UpdateDownloadedEvent } from 'electron-updater';
|
import { autoUpdater, UpdateInfo, ProgressInfo, UpdateDownloadedEvent } from 'electron-updater';
|
||||||
import { BrowserWindow, app, ipcMain } from 'electron';
|
import { BrowserWindow, app, ipcMain } from 'electron';
|
||||||
@@ -113,6 +116,7 @@ export class AppUpdater extends EventEmitter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Check for updates
|
* Check for updates
|
||||||
|
* electron-updater automatically tries providers defined in electron-builder.yml in order
|
||||||
*/
|
*/
|
||||||
async checkForUpdates(): Promise<UpdateInfo | null> {
|
async checkForUpdates(): Promise<UpdateInfo | null> {
|
||||||
try {
|
try {
|
||||||
@@ -120,7 +124,8 @@ export class AppUpdater extends EventEmitter {
|
|||||||
return result?.updateInfo || null;
|
return result?.updateInfo || null;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[Updater] Check for updates failed:', error);
|
console.error('[Updater] Check for updates failed:', error);
|
||||||
return null;
|
this.updateStatus({ status: 'error', error: (error as Error).message || String(error) });
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -129,7 +129,10 @@ export const useUpdateStore = create<UpdateState>((set, get) => ({
|
|||||||
set({ status: 'checking', error: null });
|
set({ status: 'checking', error: null });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await window.electron.ipcRenderer.invoke('update:check') as {
|
const result = await Promise.race([
|
||||||
|
window.electron.ipcRenderer.invoke('update:check'),
|
||||||
|
new Promise((_, reject) => setTimeout(() => reject(new Error('Update check timed out')), 30000))
|
||||||
|
]) as {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
info?: UpdateInfo;
|
info?: UpdateInfo;
|
||||||
error?: string;
|
error?: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user