chore: move desktop packages to packages.healthchat.ch

This commit is contained in:
2026-07-29 22:28:43 +02:00
parent 675e812f00
commit ab295d810c
5 changed files with 51 additions and 26 deletions
+10 -7
View File
@@ -29,8 +29,10 @@ Releases are driven by git tags of the form `healthchat-v<semver>` pushed to
**does not publish them**. See "Deploying the desktop release" below.
- `.github/workflows/deploy-healthchat-desktop.yaml` (desktop deploy) — **manual
dispatch only.** Downloads that tarball and mirrors it to
`https://healthchat.ch/packages/desktop/` over FTPS (the private GitHub Release can
serve neither end users nor the auto-updater). This is what makes installed apps
`https://packages.healthchat.ch/desktop/` over FTPS (the private GitHub Release can
serve neither end users nor the auto-updater), plus the legacy
`https://healthchat.ch/packages/desktop/` path while clients built <= 1.5.0 are still
in the field. This is what makes installed apps
self-update; see `apps/desktop/element.io/healthchat/README` for the feed layout and
the two caveats (first install is manual; Windows auto-update needs the Setup.exe path,
not the .msi).
@@ -185,7 +187,7 @@ run or `:latest` had not moved yet.
## Deploying the desktop release
The desktop build attaches `healthchat-desktop-feed-<version>.tar.gz` to the Release but
leaves `https://healthchat.ch/packages/desktop/` untouched. Until you run this, installed
leaves `https://packages.healthchat.ch/desktop/` untouched. Until you run this, installed
apps keep whatever version they have and the public download links still serve the old
installers.
@@ -321,7 +323,7 @@ warning. Prefer fixing the changelog over relying on the fallback.
"* Setup*.exe") **plus** `healthchat-desktop-feed-<version>.tar.gz`. Without that
tarball the desktop deploy has nothing to publish.
- [ ] Confirm the live feed is still on the **previous** version — releasing must not have
moved it. `curl -fsS https://healthchat.ch/packages/desktop/update/macos/releases.json`
moved it. `curl -fsS https://packages.healthchat.ch/desktop/update/macos/releases.json`
- [ ] Smoke-check signing before shipping to users: macOS `spctl -a -vvv -t install <app>`
is accepted; Windows installer shows a valid publisher (no SmartScreen block).
@@ -332,9 +334,10 @@ release"):
- [ ] Web deployed and `curl -fsS https://app.healthchat.ch/version` reports the new version.
- [ ] Desktop feed deployed: the "Deploy HealthChat Desktop" run is green. Its own verify
step already asserts the five feed URLs return 200, so a green run is the check.
step already asserts the feed URLs (canonical + legacy) return 200, so a green run is
the check.
- [ ] `releases.json` now advertises the new version:
`curl -fsS https://healthchat.ch/packages/desktop/update/macos/releases.json | jq -r '.releases[0].updateTo.version'`
`curl -fsS https://packages.healthchat.ch/desktop/update/macos/releases.json | jq -r '.releases[0].updateTo.version'`
- [ ] Spot-check auto-update on a real installed client (or at least confirm the app's
update check reaches the feed) before announcing.
@@ -346,7 +349,7 @@ Configured in repo Settings → Secrets and variables → Actions:
|---|---|
| `HEALTHCHAT_WORKSPACE_TOKEN` | PAT with read access to `Novaloop-AG/healthchat-workspace`. Needed by `actions/checkout` for the private plugin repo. |
| `GITHUB_TOKEN` | Auto-provided. Used for ghcr.io login and GitHub Release creation. No manual setup required. |
| `FTP_SERVER` / `FTP_USERNAME` / `FTP_PASSWORD` | Credentials for the healthchat.ch FTP(S) account. Used **only** by `deploy-healthchat-desktop.yaml` to publish the update feed + public installers under `/public_html/healthchat.ch/packages/desktop/`. `FTP_SERVER` is the hostname only (explicit FTPS / AUTH TLS). The release workflows never touch FTP, so a missing/expired credential breaks the deploy but never the release. |
| `FTP_SERVER` / `FTP_USERNAME` / `FTP_PASSWORD` | Credentials for the healthchat.ch FTP(S) account. Used **only** by `deploy-healthchat-desktop.yaml` to publish the update feed + public installers under `/public_html/packages/desktop/` (docroot of packages.healthchat.ch) plus, during the URL migration, the legacy `/public_html/healthchat.ch/packages/desktop/`. `FTP_SERVER` is the hostname only (explicit FTPS / AUTH TLS). The release workflows never touch FTP, so a missing/expired credential breaks the deploy but never the release. |
Desktop signing additionally requires two GitHub **environments** (Settings →
Environments). Without them the desktop builds still run but produce
@@ -11,7 +11,7 @@ name: Build HealthChat Desktop
#
# Notes:
# - This workflow RELEASES but does not DEPLOY. It attaches the installers and a staged update-feed
# tarball to the GitHub Release; the live auto-update feed at healthchat.ch/packages/desktop/ is
# tarball to the GitHub Release; the live auto-update feed at packages.healthchat.ch/desktop/ is
# only touched by the manually dispatched deploy-healthchat-desktop.yaml. So cutting a tag never
# pushes an update to already-installed apps until a human decides to ship it.
# - The reusable build workflows are pointed at THIS fork (repository/ref inputs) so the Electron
@@ -195,10 +195,10 @@ jobs:
targets: "dmg zip"
# Generates dist/releases.json (the Squirrel.Mac feed manifest). The reusable appends
# `/update/macos/<zip>` to this, so the in-manifest URL becomes
# https://healthchat.ch/packages/desktop/update/macos/<zip>, matching where the
# https://packages.healthchat.ch/desktop/update/macos/<zip>, matching where the
# `release` job publishes the feed. Keep in sync with update_base_url in
# element.io/healthchat/config.json (.../packages/desktop/update/).
base-url: https://healthchat.ch/packages/desktop
# element.io/healthchat/config.json (.../desktop/update/).
base-url: https://packages.healthchat.ch/desktop
windows:
name: Windows ${{ matrix.arch }}
@@ -273,7 +273,7 @@ jobs:
gh release upload "$TAG" release-files/* --clobber
# The GitHub Release above is private (internal fork), so it can't serve end users or the
# Squirrel auto-updater. Those are served from healthchat.ch/packages/desktop/, which is
# Squirrel auto-updater. Those are served from packages.healthchat.ch/desktop/, which is
# published by the SEPARATE, MANUALLY DISPATCHED "Deploy HealthChat Desktop" workflow
# (deploy-healthchat-desktop.yaml) — releasing never touches the live update feed.
# This job only *stages* that feed and attaches it to the Release as a tarball, so the
@@ -1,13 +1,13 @@
name: Deploy HealthChat Desktop
# Publishes an already-released desktop build to healthchat.ch/packages/desktop/ over FTPS.
# Publishes an already-released desktop build to packages.healthchat.ch/desktop/ over FTPS.
#
# This is the DEPLOY half of the desktop pipeline, deliberately split from the release half
# (build-healthchat-desktop.yaml). Cutting a `healthchat-v*` tag builds, signs and attaches the
# installers plus a staged update-feed tarball to the GitHub Release, but never touches the live
# feed. Nothing reaches installed apps until this workflow is dispatched by hand.
#
# Why that split matters: the feed under .../packages/desktop/update/ is what the Squirrel
# Why that split matters: the feed under .../desktop/update/ is what the Squirrel
# auto-updater polls. Writing to it pushes an update to every installed client, so it is a
# deployment, not a publication step — the same reason the ansible playbook's deploy is a manual
# dispatch rather than a release trigger.
@@ -38,7 +38,7 @@ concurrency:
jobs:
deploy:
name: Publish update feed to healthchat.ch
name: Publish update feed to packages.healthchat.ch
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
@@ -126,11 +126,21 @@ jobs:
# *.nupkg are preserved (Squirrel.Windows delta history) and only the staged files
# are written/overwritten. If the host's FTPS cert is untrusted, set
# ssl:verify-certificate to no.
#
# Dual-publish during the URL migration: /public_html/packages is the docroot of
# packages.healthchat.ch (the canonical feed URL since builds > 1.5.0), while
# /public_html/healthchat.ch/packages/desktop serves the legacy
# healthchat.ch/packages/desktop URL that clients built <= 1.5.0 still poll —
# they only learn the new URL by installing an update delivered over the old
# feed. Drop the legacy mirror (and its verify checks below) once the installed
# base is on a build carrying the new update_base_url.
lftp -u "$FTP_USERNAME" --env-password "$FTP_SERVER" <<LFTP
set cmd:fail-exit true
set ftp:ssl-force true
set ftp:ssl-protect-data true
set ssl:verify-certificate true
mkdir -pf /public_html/packages/desktop
mirror -R $MIRROR_OPTS feed/ /public_html/packages/desktop/
mkdir -pf /public_html/healthchat.ch/packages/desktop
mirror -R $MIRROR_OPTS feed/ /public_html/healthchat.ch/packages/desktop/
bye
@@ -140,13 +150,19 @@ jobs:
if: ${{ !inputs.dry_run }}
run: |
set -euo pipefail
base="https://healthchat.ch/packages/desktop"
base="https://packages.healthchat.ch/desktop"
# The legacy healthchat.ch URLs keep clients built <= 1.5.0 updating; drop them
# together with the legacy mirror above once the installed base has migrated.
legacy="https://healthchat.ch/packages/desktop"
fail=0
for url in "$base/update/macos/releases.json" \
"$base/update/win32/x64/RELEASES" \
"$base/update/win32/arm64/RELEASES" \
"$base/install/macos/HealthChat.dmg" \
"$base/install/win32/x64/HealthChat-Setup.exe"; do
"$base/install/win32/x64/HealthChat-Setup.exe" \
"$legacy/update/macos/releases.json" \
"$legacy/update/win32/x64/RELEASES" \
"$legacy/update/win32/arm64/RELEASES"; do
code=$(curl -fsS -o /dev/null -w '%{http_code}' -I "$url" 2>/dev/null || echo "000")
if [[ "$code" == "200" ]]; then echo "ok $code $url"; else echo "FAIL $code $url"; fail=1; fi
done
+14 -8
View File
@@ -98,14 +98,14 @@ runs can reach the signing credentials.
Auto-update + public installer hosting
--------------------------------------
The apps self-update over a feed hosted on healthchat.ch (the GitHub Release is private to this
internal fork, so it can serve neither end users nor the Squirrel auto-updater). Both the update
feed and the public installers live under https://healthchat.ch/packages/desktop/ (FTP web root
/public_html/healthchat.ch maps to https://healthchat.ch/; no packages. subdomain, so it's a path):
The apps self-update over a feed hosted on packages.healthchat.ch (the GitHub Release is private
to this internal fork, so it can serve neither end users nor the Squirrel auto-updater). Both the
update feed and the public installers live under https://packages.healthchat.ch/desktop/ (the
subdomain's docroot on the healthchat.ch FTP account is /public_html/packages):
update/ the Squirrel feed the installed apps poll hourly. config.json sets
"update_base_url": "https://healthchat.ch/packages/desktop/update/"
and the macos job passes base-url: https://healthchat.ch/packages/desktop so the
"update_base_url": "https://packages.healthchat.ch/desktop/update/"
and the macos job passes base-url: https://packages.healthchat.ch/desktop so the
generated releases.json points the *-mac.zip at this origin.
update/macos/releases.json + HealthChat-<ver>-mac.zip (Squirrel.Mac)
update/win32/<arch>/RELEASES + HealthChat-<ver>-full.nupkg (Squirrel.Windows; x64 + arm64)
@@ -113,14 +113,20 @@ feed and the public installers live under https://healthchat.ch/packages/desktop
install/macos/HealthChat-<ver>.dmg + HealthChat.dmg (stable "latest")
install/win32/<arch>/HealthChat-Setup-<ver>.exe + HealthChat-Setup.exe (stable) + *.msi
The `release` job in build-healthchat-desktop.yaml stages these trees and uploads them via lftp/FTPS
(mirror -R, no-delete so prior nupkgs survive for delta history). Add these repo secrets:
The `release` job in build-healthchat-desktop.yaml stages these trees; the manually dispatched
deploy-healthchat-desktop.yaml uploads them via lftp/FTPS (mirror -R, no-delete so prior nupkgs
survive for delta history). Add these repo secrets:
FTP_SERVER hostname only (explicit FTPS / AUTH TLS on port 21; if the host cert is untrusted,
flip ssl:verify-certificate to no in the workflow)
FTP_USERNAME
FTP_PASSWORD
Caveats:
- URL migration: builds <= 1.5.0 poll the legacy feed at
https://healthchat.ch/packages/desktop/ (docroot /public_html/healthchat.ch/packages/) —
they only learn the new URL by installing an update delivered over that old feed. The
deploy workflow therefore dual-publishes to both directories; drop the legacy mirror and
its verify checks once the installed base is on a build carrying the new update_base_url.
- First install is manual. Apps already installed without update_base_url (<= 1.1.2) cannot
self-update to the first build that carries it; users must download once from the install/ URL.
Every release after that updates automatically.
@@ -88,7 +88,7 @@
]
},
"show_labs_settings": false,
"update_base_url": "https://healthchat.ch/packages/desktop/update/",
"update_base_url": "https://packages.healthchat.ch/desktop/update/",
"modules": ["/modules/healthchat-module.js"],
"ch.healthchat": { "api_base_url": "https://api.healthchat.ch", "elements_base_url": "/webapp/modules/elements" }
}