fix(app-store): handle orphaned stack directories on template deploy (#530)

* fix(app-store): handle orphaned stack directories on template deploy

When a stack deployed via the App Store is later removed through Docker
Desktop or the CLI (instead of through Sencho), its directory remains on
disk without a compose file. The deploy endpoint previously rejected any
re-deploy with a 409 if the directory existed, even if empty.

Now the endpoint checks for a compose file before rejecting. If the
directory exists but contains no compose file, it is treated as an
orphaned remnant: cleaned up automatically and the deploy proceeds.

Also makes FileSystemService.hasComposeFile public so the deploy
endpoint can reuse it instead of duplicating the compose file check.

* docs(app-store): document orphaned stack directory cleanup behavior
This commit is contained in:
Anso
2026-04-12 19:26:29 -04:00
committed by GitHub
parent 36f2e8a7bc
commit 5f91e16417
3 changed files with 14 additions and 5 deletions
+11 -4
View File
@@ -5687,10 +5687,17 @@ app.post('/api/templates/deploy', authMiddleware, async (req: Request, res: Resp
try {
await fsPromises.access(stackPath);
return res.status(409).json({
error: `A stack directory named '${stackName}' already exists. Please choose a different Stack Name.`,
rolledBack: false
});
if (await fsService.hasComposeFile(stackPath)) {
return res.status(409).json({
error: `A stack directory named '${stackName}' already exists. Please choose a different Stack Name.`,
rolledBack: false
});
}
// Orphaned directory left by external deletion (e.g. Docker Desktop).
console.log(`[Templates] Cleaned up orphaned stack directory: ${stackName}`);
await fsService.deleteStack(stackName);
} catch {
// Directory does not exist; proceed with deploy
}
+1 -1
View File
@@ -34,7 +34,7 @@ export class FileSystemService {
return new FileSystemService(nodeId);
}
private async hasComposeFile(dir: string): Promise<boolean> {
async hasComposeFile(dir: string): Promise<boolean> {
const composeFiles = ['compose.yaml', 'compose.yml', 'docker-compose.yaml', 'docker-compose.yml'];
for (const file of composeFiles) {
try {
+2
View File
@@ -74,6 +74,8 @@ Below the template variables, an **Add Custom Variable** section lets you define
A toast notification confirms success or shows the error message. Large images may take a few minutes to pull.
If a previous stack with the same name was removed outside of Sencho (for example, through the Docker CLI or Docker Desktop), the leftover directory is cleaned up automatically and the deploy proceeds as normal.
<Note>
Deploying a template requires the `stack:create` permission. Users without this permission will see the Deploy button disabled.
</Note>