Skip to content

Commit 879e87c

Browse files
committed
fix(installer): skip destructive compose ops when compose file is missing
Remove/Purge/FactoryReset failed with "file does not exist" for stacks that were never extracted (no docker-compose-*.yml). Now such stacks are skipped instead of aborting the whole operation. - Add composeFileExists check before destructive compose commands - Add isDestructiveComposeOperation helper
1 parent dc83cb6 commit 879e87c

1 file changed

Lines changed: 32 additions & 0 deletions

File tree

backend/cmd/installer/processor/compose.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,22 @@ func (c *composeOperationsImpl) performStackOperation(
8686
) error {
8787
switch stack {
8888
case ProductStackPentagi:
89+
// destructive operations cannot run without the compose file and have
90+
// nothing to act on when the stack was never extracted
91+
if isDestructiveComposeOperation(operation) && !c.composeFileExists(stack) {
92+
return nil
93+
}
8994
return c.wrapPerformStackCommand(ctx, stack, state, operation, args...)
9095

9196
case ProductStackLangfuse, ProductStackObservability, ProductStackGraphiti:
9297
switch operation {
9398
// for destructive operations we must always allow compose to run, even if stack is disabled/external now
9499
case ProcessorOperationRemove, ProcessorOperationPurge, ProcessorOperationStop:
100+
// but only if the compose file exists; a missing file means the stack
101+
// was never extracted and there is nothing for compose to remove
102+
if !c.composeFileExists(stack) {
103+
return nil
104+
}
95105
return c.wrapPerformStackCommand(ctx, stack, state, operation, args...)
96106
// for non-destructive operations (start/update/download) honor embedded mode only
97107
default:
@@ -163,6 +173,28 @@ func (c *composeOperationsImpl) performStackCommand(
163173
return c.processor.runCommand(cmd, stack, state)
164174
}
165175

176+
// isDestructiveComposeOperation reports whether the operation tears a stack down
177+
// (and therefore may target a stack that is disabled/external/never extracted)
178+
func isDestructiveComposeOperation(operation ProcessorOperation) bool {
179+
switch operation {
180+
case ProcessorOperationRemove, ProcessorOperationPurge, ProcessorOperationStop:
181+
return true
182+
default:
183+
return false
184+
}
185+
}
186+
187+
// composeFileExists reports whether the stack's compose file is present on disk;
188+
// destructive operations cannot run (and have nothing to remove) without it
189+
func (c *composeOperationsImpl) composeFileExists(stack ProductStack) bool {
190+
composeFile, err := c.determineComposeFile(stack)
191+
if err != nil {
192+
return false
193+
}
194+
composePath := filepath.Join(filepath.Dir(c.processor.state.GetEnvPath()), composeFile)
195+
return c.processor.isFileExists(composePath) == nil
196+
}
197+
166198
func (c *composeOperationsImpl) determineComposeFile(stack ProductStack) (string, error) {
167199
switch stack {
168200
case ProductStackPentagi:

0 commit comments

Comments
 (0)