ci: main publishes, so a tag stops being required — and :latest stops shipping a dev client
CI & Build / Build now, or wait for Android? (push) Successful in 3s
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 7s
CI & Build / Python tests (push) Successful in 11s
CI & Build / integration (push) Successful in 17s
CI & Build / Build & push image (push) Skipped
Desktop (Tauri) / Windows installer (cross-compiled) (push) Successful in 3m21s
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 6m36s
Desktop (Tauri) / Update manifest (push) Successful in 4s
Android / Kotlin + Rust (APK) (push) Successful in 9m24s
CI & Build / Build now, or wait for Android? (push) Successful in 3s
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 7s
CI & Build / Python tests (push) Successful in 11s
CI & Build / integration (push) Successful in 17s
CI & Build / Build & push image (push) Skipped
Desktop (Tauri) / Windows installer (cross-compiled) (push) Successful in 3m21s
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 6m36s
Desktop (Tauri) / Update manifest (push) Successful in 4s
Android / Kotlin + Rust (APK) (push) Successful in 9m24s
Step 3 of M314. Note 3127 §0's diagnostic is "is `main` publishing sufficient for a user to receive the build" — and here it was not. The desktop and Android lanes BUILT on main and published nothing: `Publish release` was gated on `refs/tags/v*`, the channel publishes on `refs/heads/dev`, the manifest job on dev-or-tag. So the stable channel moved only when somebody cut a tag, which made a `v*` tag load-bearing rather than the optional bookmark the model wants. Both channels are rolling fixed-tag releases now. `dev` from dev, `stable` from main, same machinery — `publish-release.sh` already took RELEASE_TAG, `write-manifest.sh` already pruned, and both already PATCHed a stale description on 409 (#2182). This is wiring, not new mechanism. ## The defect this carried `ci.yml`'s "Fetch the Android client to bake in" read `releases/download/dev` UNCONDITIONALLY, on every branch. Every image baked in the dev APK — `:latest` included — so a stable server served a dev-channel client to anyone who downloaded it from there. That has nothing to do with versioning; it is fixed here because this is the step that finally gives `stable` an APK to point at. It also means Android needs no channel machinery of its own. The APK is served FROM the image, so the channel is already a property of which image you run — note 3127 §7's "nothing to hand off" shape, arrived at here by accident. One branch-conditional line, not a second channel in `client_dist.py` as this milestone first assumed. ## The break this nearly shipped `install.sh --channel stable` read the version out of `stable/latest.json` and then fetched `releases/tags/v<version>` for the bundles — correct while stable was a manifest-only pointer, and broken the moment stable holds its own. Stable is the DEFAULT channel, so `curl … | sh` would have failed for everyone between this commit and the first merge to main. Both channels are one lookup now: fetch the fixed-tag release, install what is on it. A transitional fallback covers the window where `stable` still has no bundles, marked for deletion in step 7 — without it the default channel is broken for however long it takes to merge, and that window is gated on an operator request rather than on this lane. ## The two writers problem `stable`'s manifest was written by tag builds. It is written by main now, and the tag path stops writing it — two writers for one channel is a race with no winner worth having. A `v*` tag still writes its own versioned manifest; its build consequence goes entirely in step 7. Also corrected: `update.rs`'s header still described stable as following `v*` tags. Nothing in that file moved — it only ever read `<channel>/latest.json` — but the comment was a lie, and it is the file somebody reads to understand the feed. #3143 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -18,7 +18,7 @@ pacman system:
|
||||
curl -fsSL https://git.fabledsword.com/bvandeusen/thoughtsync/raw/branch/dev/desktop/packaging/install.sh | sh
|
||||
```
|
||||
|
||||
That installs the newest tagged release. To follow the rolling development
|
||||
That installs the newest build from `main`. To follow the rolling development
|
||||
channel instead, pass the flag through the pipe:
|
||||
|
||||
```sh
|
||||
|
||||
@@ -5,8 +5,12 @@
|
||||
# curl -fsSL https://git.fabledsword.com/bvandeusen/thoughtsync/raw/branch/dev/desktop/packaging/install.sh | sh
|
||||
#
|
||||
# Two channels, the SAME two the app's own updater offers (src-tauri/src/update.rs):
|
||||
# stable (default) — the newest tagged v* release.
|
||||
# stable (default) — the rolling build from every merge to `main`.
|
||||
# dev — the rolling build from every green push to `dev`.
|
||||
# Both are fixed-tag releases: the tag never moves and the assets are pruned to the
|
||||
# current build, so the tag alone names the newest one. `stable` only became one in
|
||||
# M314 step 3, when `main` started publishing — before that it was a manifest-only
|
||||
# pointer at whatever `v*` tag somebody had last cut.
|
||||
# Pick one with `--channel dev` or `TS_CHANNEL=dev`. Through a pipe the options go
|
||||
# after a `--`: curl -fsSL <url> | sh -s -- --channel dev
|
||||
#
|
||||
@@ -41,7 +45,7 @@ ThoughtSync desktop installer.
|
||||
|
||||
install.sh [--channel stable|dev]
|
||||
|
||||
--channel stable newest tagged release (default)
|
||||
--channel stable newest build from main (default)
|
||||
--channel dev rolling build from the latest green push to `dev`
|
||||
-h, --help this text
|
||||
|
||||
@@ -82,20 +86,23 @@ esac
|
||||
# --- resolve the release for this channel -----------------------------------
|
||||
say "Finding the latest ThoughtSync build on the $channel channel…"
|
||||
|
||||
if [ "$channel" = "dev" ]; then
|
||||
# A release whose tag never moves and whose assets are pruned to the current
|
||||
# build — so the tag alone always names the newest dev build.
|
||||
json="$(curl -fsSL "$API/releases/tags/dev" 2>/dev/null)" ||
|
||||
die "the dev channel has nothing published yet."
|
||||
else
|
||||
# Ask the stable channel's own manifest which version is current, then install
|
||||
# THAT release. This is the same file the in-app updater reads, so the installer
|
||||
# and the updater can never disagree about what `stable` means.
|
||||
#
|
||||
# Not `/releases/latest`: that returns the newest non-prerelease release by date,
|
||||
# and the `stable` pointer release (manifest only, no bundles — see
|
||||
# write-manifest.sh) is itself a non-prerelease created moments after the
|
||||
# versioned one. It would win, and it carries nothing installable.
|
||||
# ONE lookup for both channels now. Each is a release whose tag never moves and whose
|
||||
# assets are pruned to the current build, so the tag alone names the newest build on
|
||||
# that channel — which is exactly what an installer wants and what the in-app updater
|
||||
# already reads.
|
||||
json="$(curl -fsSL "$API/releases/tags/$channel" 2>/dev/null)" ||
|
||||
die "the $channel channel has nothing published yet."
|
||||
|
||||
# TRANSITIONAL — delete with the rest of the old scheme (M314 step 7).
|
||||
#
|
||||
# `stable` existed before this as a manifest-ONLY pointer: `latest.json` naming a
|
||||
# version whose bundles lived on a separate `v<version>` release. Between this commit
|
||||
# and the first merge to `main` it still looks like that, and `stable` is the DEFAULT
|
||||
# channel — so without this fallback `curl … | sh` is broken for everyone in that
|
||||
# window. It costs nothing once main has published: the grep finds the bundles and
|
||||
# this branch never runs again.
|
||||
if [ "$channel" = "stable" ] && ! printf '%s' "$json" | grep -q "releases/download/stable/[^\"]*\.\(AppImage\|deb\|pkg\.tar\)"; then
|
||||
say "stable has no bundles of its own yet — falling back to the version its manifest names."
|
||||
manifest="$(curl -fsSL "$INSTANCE/$REPO/releases/download/stable/latest.json" 2>/dev/null || true)"
|
||||
stable_version="$(printf '%s' "$manifest" |
|
||||
grep -oE '"version"[[:space:]]*:[[:space:]]*"[^"]+"' | head -1 |
|
||||
@@ -104,11 +111,8 @@ else
|
||||
json="$(curl -fsSL "$API/releases/tags/v$stable_version" 2>/dev/null)" ||
|
||||
die "the stable channel names $stable_version, but there is no v$stable_version release to install."
|
||||
else
|
||||
# No stable pointer yet — the channel predates the updater. Fall back to the
|
||||
# newest non-prerelease release, which is what stable meant before there was
|
||||
# a manifest to ask.
|
||||
json="$(curl -fsSL "$API/releases/latest" 2>/dev/null)" ||
|
||||
die "no stable release published yet — try --channel dev, or ask the maintainer to tag one."
|
||||
die "no stable build published yet — try --channel dev, or merge to main."
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
@@ -118,6 +118,11 @@ first_id() { grep -oE '"id"[[:space:]]*:[[:space:]]*[0-9]+' | head -1 | grep -oE
|
||||
# install.sh defaults to stable, so the rolling dev release must opt in explicitly
|
||||
# — otherwise someone following the instructions here lands on a tagged build and
|
||||
# wonders why the version they were sent isn't what they got.
|
||||
#
|
||||
# Both CHANNELS are rolling pointer releases (M314 step 3): `dev` republishes on
|
||||
# every green push to dev, `stable` on every merge to main. Each says so, because a
|
||||
# release that prunes its own assets behaves differently from a versioned one and a
|
||||
# reader deserves to know which they are looking at.
|
||||
if [ "$TAG" = "dev" ]; then
|
||||
INSTALL_TAIL='sh -s -- --channel dev'
|
||||
# Backticks BARE, not `\``. The heredoc below is unquoted, so there the backslash
|
||||
@@ -125,6 +130,10 @@ if [ "$TAG" = "dev" ]; then
|
||||
# Here single quotes already do that job, so a backslash would survive into the
|
||||
# body as `\``, which is not a legal JSON escape: Forgejo answers 422.
|
||||
CHANNEL_NOTE='\n\nThis is the rolling **dev** channel: republished on every green push to `dev`, and pruned to the current build.'
|
||||
elif [ "$TAG" = "stable" ]; then
|
||||
# install.sh defaults to stable, so no flag.
|
||||
INSTALL_TAIL='sh'
|
||||
CHANNEL_NOTE='\n\nThis is the rolling **stable** channel: republished on every merge to `main`, and pruned to the current build. No tag is required for a build to arrive here.'
|
||||
else
|
||||
INSTALL_TAIL='sh'
|
||||
CHANNEL_NOTE=''
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
//! In-app updates (M10.9).
|
||||
//!
|
||||
//! Two channels, because two audiences: `stable` follows tagged `v*` releases,
|
||||
//! `dev` follows every green push. Each reads a `latest.json` published as an asset
|
||||
//! on a release whose TAG NEVER CHANGES — verified necessary, because Forgejo has no
|
||||
//! `/releases/latest/download/<asset>` route (it 404s), so "newest" cannot be named
|
||||
//! in a URL. A fixed tag can.
|
||||
//! Two channels, because two audiences: `stable` follows every merge to `main`,
|
||||
//! `dev` follows every green push to `dev`. Each reads a `latest.json` published as
|
||||
//! an asset on a release whose TAG NEVER CHANGES — verified necessary, because
|
||||
//! Forgejo has no `/releases/latest/download/<asset>` route (it 404s), so "newest"
|
||||
//! cannot be named in a URL. A fixed tag can.
|
||||
//!
|
||||
//! `stable` followed tagged `v*` releases until M314 step 3, and its manifest pointed
|
||||
//! at bundles living on a different release. It holds its own bundles now, exactly as
|
||||
//! `dev` always has — so a build reaches stable users with no tag cut anywhere, which
|
||||
//! is the whole point of the change. NOTHING HERE MOVED: this code only ever read
|
||||
//! `<channel>/latest.json`, and that is still where the manifest lands.
|
||||
//!
|
||||
//! The feed lives on Fabled-Git rather than on a ThoughtSync server, deliberately:
|
||||
//! this app is usable having never linked a server, and an install that can't reach
|
||||
|
||||
Reference in New Issue
Block a user