Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions .github/workflows/release-beta.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,25 @@ name: Build & Release (Beta)
# Runs automatically on every push to `testing` (code changes) and can also be
# run by hand from Actions → "Build & Release (Beta)" → Run workflow. Each run
# computes the next beta version, builds the Windows installer, and publishes a
# GitHub *prerelease* carrying a `beta.yml` manifest.
# GitHub *prerelease* carrying a `testing.yml` manifest.
#
# Isolation from the stable channel (see .github/workflows/release.yml):
# • Beta versions look like X.Y.Z-beta.N → electron-builder emits `beta.yml`.
# • Beta versions look like X.Y.Z-testing.N → electron-builder emits
# `testing.yml`. The channel is deliberately named "testing" and NOT "beta":
# electron-updater hardcodes "alpha"/"beta" as cascading channels that also
# pull stable releases, which would break isolation. "testing" is treated as
# a fully isolated channel. (See the note in src/main/updater.js.)
# • The release is marked --prerelease and is NEVER --latest, so it does not
# replace the stable release on the repo's main page.
# • Only installs built from this workflow (channel = beta, see updater.js)
# • Only installs built from this workflow (channel = testing, see updater.js)
# detect these updates. Stable installs ignore prereleases entirely.
#
# Versioning:
# • Base X.Y.Z = the next patch above the latest stable release (odometer:
# patch 0→99 carries into minor, minor 0→9 carries into major), or the
# numeric part of package.json if it is already higher.
# • N = beta counter for that base: first beta is -beta.1, then -beta.2, ...
# A brand-new base restarts the counter at 1.
# • N = beta counter for that base: first beta is -testing.1, then -testing.2,
# ... A brand-new base restarts the counter at 1.
# • Manual run with "publish" unchecked → test build (installer artifact only,
# no release, no tag).
on:
Expand Down Expand Up @@ -72,7 +76,7 @@ jobs:
if [ -z "$BUMP" ]; then BUMP=patch; fi
if [ -z "$PUBLISH" ]; then PUBLISH=true; fi

# Numeric part of package.json (drop any -beta suffix).
# Numeric part of package.json (drop any prerelease suffix).
PKG=$(node -p "require('./package.json').version" | sed 's/-.*$//')

# Latest STABLE release (plain X.Y.Z tags only — beta tags excluded).
Expand Down Expand Up @@ -109,11 +113,11 @@ jobs:
fi

# Highest existing beta counter for this base, then +1.
LASTN=$(git tag -l "v$BASE-beta.*" | sed "s/^v$BASE-beta\.//" \
LASTN=$(git tag -l "v$BASE-testing.*" | sed "s/^v$BASE-testing\.//" \
| grep -E '^[0-9]+$' | sort -n | tail -n1 || true)
if [ -z "$LASTN" ]; then N=1; else N=$((LASTN+1)); fi

NEW="$BASE-beta.$N"
NEW="$BASE-testing.$N"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Set the GitHub publish channel for testing

With NEW now using -testing.N, this workflow relies on electron-builder to emit testing.yml, but I checked electron-builder.yml and its GitHub publish config still has no channel. The electron-builder docs for detectUpdateChannel say it “does not apply to github publishing,” and the release-channel docs warn that GitHub publishing must explicitly set channel; as written, npx electron-builder --win --publish always will keep uploading latest.yml while the new updater code looks for testing.yml, so beta installs will not discover these releases.

Useful? React with 👍 / 👎.


echo "version=$NEW" >> "$GITHUB_OUTPUT"
echo "tag=v$NEW" >> "$GITHUB_OUTPUT"
Expand Down
25 changes: 15 additions & 10 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,23 @@ WaterDrop ships on two independent auto-update channels, one per branch:
(marked `--latest`) with versions like `X.Y.Z` and a `latest.yml` manifest.
- **beta** — the `testing` branch. Pushing to `testing` triggers
`.github/workflows/release-beta.yml`, which publishes a GitHub *prerelease*
(never `--latest`) with versions like `X.Y.Z-beta.N` and a `beta.yml`
(never `--latest`) with versions like `X.Y.Z-testing.N` and a `testing.yml`
manifest.

The channels are fully isolated: `src/main/updater.js` sets
`autoUpdater.channel` from the running build's own version (a `-beta` suffix →
`beta` channel, otherwise `latest`). A beta install only ever sees new betas; a
stable install only ever sees new stable releases. There is intentionally **no**
`generateUpdatesFilesForAllChannels`, so neither channel writes the other's
`.yml`. Promoting a feature = land it on `testing` first, then merge/push to
`main` for the stable release.
`autoUpdater.channel` from the running build's own version (prerelease tag →
that channel, otherwise `latest`). A beta install only ever sees new betas; a
stable install only ever sees new stable releases. Promoting a feature = land it
on `testing` first, then merge/push to `main` for the stable release.

**Do not rename the beta channel to "alpha" or "beta".** electron-updater's
GitHub provider hardcodes those two identifiers as *cascading* channels: a
client on `beta` is forced to also accept stable releases and fall back to
`latest.yml`, which breaks the isolation. The channel is therefore called
`testing` (any name other than alpha/beta works). The GitHub release title still
reads "(beta)" for humans.

Beta versioning: base `X.Y.Z` is the next patch above the latest stable release
(or `package.json` if higher), and `N` is a per-base beta counter that restarts
at 1 for each new base. This is handled automatically by the workflow — no
manual version edits needed for betas.
(or `package.json` if higher), and `N` is a per-base counter that restarts at 1
for each new base. This is handled automatically by the workflow — no manual
version edits needed for betas.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "waterdrop",
"version": "0.1.8",
"version": "0.1.9",
"description": "Private AirDrop-style file shelf for Tailscale networks.",
"main": "src/main/main.js",
"scripts": {
Expand Down
21 changes: 15 additions & 6 deletions src/main/updater.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,21 @@ function initUpdater(window) {
autoUpdater.autoInstallOnAppQuit = true;

// Channel isolation: the build's own version decides which release channel it
// follows. A beta build (version like `1.2.3-beta.4`) reads only `beta.yml`
// from prerelease GitHub Releases; a stable build (`1.2.3`) reads only
// `latest.yml` from full releases. Neither ever sees the other's updates.
const isBeta = app.getVersion().includes("-");
autoUpdater.channel = isBeta ? "beta" : "latest";
autoUpdater.allowPrerelease = isBeta; // beta must opt in to prerelease GitHub Releases
// follows. A prerelease build (e.g. `1.2.3-testing.4`) follows a custom
// channel named after its prerelease tag ("testing") and reads only
// `testing.yml` from prerelease GitHub Releases. A stable build (`1.2.3`)
// follows "latest" and reads only `latest.yml`.
//
// The channel name must NOT be "alpha"/"beta": electron-updater's GitHub
// provider hardcodes those two as cascading channels — a beta client is made
// to also accept stable releases and fall back to `latest.yml`, which would
// defeat the isolation. Any other name is treated as a fully isolated channel.
const version = app.getVersion();
const prereleaseTag = version.includes("-")
? version.split("-")[1].split(".")[0]
: null;
autoUpdater.channel = prereleaseTag || "latest";
autoUpdater.allowPrerelease = prereleaseTag !== null;

wireAutoUpdaterEvents();

Expand Down
Loading
Loading