Skip to content

fix(override): prune services the compose file no longer has - #169

Merged
mstrhakr merged 2 commits into
mstrhakr:devfrom
grantemsley:fix/prune-orphan-override-services
Oct 6, 2026
Merged

mstrhakr merged 2 commits into
mstrhakr:devfrom
grantemsley:fix/prune-orphan-override-services

Conversation

@grantemsley

Copy link
Copy Markdown

What changed

pruneOrphanOverrideServices() runs before every Compose Up to drop override entries for services the
compose file no longer has. To find the valid services, getMainFileServices() runs
docker compose ... config --services, but the -f list it used included the managed override itself. An
entry for a removed or renamed service holds only labels and no image, so compose failed on it ("has neither
an image nor a build context"), the list came back empty, and nothing was ever pruned. The up that followed
then failed on the same entry.

The services are now listed without the managed override and without the icon override generated from it
(new private buildComposeFileFlagsWithoutManagedOverride()). Everything else in the file list stays: the
main compose file, an indirect stack's own override, and extra compose files from COMPOSE_FILE or the
stack settings, so their services still count as valid.

Related issues

#118 (the stack that wouldn't start after a service was removed; reproduction in my comment there)

Checklist

  • I have added/updated tests where applicable
  • I have updated documentation (docs/, README, or plugin docs): N/A nothing user-facing changes
  • Linted/formatted the code (PHPStan clean)
  • Verified on Unraid or CI

Testing notes

  • New tests/unit/PruneOrphanOverrideServicesTest.php: a stand-in docker on PATH that, like compose,
    fails when handed the override with an image-less entry. It fails before this change and passes after. Full
    PHPUnit suite passes.
  • On Unraid 7.3.2 with v2026.10.02.1007: with the reproduction from the issue, the stock Util.php returns
    {"changed":false,"removed":[]} and this branch's returns {"changed":true,"removed":["old"]}, with the
    entry gone from the override and the other one kept.

Notes

  • Stacks using default file discovery (use_default_compose_files) are unchanged: they pass no -f flags,
    so there is no file to leave out, and compose itself loads compose.override.yaml from the folder.

pruneOrphanOverrideServices() asks docker compose which services the main
compose file defines, so it can drop override entries for the rest. The
-f list it used included the managed override itself, so an entry for a
removed or renamed service (labels only, no image) made compose fail with
'has neither an image nor a build context', the list came back empty, and
nothing was ever pruned. The following up then failed on the same entry.

The services are now asked for without the managed override and the icon
override generated from it. Default file discovery mode is unchanged: it
passes no -f flags to leave one out of.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011iUWDG8wTp8MhsFDqNC4NL

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Default Compose file discovery still loads the managed override, leaving the reported failure unresolved in that supported mode.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

Fixes orphan-service pruning by excluding managed overrides when querying valid Compose services.

Changes:

  • Adds filtered Compose file flag construction.
  • Adds regression tests for pruning stale override entries.
File Description
source/​compose.manager/​include/​Util.php Excludes managed overrides during service discovery.
tests/​unit/​PruneOrphanOverrideServicesTest.php Tests stale-service pruning behavior.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread source/compose.manager/include/Util.php Outdated
With use_default_compose_files on, the services query ran with only
--project-directory, so compose found compose.override.yaml next to the
compose file by itself and refused the project over the orphan entry.
Pruning stayed off in that mode.

Name the files with -f in that mode as well, from the same project
directory, leaving out the managed override as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PnMScBowJk7yyfEwraTdgg
@mstrhakr
mstrhakr merged commit 322c8dd into mstrhakr:dev Oct 6, 2026
5 checks passed
mstrhakr pushed a commit that referenced this pull request Oct 8, 2026
… checks

The web UI prunes the plugin-managed override before every up; a git
deploy did not. When a commit renames or removes a service, the override
keeps an entry for it with labels only, and compose refuses the whole
stack over a file the user did not write. Prune it after the checkout and
before the checks, and log each service removed.

This relies on #169: before it, pruneOrphanOverrideServices() never
removed anything.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PnMScBowJk7yyfEwraTdgg
mstrhakr pushed a commit that referenced this pull request Oct 8, 2026
… checks

The web UI prunes the plugin-managed override before every up; a git
deploy did not. When a commit renames or removes a service, the override
keeps an entry for it with labels only, and compose refuses the whole
stack over a file the user did not write. Prune it after the checkout and
before the checks, and log each service removed.

This relies on #169: before it, pruneOrphanOverrideServices() never
removed anything.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PnMScBowJk7yyfEwraTdgg
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants