feat(desktop): add canary build workflow for internal testing#721
Conversation
- Add reusable build-desktop.yml workflow with shared build logic - Add release-desktop-canary.yml for scheduled canary builds (every 12h) - Refactor release-desktop.yml to use reusable workflow - Add electron-builder.canary.ts config extending base config - Add canary-specific icons for visual distinction - Canary builds use separate app ID (com.superset.desktop.canary) for side-by-side installation with stable 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
📝 WalkthroughWalkthroughAdds reusable desktop build workflow, scheduled canary release workflow, canary Electron Builder config, generates update manifests for all channels, and makes the auto-updater prerelease-aware (choosing canary vs latest feeds and exposing version/error in update events). Changes
Sequence Diagram(s)sequenceDiagram
participant Cron as Scheduler (cron / manual)
participant Check as check-changes job
participant BuildWF as build-desktop.yml (reusable workflow)
participant ArtifactStore as GitHub Artifacts
participant Release as release job
participant GH as GitHub API
Cron->>Check: trigger workflow
Check->>GH: query latest canary tag/release
Check->>Check: compare HEAD to canary commit -> outputs should_build, short_sha, build_time
alt should_build = true
Check->>BuildWF: call with channel=canary, version_suffix=-canary
BuildWF->>ArtifactStore: upload artifacts (desktop-canary-*)
BuildWF->>Release: signal artifacts ready
Release->>ArtifactStore: download canary artifacts
Release->>GH: delete existing canary release & tag
Release->>GH: create prerelease and upload artifacts
else should_build = false
Check->>Check: exit (no build)
end
sequenceDiagram
participant App as Desktop App
participant Updater as Auto-Updater module
participant Semver as semver parser
participant Feed as Update Feed (GitHub Releases)
participant GH as GitHub Release API
App->>Updater: initialize on startup
Updater->>Semver: parse app version
Semver->>Updater: isPrerelease?
Updater->>Feed: choose feed URL (desktop-canary or latest)
Updater->>Updater: set allowDowngrade based on prerelease flag
Updater->>GH: fetch update manifest (canary.yml / latest.yml)
GH->>Updater: return manifest
Updater->>App: emit AutoUpdateStatusEvent (status, version?, error?)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
📜 Recent review detailsConfiguration used: defaults Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @.github/workflows/release-desktop-canary.yml:
- Around line 87-105: Update the GitHub Action invocation to use
softprops/action-gh-release@v2 (replace uses: softprops/action-gh-release@v1
with @v2) and change the Built timestamp expression in the release body to use a
reliable timestamp for scheduled runs (e.g., github.run_started_at, fallback to
github.event.workflow_run.head_commit.timestamp, then
github.event.repository.updated_at) so the Built line in the release body (the
body field alongside tag_name, name, prerelease, files) shows a correct time for
scheduled workflows.
🧹 Nitpick comments (2)
apps/desktop/electron-builder.canary.ts (1)
55-59: Windows artifactName contains spaces and uses static version.The Windows
artifactNamediffers from the Linux approach in two ways:
${productName}resolves to "Superset Canary" (with a space), which can cause issues with download URLs and shell scripts.${pkg.version}bakes the version at config-load time, whereas\${version}(as used in Linux) lets electron-builder inject it at build time.Consider aligning with the Linux pattern for consistency:
Suggested fix
win: { ...baseConfig.win, icon: join(pkg.resources, "build/icons/icon-canary.ico"), - artifactName: `${productName}-${pkg.version}-\${arch}.\${ext}`, + artifactName: `superset-canary-\${version}-\${arch}.\${ext}`, },.github/workflows/build-desktop.yml (1)
46-53: Cache key usesgithub.shawhich prevents cross-commit cache hits.Using
github.shaas the cache key means each commit creates a new cache entry and never hits an existing one. Therestore-keysfallback helps, but the primary key should use the lockfile hash for optimal caching.Suggested fix
- name: Cache dependencies uses: actions/cache@v4 with: path: | ~/.bun/install/cache - key: ${{ runner.os }}-bun-${{ github.sha }} + key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock', '**/bun.lockb') }} restore-keys: | ${{ runner.os }}-bun-
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
apps/desktop/src/resources/build/icons/icon-canary.icois excluded by!**/*.icoapps/desktop/src/resources/build/icons/icon-canary.pngis excluded by!**/*.png
📒 Files selected for processing (5)
.github/workflows/build-desktop.yml.github/workflows/release-desktop-canary.yml.github/workflows/release-desktop.ymlapps/desktop/electron-builder.canary.tsapps/desktop/src/resources/build/icons/icon-canary.icns
🧰 Additional context used
📓 Path-based instructions (4)
apps/desktop/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)
apps/desktop/**/*.{ts,tsx}: For Electron interprocess communication, ALWAYS use tRPC as defined insrc/lib/trpc
Use alias as defined intsconfig.jsonwhen possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary.
For tRPC subscriptions with trpc-electron, ALWAYS use the observable pattern from@trpc/server/observableinstead of async generators, as the library explicitly checksisObservable(result)and throws an error otherwise
Files:
apps/desktop/electron-builder.canary.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use object parameters for functions with 2+ parameters instead of positional arguments
Functions with 2+ parameters should accept a single params object with named properties for self-documentation and extensibility
Use prefixed console logging with context pattern: [domain/operation] message
Extract magic numbers and hardcoded values to named constants at module top
Use lookup objects/maps instead of repeated if (type === ...) conditionals
Avoid usinganytype - maintain type safety in TypeScript code
Never swallow errors silently - at minimum log them with context
Import from concrete files directly when possible - avoid barrel file abuse that creates circular dependencies
Avoid deep nesting (4+ levels) - use early returns, extract functions, and invert conditions
Use named properties in options objects instead of boolean parameters to avoid boolean blindness
Files:
apps/desktop/electron-builder.canary.ts
apps/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Drizzle ORM for all database operations - never use raw SQL
Files:
apps/desktop/electron-builder.canary.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Biome for formatting and linting - run at root level with
bun run lint:fixorbiome check --write
Files:
apps/desktop/electron-builder.canary.ts
🪛 actionlint (1.7.10)
.github/workflows/release-desktop-canary.yml
88-88: the runner of "softprops/action-gh-release@v1" action is too old to run on GitHub Actions. update the action's version to fix this issue
(action)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Deploy Docs
- GitHub Check: Deploy Marketing
- GitHub Check: Deploy API
- GitHub Check: Deploy Admin
- GitHub Check: Deploy Web
- GitHub Check: Build
🔇 Additional comments (7)
apps/desktop/electron-builder.canary.ts (1)
17-28: Configuration structure and publish setup look good.The canary config correctly extends the base config, uses a distinct
appIdfor side-by-side installation, and configures GitHub prerelease publishing appropriately..github/workflows/build-desktop.yml (2)
62-84: Compile and build steps are well-structured.The
CANARY_BUILDenvironment variable is consistently set in both steps, secrets are properly referenced, and the electron-builder config is correctly passed via CLI argument.
86-108: Artifact upload configuration looks correct.The uploads use configurable prefixes, appropriate retention days, and fail on missing files. This ensures build failures are detected early.
.github/workflows/release-desktop.yml (2)
18-25: Clean refactor to reusable workflow.The delegation to the reusable build workflow is well-structured with explicit inputs for channel, config, prefix, and retention. Using
secrets: inheritis appropriate here.
37-42: Artifact download pattern correctly scoped.The
pattern: desktop-*filter ensures only desktop artifacts are downloaded, preventing accidental inclusion of unrelated artifacts..github/workflows/release-desktop-canary.yml (2)
26-44: Change detection logic is well-implemented.The script correctly handles three cases: no previous canary tag (first build), same commit (skip), and new changes (build). Using
fetch-depth: 0ensures the tag can be resolved.
78-85: Rolling release cleanup handles edge cases correctly.Using
|| truegracefully handles the case where no previous canary release or tag exists, preventing workflow failures on first run.
🧹 Preview Cleanup CompleteThe following preview resources have been cleaned up:
Thank you for your contribution! 🎉 |
- Canary builds check: /releases/download/desktop-canary - Stable builds check: /releases/latest/download - CANARY_BUILD env var baked in at build time via Vite define 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update softprops/action-gh-release from v1 to v2 in both workflows - Generate build timestamp in check-changes step for reliable scheduling - Timestamp now works correctly for both scheduled and manual runs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In @.github/workflows/release-desktop-canary.yml:
- Around line 16-18: The job outputs block is missing the build_time output, so
the downstream reference needs.check-changes.outputs.build_time will be empty;
update the job outputs (the outputs: mapping that currently contains
should_build and short_sha) to also expose build_time by adding build_time: ${{
steps.check.outputs.build_time }} so the release job can consume the value.
- Around line 60-64: The release job currently runs even if the build job was
skipped, causing artifact download failures; update the release job (named
"release") to run only when the build actually ran by adding a condition like:
if: needs.build.result != 'skipped' (or equivalent check for your should_build
logic) so the release job is skipped when the build job was skipped.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
.github/workflows/release-desktop-canary.yml.github/workflows/release-desktop.yml
🧰 Additional context used
🪛 actionlint (1.7.10)
.github/workflows/release-desktop-canary.yml
95-95: property "build_time" is not defined in object type {short_sha: string; should_build: string}
(expression)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Deploy Web
- GitHub Check: Deploy Docs
- GitHub Check: Deploy Admin
- GitHub Check: Deploy Marketing
- GitHub Check: Deploy API
- GitHub Check: Build
🔇 Additional comments (8)
.github/workflows/release-desktop.yml (3)
18-25: Clean refactor to reusable workflow.The build job correctly delegates to the reusable workflow with appropriate inputs for the stable channel. The
secrets: inheritensures all required secrets are passed through.
37-42: Good addition of pattern filter.The
pattern: desktop-*filter ensures only desktop-related artifacts are downloaded, preventing potential conflicts with artifacts from other workflows.
67-72: Action upgrade and release notes generation.Good upgrade to
softprops/action-gh-release@v2and enablinggenerate_release_notes: truefor automated changelog generation..github/workflows/release-desktop-canary.yml (5)
3-7: Schedule and manual trigger look good.The 12-hour cron schedule with
workflow_dispatchfor manual testing is appropriate for a canary release cadence.
26-47: Change detection logic is sound.The approach correctly handles three cases: no previous canary tag, HEAD matches last canary, and changes detected. Using
fetch-depth: 0ensures tags are available for comparison.
49-58: Build job configuration is correct.The conditional
if: needs.check-changes.outputs.should_build == 'true'properly gates the build, and the 7-day artifact retention is appropriate for canary builds.
81-88: Rolling release cleanup looks correct.Using
|| trueensures idempotency when the release or tag doesn't exist. The sequence of deleting the release first, then the tag, is the correct order.
90-108: Release creation configuration is appropriate.The
prerelease: trueflag, clear warning in the body, and metadata (commit, short SHA) provide good visibility for internal testing builds. Once thebuild_timeoutput fix is applied, this will display the build timestamp correctly.
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use version suffix (-canary) instead of CANARY_BUILD env var - Detect update channel from app version using semver - Set autoUpdater.channel instead of manual feed URL - Enable generateUpdatesFilesForAllChannels for proper manifests - Allow downgrade for prerelease builds (canary can go back to stable) This follows VSCode/electron-builder conventions where the version determines the update channel (e.g., 0.0.53-canary -> canary channel). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
apps/desktop/electron-builder.canary.ts (1)
56-61: Inconsistent artifactName templating vs Linux, and space in filename.The Windows
artifactNameuses JavaScript template literal interpolation forproductNameandpkg.version, while Linux (line 53) uses escaped electron-builder placeholders for all variables. Additionally,productNamecontains a space ("Superset Canary") which will produce filenames with spaces.Consider aligning with the Linux pattern for consistency and avoiding spaces in artifact names:
Proposed fix
// Windows overrides win: { ...baseConfig.win, icon: join(pkg.resources, "build/icons/icon-canary.ico"), - artifactName: `${productName}-${pkg.version}-\${arch}.\${ext}`, + artifactName: `superset-canary-\${version}-\${arch}.\${ext}`, },
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
.github/workflows/build-desktop.ymlapps/desktop/electron-builder.canary.tsapps/desktop/src/main/lib/auto-updater.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- .github/workflows/build-desktop.yml
🧰 Additional context used
📓 Path-based instructions (4)
apps/desktop/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)
apps/desktop/**/*.{ts,tsx}: For Electron interprocess communication, ALWAYS use tRPC as defined insrc/lib/trpc
Use alias as defined intsconfig.jsonwhen possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary.
For tRPC subscriptions with trpc-electron, ALWAYS use the observable pattern from@trpc/server/observableinstead of async generators, as the library explicitly checksisObservable(result)and throws an error otherwise
Files:
apps/desktop/src/main/lib/auto-updater.tsapps/desktop/electron-builder.canary.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use object parameters for functions with 2+ parameters instead of positional arguments
Functions with 2+ parameters should accept a single params object with named properties for self-documentation and extensibility
Use prefixed console logging with context pattern: [domain/operation] message
Extract magic numbers and hardcoded values to named constants at module top
Use lookup objects/maps instead of repeated if (type === ...) conditionals
Avoid usinganytype - maintain type safety in TypeScript code
Never swallow errors silently - at minimum log them with context
Import from concrete files directly when possible - avoid barrel file abuse that creates circular dependencies
Avoid deep nesting (4+ levels) - use early returns, extract functions, and invert conditions
Use named properties in options objects instead of boolean parameters to avoid boolean blindness
Files:
apps/desktop/src/main/lib/auto-updater.tsapps/desktop/electron-builder.canary.ts
apps/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Drizzle ORM for all database operations - never use raw SQL
Files:
apps/desktop/src/main/lib/auto-updater.tsapps/desktop/electron-builder.canary.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Biome for formatting and linting - run at root level with
bun run lint:fixorbiome check --write
Files:
apps/desktop/src/main/lib/auto-updater.tsapps/desktop/electron-builder.canary.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Deploy Docs
🔇 Additional comments (7)
apps/desktop/electron-builder.canary.ts (3)
1-14: LGTM!Clean module setup with proper imports and JSDoc documentation. The canary configuration correctly extends the base config for side-by-side installation capability.
15-31: LGTM!The canary-specific identifiers are well-structured:
- Separate
appIdenables side-by-side installation with stable builds.- GitHub prerelease publishing is correctly configured.
- The comment clarifies that runtime feed URL override occurs in
auto-updater.ts.
42-46: LGTM!Distinct deep link scheme
superset-canary://prevents conflicts with stable builds and allows proper routing.apps/desktop/src/main/lib/auto-updater.ts (4)
6-6: LGTM!Appropriate use of the
semverlibrary'sprereleasefunction for version parsing.
11-23: LGTM!Clean prerelease detection implementation. The function correctly identifies canary builds by checking for non-empty prerelease components in the semver version string. Computing
IS_PRERELEASEat module load time is safe sinceapp.getVersion()is synchronous and available immediately.
25-30: LGTM!The feed URL routing is well-designed:
- Canary builds fetch from a fixed rolling tag (
desktop-canary).- Stable builds use
/releases/latest/download/which automatically resolves to the latest non-prerelease.The inline comments clearly document the behavior.
172-180: LGTM!Solid auto-updater configuration:
allowDowngrade = IS_PRERELEASEis a thoughtful UX decision—canary users can revert to stable if needed.- Using the generic provider with explicit feed URL ensures correct manifest resolution regardless of the electron-builder publish config.
Remove separate superset-canary:// protocol so auth callbacks from web/api work correctly with the canary build.
Summary
build-desktop.ymlworkflow with shared build logicrelease-desktop-canary.ymlfor scheduled canary builds (every 12 hours)release-desktop.ymlto use reusable workflow (reduces duplication)electron-builder.canary.tsconfig extending base configDetails
Canary builds:
com.superset.desktop.canary) for side-by-side installsuperset-canary://)desktop-canarytag/releaseworkflow_dispatchTest plan
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.