Skip to content

[Feature] Add fail-closed migration for legacy runtime project identities #140

Description

@dswegart

Summary

Please add a fail-closed migration path that preserves the effective Docker Compose
project identity of stacks imported from the original dcflachs/compose_plugin when
that identity differs from the sanitized project-folder name.

This is a follow-up to #48, not a request to revert the new folder-name/display-name
model for newly created Plus stacks.

Detailed description

Compatibility gap

The original manager used the legacy per-stack name file as the value supplied to
docker compose -p:

Plus now intentionally derives projectName from the sanitized folder name and treats
name as display metadata:

  • // projectFolder is the directory name as-is; projectName is the sanitized
    // version used for the Docker Compose -p flag. We never rename the folder.
    $this->projectName = self::sanitizeProjectString($this->projectFolder);
    // Resolve display name from metadata (or default to folder name).
    $this->displayName = $this->getDisplayName();
  • $result = [
    'projectName' => $this->projectName,
    'files' => $files,
    'envFile' => $envFile,
    'projectDirectory' => $this->composeSource,
    'useDefaultFileDiscovery' => $useDefaultDiscovery,
    ];

The bulk status lookup also joins live com.docker.compose.project labels using that
folder-derived identity:

  • // Extract project name from Labels string
    $labels = $ct['Labels'] ?? '';
    if (preg_match('/com\.docker\.compose\.project=([^,]+)/', $labels, $m)) {
    $containersByProject[$m[1]][] = $ct;
    }
    }
    }
    foreach ($stacks as $stack) {
    $key = $stack->projectName;
    $stack->setContainerList($containersByProject[$key] ?? []);

The current beta (v2026.08.23.2252, commit
220dd98bc125c717c0c798959fbf018ebcc56565) still follows the same identity rule.

That design is internally consistent for new Plus stacks, but it changes the runtime
identity of some stacks imported from the original manager. Stopping the old project
before upgrading avoids a simultaneous duplicate, but starting it under a different
-p value still creates a new Compose project identity and can change generated
network, container, and resource names.

Minimal reproduction

  1. In the original manager, create a project folder such as legacy-folder.
  2. Set its legacy name file to legacy_runtime.
  3. Start it and confirm its containers have
    com.docker.compose.project=legacy_runtime.
  4. Upgrade to Plus without issuing a stack action.
  5. Plus resolves the stack as project legacy-folder, so the existing
    legacy_runtime containers are not associated with the row.
  6. An up, down, pull, update, autostart, or shutdown action is then scoped to
    the folder-derived identity rather than the existing runtime project.

Requested behavior

Please add an explicit legacy migration mechanism rather than silently changing identity.
One possible design:

  1. During migration, calculate both the sanitized folder candidate and the sanitized
    legacy name-file candidate.
  2. Compare both with existing com.docker.compose.project labels from
    docker ps -a.
  3. If exactly one candidate owns the existing containers, preserve it as the effective
    runtime identity and persist it in dedicated metadata such as project_name;
    continue using name only as the display name.
  4. If both or neither candidate can be proven, display an identity-mismatch warning and
    disable mutating actions until the owner explicitly selects an identity.
  5. Use the resolved identity consistently for status, up, down, stop,
    pull, update, auto-update, autostart, shutdown, logs, and cache/lock keys.
  6. Offer a read-only migration preview showing folder, display name, effective runtime
    project, live-container match, and whether owner input is required.

I am not attached to the metadata filename or UI shape. The important properties are
preserving existing identity when it can be proven and refusing mutations when it
cannot.

Suggested acceptance criteria

  • A legacy stack whose folder, display name, and runtime project name are all different
    remains associated with its existing running or stopped containers after migration.
  • Merely installing Plus performs no Compose project action and creates no parallel
    project identity.
  • Every action path uses one centralized, persisted effective project identity.
  • An ambiguous or conflicting identity fails closed before invoking Docker Compose.
  • Regression tests cover:
    • legacy name different from folder;
    • running and stopped containers;
    • both candidate identities present;
    • neither candidate present;
    • new Plus-created stacks retaining the current folder-derived behavior.

This would make the README's migration promise safer for long-lived installations while
preserving Plus's canonical folder-name model for new stacks.

Alternatives considered

  1. Stop/down all stacks, then let Plus recreate them under folder-derived names.
    This avoids two simultaneously running identities but still changes project identity,
    generated resources, and recovery expectations.
  2. Rename/redeploy every mismatched project before upgrading. This works but turns a
    management-UI replacement into many workload migrations, each requiring its own
    downtime, dependency testing, and rollback.
  3. Continue using the archived original manager. This is the current safe workaround,
    but it leaves users on deprecated UI code and prevents adoption of Plus improvements.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions