Skip to content

feat: add beta release channel and split macOS arch builds#390

Merged
skevetter merged 6 commits into
mainfrom
simplify-releases
May 19, 2026
Merged

feat: add beta release channel and split macOS arch builds#390
skevetter merged 6 commits into
mainfrom
simplify-releases

Conversation

@skevetter

@skevetter skevetter commented May 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Split macOS desktop builds from universal into separate arm64 and x64 builds for faster CI and smaller downloads
  • Add release channel support (stable/beta) to the desktop app auto-updater with a UI toggle in Settings > Updates
  • Add --channel beta flag to devsy self-update CLI command for opting into pre-release versions
  • Deploy electron update metadata for both channels (stable → latest*.yml, beta → beta*.yml) to Netlify
  • Metadata deploy now runs for all releases and preserves the other channel's files via fetch-before-deploy
  • Add hack/merge-mac-metadata.py to combine macOS metadata from the two separate arch builds

Summary by CodeRabbit

  • New Features

    • Added release channel selection (Stable/Beta) in desktop app Settings for update preferences.
    • CLI now supports --channel flag to specify update channels (defaults to stable).
    • Separated macOS downloads into distinct builds for Apple Silicon and Intel processors.
  • Chores

    • Updated release automation and build workflows.
    • Refactored update mechanism architecture.

Review Change Stack

skevetter added 3 commits May 19, 2026 14:10
…flow

GITHUB_TOKEN events don't trigger downstream workflows. Using the App
token ensures the release:published event triggers release.yml to build
CLI and desktop artifacts.
Electron-builder does not generate latest*.yml auto-update manifests for
pre-release versions. The deploy-update-metadata job now only runs for
stable releases, preventing failures when no metadata artifacts exist.
- Split macOS desktop builds from universal into separate arm64 and x64
  builds for faster CI and smaller download sizes
- Add release channel (stable/beta) support to desktop auto-updater with
  persistence and UI toggle in Settings
- Add --channel flag to CLI self-update command for opting into pre-releases
- Deploy electron update metadata for both stable and beta channels
- Add merge script for combining macOS metadata from separate arch builds
@coderabbitai

coderabbitai Bot commented May 19, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@skevetter has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 25 minutes and 39 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 23b54a79-24b6-44db-b54f-e86d80ed6f23

📥 Commits

Reviewing files that changed from the base of the PR and between e89c1dd and 3236f25.

📒 Files selected for processing (10)
  • .github/workflows/release.yml
  • cmd/self_update.go
  • cmd/self_update_test.go
  • desktop/src/main/ipc.ts
  • desktop/src/main/updater.ts
  • desktop/src/renderer/src/lib/ipc/commands.ts
  • desktop/src/renderer/src/lib/ipc/events.ts
  • desktop/src/renderer/src/lib/ipc/mock.ts
  • desktop/src/renderer/src/pages/SettingsPage.svelte
  • hack/merge-mac-metadata.py
📝 Walkthrough

Walkthrough

This PR implements multi-channel update support (stable and beta) for the desktop application while simultaneously refactoring the build system to produce separate architecture-specific macOS binaries instead of universal ones. The changes flow from library-level channel support through CLI and desktop integration, culminating in a new Settings UI for channel selection, alongside a coordinated build infrastructure update with metadata merging.

Changes

Multi-Channel Release Support

Layer / File(s) Summary
Core self-update library channel support
pkg/selfupdate/selfupdate.go
New Options struct groups Version, DryRun, and IncludePrerelease fields; Upgrade refactored to accept Options and pass it to detectRelease, which now configures the go-selfupdate updater's Prerelease flag based on channel selection.
CLI self-update channel flag
cmd/self_update.go, cmd/self_update_test.go
SelfUpdateCmd gains a Channel field; --channel flag registered with stable default; RunE constructs selfupdate.Options with IncludePrerelease derived from channel comparison; test verifies flag presence and default.
Desktop updater channel persistence and configuration
desktop/src/main/updater.ts, desktop/src/main/ipc.ts
updater.ts persists release channel to a JSON settings file in Electron's userData directory, loads it on init, configures electron-updater for prerelease allowance, and exports getReleaseChannel/setReleaseChannel/checkForUpdatesWithChannel helpers; ipc.ts adds get_release_channel and set_release_channel handlers that update the channel and trigger update checks.
Renderer channel selection UI
desktop/src/renderer/src/lib/ipc/commands.ts, desktop/src/renderer/src/pages/SettingsPage.svelte
IPC command layer exports ReleaseChannel type and async getReleaseChannel/setReleaseChannel wrappers; Settings page adds releaseChannel state, handleChannelChange handler, loads current channel on mount, and renders Stable/Beta buttons in the Updates section with styling and click handlers wired to the channel change flow.

Multi-Architecture Build and Release

Layer / File(s) Summary
Electron build config for separate architectures
desktop/electron-builder.yml
macOS target configuration changed from single universal entry to separate x64 and arm64 entries for both dmg and zip formats, while preserving the artifactName pattern Devsy_${os}_${arch}.${ext}.
Release workflow matrix and metadata merging
.github/workflows/release.yml, hack/merge-mac-metadata.py
Build-desktop matrix refactored from per-OS fields to explicit named variants (linux-x64, macos-arm64, macos-x64, windows-x64) with go-os/go-arch/builder-args values; CLI binary staging simplified to copy based on matrix fields; provider generation and flatpak steps gated to linux-x64 variant. deploy-update-metadata now fetches existing metadata from the live site, uses a new Python script to merge macOS metadata files across architectures, and overlays all metadata into the publish directory. New hack/merge-mac-metadata.py script searches for and merges latest-mac/beta-mac YAML files, concatenating files arrays and setting top-level metadata from the first entry.
Release authentication and downloads documentation
.github/workflows/create-release.yml, README.md
Create-release workflow now generates a GitHub App installation token via actions/create-github-app-token@v3 and uses it for the gh release create step via GH_TOKEN environment variable. README Downloads table for macOS updated to replace the single Universal DMG entry with two separate entries (Apple Silicon ARM64 and Intel x64).

Sequence Diagram

sequenceDiagram
  participant User as User (Desktop App)
  participant Settings as SettingsPage.svelte
  participant IPC as Main IPC Handler
  participant Updater as updater.ts
  participant ElectronUpdater as electron-updater
  
  User->>Settings: Click release channel (Beta)
  Settings->>IPC: invoke('set_release_channel', 'beta')
  IPC->>Updater: setReleaseChannel('beta')
  Updater->>Updater: Save to userData/settings.json
  Updater->>ElectronUpdater: Configure with channel='beta', allowPrerelease=true
  Updater->>ElectronUpdater: checkForUpdates()
  ElectronUpdater-->>Updater: Prerelease updates available
  Updater-->>IPC: Update event
  IPC-->>Settings: Success toast
  Settings-->>User: Channel updated to Beta
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

The PR spans multiple subsystems (library, CLI, desktop backend, renderer UI, build workflow) with moderate logic density. The core changes are well-contained within their layers: channel option refactoring is straightforward, IPC wiring is standard, and the build matrix refactor is mechanical but requires attention to condition changes. The metadata merging script adds complexity in the release workflow. Review effort is moderate due to the breadth of files and the need to verify cross-layer consistency (library → CLI → desktop → UI), but individual changes are not intricate.

Possibly related PRs

  • devsy-org/devsy#303: Modifies the same .github/workflows/release.yml deploy-update-metadata job to change how desktop update metadata is assembled and served.
  • devsy-org/devsy#314: Modifies the same desktop release workflow in the provider-generation and build steps via the OS/arch matrix.
  • devsy-org/devsy#321: Overlaps in the same release workflow (.github/workflows/release.yml) in update-metadata and Flatpak-related steps and permissions.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.79% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the two main features: adding beta release channel support and splitting macOS architecture builds into separate binaries.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/create-release.yml:
- Around line 16-20: Replace the mutable tag actions/create-github-app-token@v3
used in the step with a full commit SHA to pin the exact action version; update
the step with id "app-token" (the block that supplies app-id and private-key
inputs) to reference actions/create-github-app-token@<full-commit-sha> (use the
commit SHA from the action's release tag) so the release workflow's
authentication step is immutable and provenance is preserved.

In @.github/workflows/release.yml:
- Line 232: The checkout step currently uses actions/checkout@v6 without
disabling credential persistence; update the actions/checkout call to set
persist-credentials: false (add a with: block containing persist-credentials:
false) so the deploy metadata checkout does not retain GH token credentials
during the job; target the checkout invocation that references
actions/checkout@v6 to make this change.
- Around line 232-235: Replace the floating action tags with full commit SHAs
for supply-chain pinning: locate the two steps using "uses: actions/checkout@v6"
and "uses: actions/download-artifact@v8" (the checkout step and the "download
update metadata artifacts" step) and change each to the corresponding
repository@<full-commit-sha> form (e.g., actions/checkout@<sha> and
actions/download-artifact@<sha>), fetching the latest trusted commit SHAs from
the official action repos and updating the workflow YAML accordingly so the
actions are pinned to immutable commit SHAs.

In `@cmd/self_update.go`:
- Around line 26-31: Validate the provided channel string and reject unknown
values instead of silently treating them as stable: check cmd.Channel against
the allowed values (e.g., "stable" and "beta") before building
selfupdate.Options, return an error (or exit) when the value is unrecognized
(typo like "bata") and only set IncludePrerelease = true when cmd.Channel ==
"beta"; apply the same validation in the other place that constructs
selfupdate.Options/sets IncludePrerelease so both occurrences enforce valid
channels and surface a clear error message.

In `@desktop/src/main/ipc.ts`:
- Around line 670-676: Validate the IPC payload before casting in the
"set_release_channel" handler: ensure args.channel is one of the allowed
ReleaseChannel values (e.g., check against the ReleaseChannel enum or permitted
string set) and reject/throw or return an error if not; only then call
setReleaseChannel(channel) and await checkForUpdatesWithChannel(channel). Update
the ipcMain.handle("set_release_channel", ...) logic to perform this guard and
avoid the unchecked cast to ReleaseChannel.

In `@desktop/src/renderer/src/pages/SettingsPage.svelte`:
- Around line 148-155: handleChannelChange currently sets the UI state
optimistically by assigning releaseChannel = channel before persisting with
setReleaseChannelIpc; when persistence fails the UI is never reverted. Save the
previous value (e.g., const prev = releaseChannel) before assigning, call await
setReleaseChannelIpc(channel) as you do, and in the catch restore releaseChannel
= prev and keep the error toast using extractErrorMessage(err); reference
function handleChannelChange, variable releaseChannel, and setReleaseChannelIpc
when making the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 926f32a8-dce3-4bd5-b5e0-cc4a05af63bd

📥 Commits

Reviewing files that changed from the base of the PR and between adca389 and e89c1dd.

📒 Files selected for processing (12)
  • .github/workflows/create-release.yml
  • .github/workflows/release.yml
  • README.md
  • cmd/self_update.go
  • cmd/self_update_test.go
  • desktop/electron-builder.yml
  • desktop/src/main/ipc.ts
  • desktop/src/main/updater.ts
  • desktop/src/renderer/src/lib/ipc/commands.ts
  • desktop/src/renderer/src/pages/SettingsPage.svelte
  • hack/merge-mac-metadata.py
  • pkg/selfupdate/selfupdate.go

Comment on lines +16 to +20
- uses: actions/create-github-app-token@v3
id: app-token
with:
app-id: ${{ secrets.DEVSY_GITHUB_APP_ID }}
private-key: ${{ secrets.DEVSY_GITHUB_APP_PRIVATE_KEY }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify non-SHA action refs in create-release workflow
rg -n '^\s*-\s+uses:\s+[^@]+@v[0-9]+' .github/workflows/create-release.yml

Repository: devsy-org/devsy

Length of output: 148


Pin actions/create-github-app-token to a full commit SHA.

@v3 is mutable and weakens provenance guarantees for release-authentication logic. Use the commit SHA from the release tag instead (e.g., actions/create-github-app-token@<full-sha>) to prevent unexpected action updates during release workflows.

🧰 Tools
🪛 zizmor (1.25.2)

[error] 16-16: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 16-16: dangerous use of GitHub App tokens (github-app): app token inherits blanket installation permissions

(github-app)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/create-release.yml around lines 16 - 20, Replace the
mutable tag actions/create-github-app-token@v3 used in the step with a full
commit SHA to pin the exact action version; update the step with id "app-token"
(the block that supplies app-id and private-key inputs) to reference
actions/create-github-app-token@<full-commit-sha> (use the commit SHA from the
action's release tag) so the release workflow's authentication step is immutable
and provenance is preserved.

Comment thread .github/workflows/release.yml
Comment on lines +232 to 235
- uses: actions/checkout@v6

- name: download update metadata artifacts
uses: actions/download-artifact@v8

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify non-SHA action refs in this workflow
rg -n '^\s*-\s+uses:\s+[^@]+@v[0-9]+' .github/workflows/release.yml

Repository: devsy-org/devsy

Length of output: 506


🏁 Script executed:

sed -n '230,240p' .github/workflows/release.yml

Repository: devsy-org/devsy

Length of output: 349


Pin GitHub Actions to full commit SHAs.

Using floating version tags (@v6, @v8) for actions/checkout and actions/download-artifact weakens supply-chain security guarantees and conflicts with strict pinning policy. Pin these actions to their full commit SHAs instead.

🧰 Tools
🪛 zizmor (1.25.2)

[warning] 232-232: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 232-232: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 235-235: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml around lines 232 - 235, Replace the floating
action tags with full commit SHAs for supply-chain pinning: locate the two steps
using "uses: actions/checkout@v6" and "uses: actions/download-artifact@v8" (the
checkout step and the "download update metadata artifacts" step) and change each
to the corresponding repository@<full-commit-sha> form (e.g.,
actions/checkout@<sha> and actions/download-artifact@<sha>), fetching the latest
trusted commit SHAs from the official action repos and updating the workflow
YAML accordingly so the actions are pinned to immutable commit SHAs.

Comment thread cmd/self_update.go
Comment thread desktop/src/main/ipc.ts
Comment thread desktop/src/renderer/src/pages/SettingsPage.svelte
- Validate --channel flag in CLI (reject invalid values in PreRunE)
- Validate IPC set_release_channel input before processing
- Revert UI state on channel switch failure
- Add persist-credentials: false to deploy-update-metadata checkout
- Use argparse in merge-mac-metadata.py
- Overhaul Updates section UI with card-based channel selector
@netlify

netlify Bot commented May 19, 2026

Copy link
Copy Markdown

Deploy Preview for devsydev canceled.

Name Link
🔨 Latest commit 3236f25
🔍 Latest deploy log https://app.netlify.com/projects/devsydev/deploys/6a0cdc352c4237000854d5b5

skevetter added 2 commits May 19, 2026 16:35
Satisfies goconst linter by defining channelStable and channelBeta
constants instead of repeating string literals.
- Add "Check for Updates" button in Settings version section
- Stream update status events (checking/available/downloaded/error) to renderer
- Display release notes when an update is available or downloaded
- Add "Restart & Update" button when update is downloaded
- Add installUpdate IPC handler to trigger quit-and-install from UI
@github-actions github-actions Bot added size/xl and removed size/l labels May 19, 2026
@skevetter skevetter merged commit bda9a80 into main May 19, 2026
53 checks passed
@skevetter skevetter deleted the simplify-releases branch May 19, 2026 22:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant