Skip to content

Commit 9e5fdc5

Browse files
authored
fix(update): electron update function (#32)
1 parent e8a7377 commit 9e5fdc5

File tree

4 files changed

+168
-2
lines changed

4 files changed

+168
-2
lines changed

.github/workflows/release.yml

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ jobs:
121121
release/latest*.yml
122122
retention-days: 7
123123

124+
# ──────────────────────────────────────────────────────────────
125+
# Job: Publish to GitHub Releases
126+
# ──────────────────────────────────────────────────────────────
124127
publish:
125128
needs: release
126129
runs-on: ubuntu-latest
@@ -195,3 +198,153 @@ jobs:
195198
💬 Found an issue? Please submit an [Issue](https://github.com/${{ github.repository }}/issues)
196199
env:
197200
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
201+
202+
# ──────────────────────────────────────────────────────────────
203+
# Job: Upload to Alibaba Cloud OSS
204+
# Uploads all release artifacts to OSS for:
205+
# - Official website downloads (via release-info.json)
206+
# - electron-updater auto-update (via latest-*.yml)
207+
#
208+
# Directory structure on OSS:
209+
# latest/ → always overwritten with the newest version
210+
# releases/vX.Y.Z/ → permanent archive, never deleted
211+
# ──────────────────────────────────────────────────────────────
212+
upload-oss:
213+
needs: release
214+
runs-on: ubuntu-latest
215+
216+
steps:
217+
- name: Checkout code
218+
uses: actions/checkout@v4
219+
220+
- name: Download all artifacts
221+
uses: actions/download-artifact@v4
222+
with:
223+
path: release-artifacts
224+
225+
- name: Extract version
226+
id: version
227+
run: |
228+
if [[ "${{ github.ref }}" == refs/tags/v* ]]; then
229+
VERSION="${GITHUB_REF#refs/tags/v}"
230+
else
231+
VERSION="${{ github.event.inputs.version }}"
232+
fi
233+
echo "version=${VERSION}" >> $GITHUB_OUTPUT
234+
echo "tag=v${VERSION}" >> $GITHUB_OUTPUT
235+
echo "Detected version: ${VERSION}"
236+
237+
- name: Prepare upload directories
238+
run: |
239+
VERSION="${{ steps.version.outputs.version }}"
240+
TAG="${{ steps.version.outputs.tag }}"
241+
242+
mkdir -p staging/latest
243+
mkdir -p staging/releases/${TAG}
244+
245+
# Flatten all platform artifacts into staging directories
246+
find release-artifacts/ -type f | while read file; do
247+
filename=$(basename "$file")
248+
cp "$file" "staging/latest/${filename}"
249+
cp "$file" "staging/releases/${TAG}/${filename}"
250+
done
251+
252+
echo "=== staging/latest/ ==="
253+
ls -lh staging/latest/
254+
echo ""
255+
echo "=== staging/releases/${TAG}/ ==="
256+
ls -lh staging/releases/${TAG}/
257+
258+
- name: Generate release-info.json
259+
run: |
260+
VERSION="${{ steps.version.outputs.version }}"
261+
BASE_URL="https://valuecell-clawx.oss-cn-hangzhou.aliyuncs.com/latest"
262+
263+
jq -n \
264+
--arg version "$VERSION" \
265+
--arg date "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
266+
--arg base "$BASE_URL" \
267+
--arg changelog "https://github.com/${{ github.repository }}/releases/tag/v${VERSION}" \
268+
'{
269+
version: $version,
270+
releaseDate: $date,
271+
downloads: {
272+
mac: {
273+
x64: ($base + "/ClawX-" + $version + "-mac-x64.dmg"),
274+
arm64: ($base + "/ClawX-" + $version + "-mac-arm64.dmg")
275+
},
276+
win: {
277+
x64: ($base + "/ClawX-" + $version + "-win-x64.exe"),
278+
arm64: ($base + "/ClawX-" + $version + "-win-arm64.exe")
279+
},
280+
linux: {
281+
deb_amd64: ($base + "/ClawX-" + $version + "-linux-amd64.deb"),
282+
deb_arm64: ($base + "/ClawX-" + $version + "-linux-arm64.deb"),
283+
appimage_x64: ($base + "/ClawX-" + $version + "-linux-x86_64.AppImage"),
284+
appimage_arm64: ($base + "/ClawX-" + $version + "-linux-arm64.AppImage"),
285+
rpm_x64: ($base + "/ClawX-" + $version + "-linux-x86_64.rpm")
286+
}
287+
},
288+
changelog: $changelog
289+
}' > staging/latest/release-info.json
290+
291+
echo "=== release-info.json ==="
292+
cat staging/latest/release-info.json
293+
294+
- name: Install and configure ossutil
295+
env:
296+
OSS_ACCESS_KEY_ID: ${{ secrets.OSS_ACCESS_KEY_ID }}
297+
OSS_ACCESS_KEY_SECRET: ${{ secrets.OSS_ACCESS_KEY_SECRET }}
298+
run: |
299+
curl -sL https://gosspublic.alicdn.com/ossutil/install.sh | sudo bash
300+
301+
# Write config file for non-interactive use
302+
cat > $HOME/.ossutilconfig << EOF
303+
[Credentials]
304+
language=EN
305+
endpoint=oss-cn-hangzhou.aliyuncs.com
306+
accessKeyID=${OSS_ACCESS_KEY_ID}
307+
accessKeySecret=${OSS_ACCESS_KEY_SECRET}
308+
EOF
309+
310+
ossutil --version
311+
312+
- name: "Upload to OSS: latest/ (overwrite)"
313+
run: |
314+
# Clean old latest/ to remove stale version files
315+
ossutil rm -r -f oss://valuecell-clawx/latest/ || true
316+
317+
# Upload all files with no-cache so clients always get the freshest version
318+
ossutil cp -r -f \
319+
staging/latest/ \
320+
oss://valuecell-clawx/latest/ \
321+
--meta "Cache-Control:no-cache,no-store,must-revalidate"
322+
323+
echo "Uploaded to latest/"
324+
325+
- name: "Upload to OSS: releases/vX.Y.Z/ (archive)"
326+
run: |
327+
TAG="${{ steps.version.outputs.tag }}"
328+
329+
# Upload to permanent archive (long cache, immutable)
330+
ossutil cp -r \
331+
staging/releases/${TAG}/ \
332+
oss://valuecell-clawx/releases/${TAG}/ \
333+
--meta "Cache-Control:public,max-age=31536000,immutable"
334+
335+
echo "Uploaded to releases/${TAG}/"
336+
337+
- name: Verify OSS upload
338+
run: |
339+
TAG="${{ steps.version.outputs.tag }}"
340+
341+
echo "=== latest/ ==="
342+
ossutil ls oss://valuecell-clawx/latest/ --short
343+
344+
echo ""
345+
echo "=== releases/${TAG}/ ==="
346+
ossutil ls oss://valuecell-clawx/releases/${TAG}/ --short
347+
348+
echo ""
349+
echo "=== Verify release-info.json ==="
350+
curl -sL "https://valuecell-clawx.oss-cn-hangzhou.aliyuncs.com/latest/release-info.json" | jq .

electron-builder.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,12 @@ asarUnpack:
3333
- "**/*.node"
3434

3535
# Auto-update configuration
36+
# Primary: Alibaba Cloud OSS (fast for Chinese users, used for auto-update)
37+
# Fallback: GitHub Releases (backup, used when OSS is unavailable)
3638
publish:
39+
- provider: generic
40+
url: https://valuecell-clawx.oss-cn-hangzhou.aliyuncs.com/latest
41+
useMultipleRangeRequest: false
3742
- provider: github
3843
owner: ValueCell-ai
3944
repo: ClawX

electron/main/updater.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
/**
22
* Auto-Updater Module
33
* Handles automatic application updates using electron-updater
4+
*
5+
* Update providers are configured in electron-builder.yml (OSS primary, GitHub fallback).
6+
* electron-updater handles provider resolution automatically.
47
*/
58
import { autoUpdater, UpdateInfo, ProgressInfo, UpdateDownloadedEvent } from 'electron-updater';
69
import { BrowserWindow, app, ipcMain } from 'electron';
@@ -113,14 +116,16 @@ export class AppUpdater extends EventEmitter {
113116

114117
/**
115118
* Check for updates
119+
* electron-updater automatically tries providers defined in electron-builder.yml in order
116120
*/
117121
async checkForUpdates(): Promise<UpdateInfo | null> {
118122
try {
119123
const result = await autoUpdater.checkForUpdates();
120124
return result?.updateInfo || null;
121125
} catch (error) {
122126
console.error('[Updater] Check for updates failed:', error);
123-
return null;
127+
this.updateStatus({ status: 'error', error: (error as Error).message || String(error) });
128+
throw error;
124129
}
125130
}
126131

src/stores/update.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,10 @@ export const useUpdateStore = create<UpdateState>((set, get) => ({
129129
set({ status: 'checking', error: null });
130130

131131
try {
132-
const result = await window.electron.ipcRenderer.invoke('update:check') as {
132+
const result = await Promise.race([
133+
window.electron.ipcRenderer.invoke('update:check'),
134+
new Promise((_, reject) => setTimeout(() => reject(new Error('Update check timed out')), 30000))
135+
]) as {
133136
success: boolean;
134137
info?: UpdateInfo;
135138
error?: string;

0 commit comments

Comments
 (0)