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
12 changes: 6 additions & 6 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name: Publish

# Three ways to cut a stable release:
# 1. The nightly schedule, 03:00 UTC. Skipped when main has not moved since
# the latest stable release. This is the normal path: a build ships
# every night without anyone dispatching it.
# 1. The schedule, every six hours. Skipped when main has not moved since
# the latest stable release. This is the normal path: a build ships a
# few hours after a change lands without anyone dispatching it.
# 2. Actions → Publish → "Run workflow" — version optional (empty = next
# patch above the highest existing release). Fully CI, no local git.
# 3. Push a vX.Y.Z tag (the original path) — still works identically.
Expand All @@ -12,7 +12,7 @@ name: Publish
# feed and the website's download button follow.
on:
schedule:
- cron: '0 3 * * *'
- cron: '0 */6 * * *'
push:
tags:
- 'v*'
Expand All @@ -32,8 +32,8 @@ concurrency:
jobs:
check:
# Only the scheduled run can be pointless. It compares main against the
# latest stable release rather than a 24h window so a night the cron
# misses is caught up the next night instead of waiting for a new commit.
# latest stable release rather than a fixed window so a run the cron
# misses is caught up by the next one instead of waiting for a new commit.
if: github.event_name != 'schedule' || github.repository == 'Gilbert09/talyn'
runs-on: ubuntu-latest
outputs:
Expand Down
4 changes: 2 additions & 2 deletions claude.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ Every push to main deploys — treat a push as a production release. All deploy/
- **`test.yml`** — every push + PR. 3-OS matrix (macOS/Windows/Ubuntu): full builds → `typecheck` → `lint` → `npm test`. The only gate — nothing blocks a deploy on it, so don't push red.
- **`deploy-backend.yml`** — push to main touching `packages/backend|shared`, `Dockerfile`, `railway.toml` (+ `workflow_dispatch`). Deploys to Railway via CLI token; cutover is health-gated (`/health` does a real DB check and 503s while draining), so a boot-refusing build keeps the old one serving. NOTE: every deploy briefly overlaps old+new instances — the pg advisory locks (`services/advisoryLock.ts`) exist for exactly that window.
- **`deploy-marketing.yml`** — push to main touching `apps/marketing/**`. Lint + typecheck gate, then Vercel prebuilt deploy to www.talyn.dev.
- **`publish.yml`** — the **stable release**, cut **every night at 03:00 UTC** and on demand. The scheduled run is skipped when main has not moved since the latest stable release (`/releases/latest` + the compare API, so a night the cron misses is caught up the next night). On demand: Actions → Publish → "Run workflow" (version input optional; empty auto-picks the next patch, and electron-builder creates the release AND the tag, so no local git needed) or push a `vX.Y.Z` tag. Builds **macOS arm64+x64 (signed + notarized), Windows NSIS, and Linux AppImage**, publishing a **full release**, which is what the updater and the talyn.dev download button follow. The tag/input is the single source of truth for the app version (baked into `release/app/package.json` at build time, never committed). A `concurrency` group queues a manual dispatch behind a scheduled run: the `version` job reads the release list at run time, so two runs in flight would stamp the same version. (`nightly.yml`, which shipped arm64-only pre-releases on the same cron to nightly-channel users only, was folded into this in Session 96.)
- **`publish.yml`** — the **stable release**, cut **every six hours** and on demand. The scheduled run is skipped when main has not moved since the latest stable release (`/releases/latest` + the compare API, so a run the cron misses is caught up by the next one). On demand: Actions → Publish → "Run workflow" (version input optional; empty auto-picks the next patch, and electron-builder creates the release AND the tag, so no local git needed) or push a `vX.Y.Z` tag. Builds **macOS arm64+x64 (signed + notarized), Windows NSIS, and Linux AppImage**, publishing a **full release**, which is what the updater and the talyn.dev download button follow. The tag/input is the single source of truth for the app version (baked into `release/app/package.json` at build time, never committed). A `concurrency` group queues a manual dispatch behind a scheduled run: the `version` job reads the release list at run time, so two runs in flight would stamp the same version. (`nightly.yml`, which shipped arm64-only pre-releases on the same cron to nightly-channel users only, was folded into this in Session 96.)

**Job shape**: a `version` job resolves the version ONCE and fans it out (three legs each computing "next patch above the latest release" would race), then the **macOS leg runs alone** — it's what creates the GitHub Release (and the tag, on the schedule and dispatch paths) — and only then does a `windows-latest`/`ubuntu-latest` matrix upload into it. Keep that ordering: parallelising all three races three electron-builder processes to create the same release, and chaining means a Windows/Linux failure can't take down a macOS release that already published. **Windows ships unsigned** until an EV cert is bought (SmartScreen warns on first install); setting `CSC_LINK`/`CSC_KEY_PASSWORD` fixes it with no workflow change.

**Update channels**: the desktop picker (Settings → About; persisted in userData via `src/main/updateChannel.ts`, default `stable`) maps to electron-updater's `allowPrerelease`. Since Session 96 nothing publishes a pre-release, so both channels receive the same nightly stable build. The picker is kept so a pre-release track can come back without a client change; removing it (and the "every build as it lands" copy) is an open follow-up.
**Update channels**: the desktop picker (Settings → About; persisted in userData via `src/main/updateChannel.ts`, default `stable`) maps to electron-updater's `allowPrerelease`. Since Session 96 nothing publishes a pre-release, so both channels receive the same stable build. The picker is kept so a pre-release track can come back without a client change; removing it (and the "every build as it lands" copy) is an open follow-up.

## Testing — run only the relevant tests while iterating

Expand Down
Loading