mirror of
https://github.com/Novaloop-AG/healthchat-web.git
synced 2026-10-31 08:15:07 +00:00
Merge pull request #5 from Novaloop-AG/feat/desktop-auto-update
feat(desktop): wire up HealthChat auto-update + public installer hosting
This commit is contained in:
@@ -18,7 +18,12 @@ Releases are driven by git tags of the form `healthchat-v<semver>` pushed to
|
||||
workflows create-if-missing then upload, so they race safely. (Linux is intentionally
|
||||
not built — the upstream Linux reusable pulls a build-env Docker image keyed by commit
|
||||
SHA that only exists in the upstream element-hq registry, so it cannot succeed in this
|
||||
fork.)
|
||||
fork.) The `release` job additionally **mirrors the Squirrel update feed and the public
|
||||
installers 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 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).
|
||||
|
||||
Publish target: **ghcr.io Docker image + GitHub Release (web bundle + desktop
|
||||
installers).** No npm, no mobile fan-out.
|
||||
@@ -165,6 +170,11 @@ warning. Prefer fixing the changelog over relying on the fallback.
|
||||
- [ ] The desktop workflow run ("Build HealthChat Desktop") is green and the
|
||||
GitHub Release has the desktop installers attached (.dmg, *-mac.zip, *.msi,
|
||||
"* Setup*.exe").
|
||||
- [ ] The update feed + installers published to healthchat.ch: `curl -fsI`
|
||||
`https://healthchat.ch/packages/desktop/update/macos/releases.json`,
|
||||
`.../update/win32/x64/RELEASES`, and the public installer URLs
|
||||
`.../install/macos/HealthChat.dmg` / `.../install/win32/x64/HealthChat-Setup.exe`
|
||||
all return 200.
|
||||
- [ ] Smoke-check signing: macOS `spctl -a -vvv -t install <app>` is accepted;
|
||||
Windows installer shows a valid publisher (no SmartScreen block).
|
||||
|
||||
@@ -176,6 +186,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. The desktop `release` job uses them to publish the update feed + public installers under `/public_html/healthchat.ch/packages/desktop/`. `FTP_SERVER` is the hostname only (explicit FTPS / AUTH TLS). Without them the FTP publish step fails (but the GitHub Release still gets the installers). |
|
||||
|
||||
Desktop signing additionally requires two GitHub **environments** (Settings →
|
||||
Environments). Without them the desktop builds still run but produce
|
||||
|
||||
@@ -189,6 +189,12 @@ jobs:
|
||||
sign: true
|
||||
test: false
|
||||
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
|
||||
# `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
|
||||
|
||||
windows:
|
||||
name: Windows ${{ matrix.arch }}
|
||||
@@ -255,3 +261,64 @@ jobs:
|
||||
gh release view "$TAG" >/dev/null 2>&1 || \
|
||||
gh release create "$TAG" --title "$TAG" --notes "HealthChat desktop installers for $TAG"
|
||||
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. Mirror the update feed + public installers to healthchat.ch over
|
||||
# FTPS so installed apps self-update (update_base_url -> .../packages/desktop/update/) and
|
||||
# users can download from a public URL (.../packages/desktop/install/).
|
||||
- name: Stage update feed + public installers
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# --- macOS update feed: releases.json (Squirrel.Mac manifest) + signed *-mac.zip payload ---
|
||||
mkdir -p feed/update/macos feed/install/macos
|
||||
test -f dist-artifacts/macos/releases.json || {
|
||||
echo "::error::dist-artifacts/macos/releases.json missing (did the macos job get base-url?)"; exit 1; }
|
||||
cp -v dist-artifacts/macos/releases.json feed/update/macos/
|
||||
find dist-artifacts/macos -type f -iname '*-mac.zip' -exec cp -v {} feed/update/macos/ \;
|
||||
# --- macOS installer: versioned .dmg + a stable "latest" copy ---
|
||||
find dist-artifacts/macos -type f -iname '*.dmg' -exec cp -v {} feed/install/macos/ \;
|
||||
dmg=$(find feed/install/macos -type f -iname '*.dmg' | head -n1)
|
||||
test -n "$dmg" && cp -v "$dmg" feed/install/macos/HealthChat.dmg
|
||||
# --- Windows: per-arch Squirrel feed (RELEASES + full nupkg) + installers (Setup.exe, msi) ---
|
||||
for arch in x64 arm64; do
|
||||
src="dist-artifacts/win-$arch"
|
||||
[ -d "$src" ] || { echo "::error::$src missing"; exit 1; }
|
||||
mkdir -p "feed/update/win32/$arch" "feed/install/win32/$arch"
|
||||
find "$src" -type f -iname 'RELEASES' -exec cp -v {} "feed/update/win32/$arch/" \;
|
||||
find "$src" -type f -iname '*-full.nupkg' -exec cp -v {} "feed/update/win32/$arch/" \;
|
||||
find "$src" -type f -iname '* Setup*.exe' -exec cp -v {} "feed/install/win32/$arch/" \;
|
||||
find "$src" -type f -iname '*.msi' -exec cp -v {} "feed/install/win32/$arch/" \;
|
||||
setup=$(find "feed/install/win32/$arch" -type f -iname '* Setup*.exe' | head -n1)
|
||||
test -n "$setup" && cp -v "$setup" "feed/install/win32/$arch/HealthChat-Setup.exe"
|
||||
done
|
||||
echo "--- staged feed tree ---"
|
||||
find feed -type f | sort
|
||||
|
||||
- name: Install lftp
|
||||
run: sudo apt-get update && sudo apt-get install -y lftp
|
||||
|
||||
- name: Publish to healthchat.ch over FTPS
|
||||
env:
|
||||
FTP_SERVER: ${{ secrets.FTP_SERVER }}
|
||||
FTP_USERNAME: ${{ secrets.FTP_USERNAME }}
|
||||
# Passed to lftp via LFTP_PASSWORD (--env-password) so it never appears on the
|
||||
# command line / process list.
|
||||
LFTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
: "${FTP_SERVER:?FTP_SERVER secret not set}"
|
||||
: "${FTP_USERNAME:?FTP_USERNAME secret not set}"
|
||||
: "${LFTP_PASSWORD:?FTP_PASSWORD secret not set}"
|
||||
# mirror -R (reverse) uploads the local tree; default is no-delete, so prior
|
||||
# *.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.
|
||||
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/healthchat.ch/packages/desktop
|
||||
mirror -R --parallel=4 --verbose feed/ /public_html/healthchat.ch/packages/desktop/
|
||||
bye
|
||||
LFTP
|
||||
|
||||
@@ -8,6 +8,7 @@ permissions: {}
|
||||
|
||||
jobs:
|
||||
doc:
|
||||
if: ${{ github.repository == 'element-hq/element-web' }}
|
||||
name: Build storybook
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
@@ -90,6 +90,38 @@ Without these the jobs still build but produce unsigned/untrusted output. Becaus
|
||||
a public-history fork, add environment/branch protection so only release/healthchat + healthchat-v*
|
||||
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):
|
||||
|
||||
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
|
||||
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)
|
||||
install/ public downloads for the FIRST install (users get these URLs, not the GitHub Release):
|
||||
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:
|
||||
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:
|
||||
- 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.
|
||||
- Windows auto-update only works for the Squirrel Setup.exe install path, NOT the per-machine
|
||||
.msi (the updater needs Squirrel's Update.exe, which the MSI doesn't install). Hand users the
|
||||
Setup.exe as the primary Windows installer. macOS: install the .dmg into /Applications.
|
||||
|
||||
Open items
|
||||
----------
|
||||
- api_base_url: confirm the production API origin in config.json (currently assumed
|
||||
@@ -99,5 +131,3 @@ Open items
|
||||
rewrites any `version` override into a nightly string), NOT the healthchat-v tag. Bump
|
||||
apps/desktop/package.json in the release commit if you want the About dialog / installer
|
||||
filenames to match the tag.
|
||||
- Auto-update: not wired up. The apps install from the GitHub Release but do not self-update.
|
||||
Adding it needs a hosted update feed (releases.json / RELEASES) on a stable URL.
|
||||
|
||||
@@ -96,6 +96,7 @@
|
||||
]
|
||||
},
|
||||
"show_labs_settings": false,
|
||||
"update_base_url": "https://healthchat.ch/packages/desktop/update/",
|
||||
"modules": ["/modules/healthchat-module.js"],
|
||||
"ch.healthchat": {
|
||||
"api_base_url": "https://healthchat.ch",
|
||||
|
||||
Reference in New Issue
Block a user