Repository navigation
Carry on past a failed app, and report what actually made it - #10
Merged
Merged
Conversation
An update over 30 apps died at [1/30]: audiobookshelf couldn't start (a bind-mount path the daemon couldn't reach), run_step returned non-zero, and `set -e` took the whole run down with it. The other 29 apps were never touched, no summary was printed, and the only clue was "Command finished with errors (exit 1)". Per-app steps are now guarded rather than left to `set -e`. A failure is reported where it happens and the run carries on to the next app; enter_app returns instead of exiting so a missing or unusable folder is skipped the same way. A backup whose archive fails now starts the app again rather than leaving it stopped, and drops the partial archive. Every run closes with a tally of what actually made it - "Updated 27 of 30 apps in 3m 4s - 1 failed, 2 skipped" - followed by the names in each bucket, with the per-app table marking failed and skipped rows. The command exits non-zero when either bucket is non-empty so cron and wrapper scripts can tell without parsing output, and the webhook carries the same tally. Where a failure has a recognisable cause, a [hint] line now says what to do about it: an image with no build for this architecture, a bind-mount path docker can't reach, a port already allocated, an image or tag that doesn't exist, a full disk, or a *folder* named compose.yaml shadowing the real compose file. Unrecognised failures get no hint - the command's own output stays the source of truth. Also fixes run_step silently swallowing failures without a terminal: it returned 0 unconditionally in that path, so under cron a failed step was never labelled and the run died with only docker's raw output. Co-Authored-By: Claude Opus 5 <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.
The bug
An
updateacross 30 apps died at app 1 of 30:run_stepreturned non-zero,set -etook the whole run down, and the other 29 apps were never touched. No summary was printed, and "Command finished with errors (exit 1)" was the only account of what happened — no sign of what had been updated, or how many apps succeeded versus failed.What changed
One bad app no longer ends the run. Per-app steps are guarded explicitly rather than left to
set -e: a failure is reported where it happens and the run carries on to the next app.enter_appreturns instead of exiting, so a missing or unusable folder is skipped the same way. Abackupwhose archive fails now starts the app back up rather than leaving it stopped, and drops the partial archive.Every run says what actually made it. The per-app table marks failed and skipped rows, and the run closes with a plain tally:
skippedmeans the app was left untouched (its pull failed, so it stays on the image it has);failedmeans the command was attempted and didn't work. The command exits non-zero when either bucket is non-empty, so cron and wrapper scripts can tell without parsing output, and the webhook carries the same tally.Hints for the usual docker failures. Where the cause is recognisable, a
[hint]line says what to do about it. All three failures from the original run now explain themselves:Also covered: a port already allocated, an image or tag that doesn't exist or is private, and a full disk. Unrecognised failures get no hint — the command's own output stays the source of truth.
Bug found along the way
Without a terminal (cron, pipes)
run_stepreturned0unconditionally, so a failed step was never labelled as one and the run died with only docker's raw output as a clue. That path now captures, reports and propagates failures the same way the terminal path does.Verification
End-to-end runs against a stub
dockerreproducing the exact failure mix from the report — 10 apps, two failing their pull (compose-file-is-a-directory, architecture mismatch), two failing to start (bind-mount permission, port conflict):Updated 6 of 10 apps - 2 failed, 2 skipped, and exits 1.Started all 3 apps in 0s.and exit 0; single-app runs read correctly (Started 1 app,Started 0 of 1 app - 1 failed).--dry-rununaffected.Each of the above under Debian
dash, with and without a pty.shellcheckclean (via the CI's own image),sh -nanddash -npass.🤖 Generated with Claude Code