feat: add release notifications and interactive updates - #468
Merged
nieomylnieja merged 38 commits intoSep 24, 2026
Merged
Conversation
Show a cached TTY notification after successful commands when a newer sloctl release includes feature updates. Add coverage for notifier behavior and CLI execution flow, including end-to-end notification tests.
…ew-version-notifications
Detect how sloctl was installed so notifications can suggest the right upgrade command for Homebrew, `go install`, or the install script fallback.
Show notifications for releases without feature entries and include bug-fix sections when extracting release notes. Refresh the plain-text styling and wrap long install commands to fit narrower terminals.
Run update notifications before command execution and let users upgrade, skip, or defer until the next version. Replace the GitHub proxy tests with deterministic TTY fixtures and a local release fixture server.
Detect MinGW and Cygwin before showing the interactive update form. Fall back to notification-only behavior for unsupported Windows shells.
Recognize Cygwin and MinGW terminals while suppressing the update form in native Windows consoles. Add platform Bats coverage for Linux, macOS Homebrew installs, and Windows.
…ew-version-notifications
Use semantic version ordering, preserve prompt interruption, and execute detected updater commands safely. Expand release-note and CLI regression coverage, and align test documentation and CI configuration.
Detect Homebrew and Go installations reliably, persist skip preferences safely, and add installation guidance for unsupported setups. Extend notification tests and PTY helpers for update flows and timeout handling.
Render release notices and update actions from an embedded template for consistent formatting.
Keep Windows release notifications noninteractive to avoid legacy terminal hangs and add coverage for feature highlights.
ditrytus
requested changes
Sep 22, 2026
nieomylnieja
added this pull request to stack #555
September 22, 2026 21:04
ditrytus
approved these changes
Sep 23, 2026
…ew-version-notifications
nieomylnieja
deleted the
add-new-feature-and-new-version-notifications
branch
September 24, 2026 10:37
nieomylnieja
added a commit
that referenced
this pull request
Sep 24, 2026
) ## Motivation `make test/bats/platform` fails on macOS before any test runs: ```text Could not find library 'bats-support' relative to test file or in BATS_LIB_PATH ``` The target runs Bats natively, and CI passes only because `bats-action` installs Bats and its libraries and exports `BATS_LIB_PATH`. Nothing documents that setup for local runs. `docs/DEVELOPMENT.md` also does not list the other tools the Makefile expects, like Node.js, Docker or jq. ## Summary ### Platform tests in Docker | Target | Before | After | |---|---|---| | `test/bats/platform` | Native, needs Bats on the host | Docker, `platform:unix` tests in the Bats unit image | | `test/bats/platform-native` | - | Native, the previous `test/bats/platform` recipe | | CI notification jobs | `make test/bats/platform` | `make test/bats/platform-native` | | `test/bats/unit` | Excludes platform tests | Unchanged | - `test/bats/platform` works like the other Bats targets, so local runs need no Bats on the host. The `platform:macos` tests are also tagged `platform:unix`, so they run in the container too. The two `platform:windows` tests run only natively on Windows. - CI keeps the native runs, because the macOS and Windows runners cannot run the Linux image. - The tests chose the sloctl binary by tag, so platform tests expected the host binary from `make build`, which the image does not have. They now check for a container instead, the same check `setup_file` already used. Native runs keep using the host binary. ### Docs - New prerequisites list in `docs/DEVELOPMENT.md`: Go, git, Node.js and Yarn 1.x, Docker and jq, each mapped to the targets that need it. - New "Platform compatibility tests" section: `test/bats/platform` runs in Docker, and `test/bats/platform-native` is the native CI run. - Documents that the e2e tests read missing `SLOCTL_*` credentials from the current sloctl context. - Clarifies that `yarn` dependencies are also installed automatically, into `node_modules`. ### Install script tests `install-script.bats` expected `linux amd64` in the installed binary's version output. On arm64 hosts, like Apple Silicon Macs, the container installs the `linux-arm64` release and both install tests failed. The tests now derive the expected architecture from `uname -m`. ### `make check` on macOS - `unparam` failed with `resolveEditor - goOS always receives "darwin"` because `runtime.GOOS` is a constant and the tests only passed the host OS or `"darwin"`. CI lints on Linux, so it did not catch this. `TestResolveEditor` now also checks the Windows default editor. - Replaced the deprecated gofumpt `extra-rules` setting with `extra.group-params`, which removes the warning from every lint run. ## Related changes - Stacked on #468, which adds the native platform tests. - #545 on `main` makes the Go docker e2e test read credentials from the current sloctl context, so this PR does not change that test. ## Testing | Scenario | Result | |---|---| | `make test/bats/platform` on an arm64 Mac | 16 tests pass in Docker | | `make test/bats/unit` on an arm64 Mac | 82 tests pass, including install script tests | | `BATS_LIB_PATH=<libs> make test/bats/platform-native` with bats on `PATH`, as in CI | 16 tests pass with the host binary | | `make check` on macOS | Pass, no lint issues or warnings | `unit-tests.yml` runs only for pull requests into `main`, so the renamed CI target first runs on #468 once this PR is merged into it. --------- Co-authored-by: Mateusz Hawrus <mateusz.hawrus@nobl9.com> Co-authored-by: Mateusz Hawrus <48822818+nieomylnieja@users.noreply.github.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Help users keep sloctl up to date without letting optional release notifications or failed updates stop the requested command.
Summary
brewthrough PATH and checks that it owns the running executable.Testing
Results and screenshots
The screenshots show actual terminal output from a
v1.0.0build and a localv1.1.0release fixture. The Linux and macOS prompt captures include the theme fix in7a44da8; the other captures usef27e9ec. These checks need no Nobl9 credentials.Linux: light background, default Skip
Linux: dark background, readable update choices
Linux: failed Go update, original command recovered
Windows: notice and command completion without input
macOS: light background, default Skip
macOS: dark background, readable update choices
macOS: unrecognized installation, notice without input
macOS: failed Go update, original command recovered
Automated coverage
Manual testing: Linux laptop
Run these steps directly on your Linux laptop. This path needs no VM or container.
Manual setup
Check out this PR. Open two interactive Bash terminals in the repository root.
Use Go 1.26.6 or newer, Git, GNU Make, and Python 3 in both terminals. On NixOS, run this in each terminal:
Keep stdin and stderr attached to the terminal when running sloctl.
In terminal 1, start the local release server and leave it running:
In terminal 2, install the PR binary into a temporary Go installation directory:
This keeps the test binary and notification cache separate from your normal installation. Keep this terminal open for the checks below.
Manual checks
Run these commands in terminal 2.
Go installation and default Skip:
Expect the release highlights, release link, and three choices. Update names
go install github.com/nobl9/sloctl/cmd/sloctl@latest. Press Enter for Skip. Expect version output and exit status 0. Repeat on light and dark terminal backgrounds. All choices must remain readable.Unrecognized installation:
Expect identical highlights and a release link, with no choices or input required. Expect version output and exit status 0.
Failed update recovery:
Keep port 1 unused. Select Update. Expect a connection error, the original version output, and exit status 0.
Run
reset_noticebefore each additional check, except where the table says to retain state:eval "$("$installed" completion bash)", thencomplete -p sloctl. Expect a registered completion function without a notice or prompt."$installed" versionand select Skip. Expect version output and exit 0.reset_notice. Expect only the version."$cache_dir/notifications.json"and rerun. The same release stays hidden. In terminal 1, stop the server and restart it withRELEASE_SERVER_TAG=v1.2.0 RELEASE_SERVER_HTML_URL=https://github.com/nobl9/sloctl/releases/tag/v1.2.0 python3 test/inputs/notifications/release_server.py "$(mktemp)" 38080. Remove only the timestamp file and rerun. Expect the new notice.SLOCTL_ACCESSIBLE_MODE=1 "$installed" version. Expect numbered choices with Skip as the default. Enter or bare Ctrl+D skips, prints the version, and exits 0. On a fresh run, enterx, then2. Expect a validation message, another prompt, then version output and exit 0."$installed" version. Expect the version and exit 0.RELEASE_SERVER_RAW_RESPONSE='{' python3 test/inputs/notifications/release_server.py "$(mktemp)" 38080. Reset and run sloctl. Expect the version and exit 0. Restore the normal server afterward.SLOCTL_NO_NOTIFICATIONS=1 "$installed" version, thenCI=1 "$installed" version. Expect only the version in both cases.make installcommand above before further checks.For Homebrew, use the optional Homebrew check before cleanup.
Cleanup: stop the server with Ctrl+C in terminal 1. In terminal 2, run
rm -rf "$sloctl_test_dir", then close that test shell.Manual testing: Windows with Dockur
Manual setup
On the Linux host, install Podman and meet the Dockur Windows requirements. Start the VM:
Open
http://127.0.0.1:18006on the host. Let Windows install and complete setup with a local test account.Inside Windows, install Go 1.26.6 or newer and MSYS2. In MSYS2, run
pacman -S --needed git make python. Check out this PR inside the guest.Open two MSYS2 terminals from guest PowerShell using the command below. Run it twice. This selects mintty with ConPTY disabled and preserves the Windows PATH:
In both MSYS2 terminals, enter the repository root. Confirm that
go env GOOSprintswindows.In guest terminal 1, start the local release server:
In guest terminal 2, build the Windows executable:
Manual checks
In guest terminal 2, run:
Expect the highlights, release link, version output, and exit status 0. Windows must finish without choices or input, including for this Go installation.
Reset and repeat with
SLOCTL_ACCESSIBLE_MODE=1 "$installed" version. Expect the same behavior.Launch another mintty window with
--pcon oninstead of--pcon off. Repeat guest terminal 2 setup and check 1 in that window.Run
cygpath -w "$installed"to get the executable's full Windows path. In PowerShell, run& '<full Windows path>' version. In Command Prompt, run"<full Windows path>" version. Replace the placeholder with the printed path. Reset the notice from MSYS2 before each run. Expect the same notice and exit 0 without input.Stop the server, reset, and rerun. Expect only the version and exit 0. Repeat with
RELEASE_SERVER_RAW_RESPONSE='{' python3 test/inputs/notifications/release_server.py "$(mktemp)" 38080in guest terminal 1.Restore the normal server. After separate resets, run
SLOCTL_NO_NOTIFICATIONS=1 "$installed" versionandCI=1 "$installed" version. Expect only the version.Cleanup: stop the guest fixture, run
reset_notice, and close the guest shells. On the host, runpodman stop sloctl-windows-reviewandpodman rm sloctl-windows-review. The disk remains in$windows_vm_dir/storage.Manual testing: macOS with Dockur
Manual setup
On the Linux host, install Podman and meet the Dockur macOS requirements. Start the VM:
These VM settings were exercised on Intel hardware. On AMD hosts, change
CPU_CORES=4toCPU_CORES=1before starting the container.Open
http://127.0.0.1:18007on the host. Use Disk Utility to format the new 64 GiB virtual disk as APFS. Select Reinstall macOS and complete setup with a local test account.Inside macOS, install Go 1.26.6 or newer, Git, GNU Make, and Python 3. Check out this PR inside the guest.
Open two Terminal windows in the repository root. Run
bashin each window.In guest terminal 1, start the local release server:
In guest terminal 2, install the PR binary into a temporary Go installation directory:
Manual checks
Run these commands in guest terminal 2.
Go installation and default Skip:
Expect the highlights, release link, and three choices. Press Enter for Skip. Expect version output and exit status 0.
Unrecognized installation:
Expect identical highlights, with no choices or input required, then version output and exit status 0.
Failed update recovery:
Keep port 1 unused. Select Update. Expect a connection error, the original version output, and exit status 0.
Run
reset_noticebefore each additional check, except where the table says to retain state:eval "$("$installed" completion bash)", thencomplete -p sloctl. Expect a registered completion function without a notice or prompt."$installed" versionand select Skip. Expect version output and exit 0.reset_notice. Expect only the version."$cache_dir/notifications.json"and rerun. The same release stays hidden. In guest terminal 1, stop the server and restart it withRELEASE_SERVER_TAG=v1.2.0 RELEASE_SERVER_HTML_URL=https://github.com/nobl9/sloctl/releases/tag/v1.2.0 python3 test/inputs/notifications/release_server.py "$(mktemp)" 38080. Remove only the timestamp file and rerun. Expect the new notice.SLOCTL_ACCESSIBLE_MODE=1 "$installed" version. Expect numbered choices with Skip as the default. Enter or bare Ctrl+D skips, prints the version, and exits 0. On a fresh run, enterx, then2. Expect a validation message, another prompt, then version output and exit 0."$installed" version. Expect the version and exit 0.RELEASE_SERVER_RAW_RESPONSE='{' python3 test/inputs/notifications/release_server.py "$(mktemp)" 38080. Reset and run sloctl. Expect the version and exit 0. Restore the normal server afterward.SLOCTL_NO_NOTIFICATIONS=1 "$installed" version, thenCI=1 "$installed" version. Expect only the version in both cases.make installcommand above before further checks.For Homebrew, use the optional Homebrew check before cleanup.
Cleanup: stop the guest fixture, run
reset_notice, and close the guest shells. On the host, runpodman stop sloctl-macos-reviewandpodman rm sloctl-macos-review. The disk remains in$macos_vm_dir/storage.Homebrew check on Linux or macOS
The real Homebrew upgrade remains unrun locally. The official installer exited 1 in the Intel macOS guest with
Homebrew on macOS is only supported on Apple Silicon processors!. The automated suite checks Homebrew command selection and failure recovery with a stub.Run this optional check in a disposable Homebrew installation before platform cleanup. Install sloctl as described in the README. Use the PR binary and shell variables from that platform's setup:
Expect the same notice and choices, with
brew upgrade sloctlas the update command. Check Skip, then reset and select Update. On success, expect exit 0 without the original version output. Restore the packaged binary withbrew reinstall sloctl.Release Notes
Added release notices with inline highlights and update choices for recognized Homebrew and Go installations on Linux and macOS. Windows displays release information without an update prompt. Fetch, cache, and updater failures let the requested command continue.