Show a remote banner fetched from banner.json on main - #973
Conversation
The CLI fetches banner.json from the repo's main branch on every run and, when the message is non-empty and the semver constraint in "versions" matches the running build, prints it to stderr after the command finishes. The fetch is never awaited: whatever has not arrived by then is dropped, so no command gets slower. Non-interactive runs never see it. Editing banner.json on main is the whole publishing process, so notices such as "upgrade via brew" reach installed CLIs without a release or an auto-updater.
|
Demo: banner-sync.mp4 |
One entry per notice, each with its own versions constraint, so a new-feature announcement for old builds can sit next to an upgrade notice without either having to be removed first.
Every --json flag binds to a shared jsonOutput destination so the banner, which prints after the command returns, can tell a --json run apart from an interactive one and keep stderr clean for downstream parsers.
This reverts commit b9e5001.
Status puts it on stderr and honors --quiet; the border sets it apart from the command's own output.
Printing before the command means the notice cannot wait on the network, so each run shows the banner.json cached at ~/.livekit/banner.json by the run before it and refreshes that cache in the background. A notice lands one run after it is published; no command gets slower.
The fetch is awaited with a 1s timeout and the file is cached for an hour, so only the first run each hour pays the round trip. Non-interactive runs skip the fetch entirely.
The cache is {data, downloadedAt}; a refetch happens once downloadedAt is
over an hour old. Sync tools and backups that rewrite mtime no longer force
a refetch or hide a stale file.
…time" This reverts commit 4daab13.
There was a problem hiding this comment.
This looks great, small nits mainly. My one question is whether there will ever be other conditions besides just your lk version that might want to trigger a banner? A specific command for example might want to provide usage tips that aren't dependent on version, but aren't appropriate to show at all times.
| // The banner prints before the command, so the fetch is awaited. To keep that off | ||
| // most runs, the fetched file is cached and reused for bannerTTL. | ||
| const ( | ||
| bannerTimeout = time.Second |
There was a problem hiding this comment.
Is this enough time for remote locations / mobile hotspot / etc?
| BorderForeground(util.Warning()). | ||
| Padding(0, 1). | ||
| Width(76) | ||
| out.Statusf("%s\n", fence.Render(strings.Join(msgs, "\n\n"))) |
There was a problem hiding this comment.
Maybe put a separator between message?
| continue | ||
| } | ||
| if b.Versions != "" { | ||
| c, err := semver.NewConstraint(b.Versions) |
There was a problem hiding this comment.
Nice, I was gonna check you were using this since we had it already
Why
We want to tell people running an installed
lkthings like "a new version is out, runbrew upgrade livekit-cli" or "livekit.toml layout changed" without shipping an auto-updater (decided against) and without waiting for them to update to see the notice.What
banner.jsonat the repo root, fetched frommainon every run. It is a list of notices, each with its own version selector:[ {"message": "lk agent simulate can now export runs. Upgrade: brew upgrade livekit-cli", "versions": "< 2.18.0"}, {"message": "lk 3.0 is out and moves the agent id to [cloud] in livekit.toml.", "versions": "< 3.0.0"} ]versionsis a semver constraint; empty matches every build. Every entry that matches prints, in file order, so a new-feature announcement for old builds can sit next to an upgrade notice. The committed file is[]. Editing the file onmainis the whole publishing process.out.Status, so it honors--quietand never mixes with stdout. Only shown on an interactive terminal, so scripts and pipes are unaffected.~/.livekit/banner.jsonfor an hour, so only the first run each hour pays the round trip (~70-170ms to raw.githubusercontent.com). A failed fetch falls back to the stale cache. Non-interactive runs skip the fetch entirely.Verification
go build ./cmd/lk,go vet ./cmd/lk,go test ./cmd/lkpass. Demo video in a comment below.