coily upgrade --dry exits non-zero when an upgrade is available #86

Open
opened 2026-05-26 04:10:18 +00:00 by coilysiren · 0 comments
Owner

Symptom

coily upgrade --dry exits non-zero (3, wrapping brew's exit 1) whenever an upgrade is available, which is the success case for a dry-run.

Repro

On a host where the installed coily is behind the formula:

$ coily upgrade --dry
==> brew outdated coilysiren/coily/coily
coilysiren/coily/coily (2.37.1) < 2.37.2
coily: exit status 1
error:
    kind: upstream_failed
    message: exit status 1
    exit_code: 3

Cause

runUpgrade in cmd/coily/upgrade.go shells out to brew outdated <formula> for the dry path. brew outdated exits 1 when the formula is outdated, 0 when current. coily propagates the exit code verbatim, so "there is an upgrade waiting" is reported as a verb failure.

Expected

coily upgrade --dry exits 0 when it successfully prints the version diff (whether or not anything is outdated), and only exits non-zero when brew itself failed to produce a diff (tap unreachable, formula unknown, etc.). The diff itself is the deliverable; whether the version moved is information, not a failure.

Fix sketch

In runUpgrade, when dry is set, treat brew outdated's exit 1 as a normal outcome. Either swallow exit 1 specifically, or use brew info --json / a comparison path that doesn't encode "outdated" as an error. Keep other brew failure modes as errors.

Context

Came up on Kai's Mac during a tap-remote swap from GitHub to Forgejo. Hit immediately after the swap when checking the upgrade was wired up correctly — the diff was correct, the exit code lied about it.

**Symptom** `coily upgrade --dry` exits non-zero (3, wrapping brew's exit 1) whenever an upgrade is available, which is the success case for a dry-run. **Repro** On a host where the installed coily is behind the formula: ``` $ coily upgrade --dry ==> brew outdated coilysiren/coily/coily coilysiren/coily/coily (2.37.1) < 2.37.2 coily: exit status 1 error: kind: upstream_failed message: exit status 1 exit_code: 3 ``` **Cause** `runUpgrade` in `cmd/coily/upgrade.go` shells out to `brew outdated <formula>` for the dry path. `brew outdated` exits 1 when the formula is outdated, 0 when current. coily propagates the exit code verbatim, so "there is an upgrade waiting" is reported as a verb failure. **Expected** `coily upgrade --dry` exits 0 when it successfully prints the version diff (whether or not anything is outdated), and only exits non-zero when brew itself failed to produce a diff (tap unreachable, formula unknown, etc.). The diff itself is the deliverable; whether the version moved is information, not a failure. **Fix sketch** In `runUpgrade`, when `dry` is set, treat `brew outdated`'s exit 1 as a normal outcome. Either swallow exit 1 specifically, or use `brew info --json` / a comparison path that doesn't encode "outdated" as an error. Keep other brew failure modes as errors. **Context** Came up on Kai's Mac during a tap-remote swap from GitHub to Forgejo. Hit immediately after the swap when checking the upgrade was wired up correctly — the diff was correct, the exit code lied about it.
coilysiren added
P4
and removed
P3
labels 2026-05-31 06:59:45 +00:00
Sign in to join this conversation.
No labels
P0
P1
P2
P3
P4
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-bridge/coily#86
No description provided.