Repository navigation
feat(badge): opt-in update badge around brew update/upgrade - #150
Merged
Merged
Conversation
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
…ract Pipe-separated counts from badge_counts so empty fields survive read -a. Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
EXIT trap owns lock release + size-capped refresh.log on every path; empty-outdated runs still write a fresh empty export; subcommand tokens never parse as package names; state dir auto-created before locking. Co-Authored-By: Claude <noreply@anthropic.com>
REFRESH_MODE initialized with the other mode flags and the refresh handler moved below full argument parsing so the parse default cannot clobber it. Co-Authored-By: Claude <noreply@anthropic.com>
The wrapper's failed >/dev/tty open printed shell noise when no controlling terminal exists; a brace group with its own 2>/dev/null swallows exactly that message. The init test's pty harness now picks BSD vs util-linux script(1) syntax — CI runs ubuntu-latest too. Co-Authored-By: Claude <noreply@anthropic.com>
Failed refreshes start a 30-min backoff window (configurable) during which the badge neither spawns nor prints a refresh suffix — the line never promises a refresh that is not happening. A network-dead refresh (zero fresh|cached-fresh retrievals) keeps a healthy export instead of clobbering it with forced-unknown records and exits 2 (backoff + log). Setup hint now points at -u, the flagship workflow. Co-Authored-By: Claude <noreply@anthropic.com>
One outdated package with every curl probe failing instantly (BREW_CHANGE_MAX_RETRIES=1 removes retry sleeps; a single package is a single batch, so no rate-limit sleep) runs the doomed evidence pass in under a second and exercises the full guard: healthy export kept, exit 2, rc=2 logged, backoff started, lock released. Co-Authored-By: Claude <noreply@anthropic.com>
The fixture kept a hardcoded generated_at while BREW_CHANGE_TEST_NOW tracked capture time, so the test only passed within ~1h of that UTC instant. Fixture and injected clock now derive from the same capture. Co-Authored-By: Claude <noreply@anthropic.com>
Users who added the eval line while PATH still resolved v1.20.1 got a shell-startup stall: the old pre-parse treats unknown words as package names, so 'init zsh' ran the changelog pipeline (and could block on a selection prompt) inside rc evaluation. init now emits __bc_bin=<absolute path of the emitting binary> and the wrapper invokes badge through it — immune to PATH drift, and checkout installs work before any release. Requirements note added to docs. Co-Authored-By: Claude <noreply@anthropic.com>
The badge pre-acquires the refresh lock and writes the spawned child's pid into it; the child then saw a lock 'held by a live process' — itself — and exited instantly. Every badge spawn produced a no-op child and a lingering lock: refresh never ran. Found live: badge said 'refreshing…' forever while the lock held a dead pid and refresh.log stayed empty. refresh_lock_acquire now adopts a lock whose pid equals its own; foreign live pids still block, dead/expired still take over. Co-Authored-By: Claude <noreply@anthropic.com>
Harness suites faked brew/curl but ran with the real HOME, so piped -u tests overwrote the user's ~/.brew-change/last-assessment.json with 3-package all-unknown fixture data — pre-existing since tasks-005, and user-visible once the badge started reading that file. setup_command_ harness now points HOME at a temp dir inside the harness root and teardown restores it. Co-Authored-By: Claude <noreply@anthropic.com>
The post-upgrade badge lands after the decision point — useless at the y/n. before-upgrade prints the cached verdict above brew's plan where the choice happens: no refresh, no suffix, decision support only. The post-upgrade badge keeps the settle-state and self-healing refresh. Co-Authored-By: Claude <noreply@anthropic.com>
Breaking red, no-signal green, unknown yellow, prefix and age dimmed — presentation only, the words carry the classification, NO_COLOR respected. The verdict is marked with Homebrew's own bold-green '==>' header style. An after-* verdict identical to the last printed one (same export, <10 min) repeats nothing: only the honest spawn tail or silence. before-upgrade always prints — decision support is never suppressed. Color and dedupe require a real TTY so FORCE runs stay deterministic. Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Three CI-ubuntu failures, none reproducible on macOS: - badge_export_stamp tried BSD stat -f first; GNU stat -f is a filesystem query that succeeds with drifting multi-line output, so stamps never matched and duplicate suppression never fired. GNU -c first now (macOS -c errors into the -f fallback). - the export-subcommand test needs brew on PATH for verify_dependencies; CI ubuntu runners have no Homebrew. Minimal brew shim added. - the order test used BSD script syntax only; util-linux needs -c. Same case-split as the wrapper pty harness.
Owner
Author
✅ PR MergedMerged to: SummaryOpt-in update badge for brew-change: a one-line risk verdict around Changes
Issues ResolvedNone (no linked issues) 🤖 Generated by Claude Code - GLM 5.3 Flash |
2 tasks done
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.
Summary
eval "$(brew-change init zsh)"prints a one-line risk verdict from the cached assessment after everybrew update/brew upgrade— counts, breaking packages (red), no-signal (green), unknown (yellow), age — under Homebrew's own==>header style. Brew's exit status passes through untouched;NO_COLORrespected; silent in pipes.before-upgradetrigger: read-only verdict above brew's plan, where they/ndecision actually happens.brew-change refresh: headless, lock-coalescing background re-run that keeps the export fresh (dead-PID/expiry takeover, 30-min failure backoff, degraded-run guard that never clobbers a healthy export with forced-unknown records, size-cappedrefresh.log). Also the future entry point for a LaunchAgent.brew-change init: emits the wrapper with the emitting binary's absolute path pinned (__bc_bin), so PATH drift cannot resolve an older brew-change that predates the subcommands.Design record:
docs/dev/prd-004-badge-integration.md(with live-testing addendum), plan indocs/dev/tasks-006-badge-integration.md, user guide indocs/badge-integration.md.Test Plan
brew update, spawn → adopt → refreshrc=0, settle-back, decline path, wrapper exit-code passthrough🤖 Generated by Claude Code - glm-5.3-flash