Skip to content

fix: support custom canonical compose filenames#2285

Merged
kmendell merged 1 commit intomainfrom
fix/custom-compose-file-names
Apr 9, 2026
Merged

fix: support custom canonical compose filenames#2285
kmendell merged 1 commit intomainfrom
fix/custom-compose-file-names

Conversation

@kmendell
Copy link
Copy Markdown
Member

@kmendell kmendell commented Apr 8, 2026

Checklist

  • This PR is not opened from my fork’s main branch

What This PR Implements

Fixes:

Changes Made

Testing Done

  • Development environment started: ./scripts/development/dev.sh start
  • Frontend verified at http://localhost:3000
  • Backend verified at http://localhost:3552
  • Manual testing completed (describe):
  • No linting errors (e.g., just lint all)
  • Backend tests pass: just test backend

AI Tool Used (if applicable)

AI Tool:
Assistance Level:
What AI helped with:
I reviewed and edited all AI-generated output:
I ran all required tests and manually verified changes:

Additional Context

Disclaimer Greptiles Reviews use AI, make sure to check over its work.

To better help train Greptile on our codebase, if the comment is useful and valid Like the comment, if its not helpful or invalid Dislike

To have Greptile Re-Review the changes, mention greptileai.

Greptile Summary

This PR adds support for custom canonical compose filenames (e.g. radarr.yaml, sonarr.yaml) by extending DetectComposeFile with a priority-tiered detection strategy (dir-name match → stem contains "compose" → single valid YAML) and adding HasComposeRootKeysInFile to validate candidates by checking for top-level services or include keys. It also introduces RemoveStaleComposeFiles and DirectorySyncContentsChanged to keep the GitOps directory sync path clean when the canonical compose filename changes.

Confidence Score: 5/5

Safe to merge — the core detection and cleanup logic is correct and well-tested; remaining findings are P2 quality improvements.

All P0/P1 concerns from the prior review have been addressed: unexported functions now carry the Internal suffix, and non-compose YAML files are filtered via HasComposeRootKeysInFile before being returned as compose candidates. The two new findings are P2: a missed-redeploy edge case when switching between custom filenames (files are still written correctly) and a missing debug log for unreadable candidate files. Neither blocks correct behavior.

backend/pkg/projects/fs_util.go — the stale-custom-compose detection gap in DirectorySyncContentsChanged is worth a follow-up.

Vulnerabilities

No security concerns identified. The new file-reading logic (HasComposeRootKeysInFile) does not expose new attack surface — it reads files within already-validated project directories and parses them as YAML without executing any content.

Comments Outside Diff (1)

  1. backend/internal/services/gitops_sync_service.go, line 1578-1598 (link)

    P1 removeStaleComposeFilesInternal does not clean up stale custom compose filenames

    This function iterates only over projects.ComposeFileCandidates() (the six standard filenames). If a project's staged directory already contains a custom compose file (e.g. radarr.yaml from a previous sync whose SyncedFiles record has been lost or was never written), and the new sync also uses a different custom filename (e.g. sonarr.yaml), neither will match the standard candidates list — the old custom file will survive the cleanup. Later, DetectComposeFile will see two custom YAML files and return "multiple custom compose files found", breaking the sync.

    The function should also scan the staged directory for other custom YAML files that match IsProjectFile criteria, removing them when they are neither the current composeFileName nor a member of syncedFiles:

    entries, _ := os.ReadDir(projectPath)
    for _, entry := range entries {
        name := entry.Name()
        if name == composeFileName { continue }
        if _, exists := syncedFileSet[name]; exists { continue }
        if !IsProjectFile(name) { continue }
        _ = os.Remove(filepath.Join(projectPath, name))
    }
    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: backend/internal/services/gitops_sync_service.go
    Line: 1578-1598
    
    Comment:
    **`removeStaleComposeFilesInternal` does not clean up stale custom compose filenames**
    
    This function iterates only over `projects.ComposeFileCandidates()` (the six standard filenames). If a project's staged directory already contains a custom compose file (e.g. `radarr.yaml` from a previous sync whose `SyncedFiles` record has been lost or was never written), and the new sync also uses a different custom filename (e.g. `sonarr.yaml`), neither will match the standard candidates list — the old custom file will survive the cleanup. Later, `DetectComposeFile` will see two custom YAML files and return `"multiple custom compose files found"`, breaking the sync.
    
    The function should also scan the staged directory for other custom YAML files that match `IsProjectFile` criteria, removing them when they are neither the current `composeFileName` nor a member of `syncedFiles`:
    
    ```go
    entries, _ := os.ReadDir(projectPath)
    for _, entry := range entries {
        name := entry.Name()
        if name == composeFileName { continue }
        if _, exists := syncedFileSet[name]; exists { continue }
        if !IsProjectFile(name) { continue }
        _ = os.Remove(filepath.Join(projectPath, name))
    }
    ```
    
    How can I resolve this? If you propose a fix, please make it concise.

    Fix in Codex

Fix All in Codex

Prompt To Fix All With AI
This is a comment left during a code review.
Path: backend/pkg/projects/fs_util.go
Line: 297-309

Comment:
**Stale custom compose files not detected by `DirectorySyncContentsChanged`**

The third loop only checks `ComposeFileCandidates()` (the fixed list of standard names). If the live project directory contains a stale *custom* compose file (e.g. `sonarr.yaml` left over from a previous sync configuration), it won't set `contentsChanged = true`. This means a transition from one custom filename to another won't trigger a redeploy when the project is running — the files will still be written and cleaned up correctly via `RemoveStaleComposeFiles`, but the caller in `performDirectorySync` skips `redeployIfRunningAfterSync` when `contentsChanged` is false.

Consider scanning for extra custom compose files the same way `RemoveStaleComposeFiles` does, or simply returning `true` whenever `RemoveStaleComposeFiles` would find at least one file to delete.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: backend/pkg/projects/load.go
Line: 100-107

Comment:
**Unreadable file silently promoted to candidate**

When `HasComposeRootKeysInFile` returns an error (permission denied, I/O error, etc.) and the file is `dirMatched` or `composeNamed`, it's still added to the candidate lists without any log. If the file is subsequently returned as the compose path and fails to load, the error from `LoadComposeProject` will obscure the earlier I/O problem.

Consider logging the `rootKeysErr` at debug level:
```go
} else {
    slog.DebugContext(context.Background(), "could not check compose root keys, using name heuristic",
        "path", candidatePath, "error", rootKeysErr)
}
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (2): Last reviewed commit: "fix: support custom canonical compose fi..." | Re-trigger Greptile

@kmendell kmendell marked this pull request as ready for review April 8, 2026 22:20
@kmendell kmendell requested a review from a team April 8, 2026 22:20
@kmendell
Copy link
Copy Markdown
Member Author

kmendell commented Apr 8, 2026

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

Copy link
Copy Markdown
Member Author

kmendell commented Apr 8, 2026

This stack of pull requests is managed by Graphite. Learn more about stacking.

@getarcaneappbot
Copy link
Copy Markdown
Contributor

getarcaneappbot commented Apr 8, 2026

Container images for this PR have been built successfully!

  • Manager: ghcr.io/getarcaneapp/arcane:pr-2285
  • Agent: ghcr.io/getarcaneapp/arcane-headless:pr-2285

Built from commit 3f1ad02

Comment thread backend/pkg/projects/load.go Outdated
Comment thread backend/pkg/projects/load.go
@kmendell kmendell force-pushed the fix/custom-compose-file-names branch from f277219 to 6cbca98 Compare April 8, 2026 22:26
@kmendell kmendell force-pushed the fix/custom-compose-file-names branch from 6cbca98 to 3f1ad02 Compare April 8, 2026 22:59
@kmendell kmendell merged commit 8bd1650 into main Apr 9, 2026
25 checks passed
@kmendell kmendell deleted the fix/custom-compose-file-names branch April 9, 2026 01:01
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.

2 participants