fix: docsgpt up --adopt recreates every container

Compose keeps containers whose configuration did not change, so after a
takeover Redis and Postgres still carried the other folder's working
directory label, and the next `docsgpt up` asked for --adopt again.
This commit is contained in:
Alex committed 2026-09-15 23:11:32 +01:00
1 parent 0bd0afc1f8
commit c7af5f873a
2 files changed
+22 -6

No files matched your search

+11 -6
View File
@@ -130,17 +130,20 @@ def _current_provider(env: Mapping[str, str]) -> str:
return name if name in stack.PROVIDERS else "docsgpt"
def _check_other_stacks(args, context: Context, directory: Path) -> None:
def _check_other_stacks(args, context: Context, directory: Path) -> bool:
"""True when containers of the project were started from another folder and ``up`` takes them over."""
others = {path for path in context.docker.project_dirs(PROJECT) if path.resolve() != directory.resolve()}
if not others or args.adopt:
return
if not others:
return False
if args.adopt:
return True
where = ", ".join(sorted(str(path) for path in others))
question = (
f"Docker already runs a DocsGPT stack started from {where}; it uses the same data volumes. "
f"Manage it from {directory} instead?"
)
if context.interactive and context.prompter.confirm(question, default=False):
return
return True
raise DeployError(
f"Docker already runs a DocsGPT stack started from {where}. Stop it with `docker compose down` "
f"in that folder, or run again with --adopt to manage it from {directory}."
@@ -179,7 +182,9 @@ def up(args, context: Optional[Context] = None) -> int:
configured = record_path.is_file()
context.docker.preflight(context.interactive)
_check_other_stacks(args, context, directory)
# Compose keeps containers whose configuration did not change, and with them the other
# folder's working-directory label; recreating them all makes the takeover complete.
recreate = ["--force-recreate"] if _check_other_stacks(args, context, directory) else []
ask = context.interactive and (not configured or args.reconfigure)
expose, domain = args.expose, args.domain
@@ -214,7 +219,7 @@ def up(args, context: Optional[Context] = None) -> int:
if stack.exposure(existing) == "domain" and stack.exposure(env) != "domain":
# With the https profile off, `up --remove-orphans` would leave Caddy running on ports 80 and 443.
context.docker.compose(directory, *_EVERY_PROFILE, "rm", "--stop", "--force", "caddy", check=False)
up_args = ["up", "-d", "--remove-orphans"]
up_args = ["up", "-d", "--remove-orphans", *recreate]
if image_tag in _MOVING_TAGS:
up_args += ["--pull", "always"]
print(f"Starting DocsGPT {image_tag} from {directory} ...")
+11
View File
@@ -185,6 +185,17 @@ class TestUpAgain:
assert docker.calls == []
assert _run(["up", "--yes", "--adopt", "--dir", str(tmp_path)], _context(docker)) == 0
def test_adopting_recreates_every_container(self, tmp_path):
"""Compose keeps unchanged containers, and with them the old folder's label; the next up would ask again."""
docker = FakeDocker(project_dirs={"/srv/old-docsgpt"})
assert _run(["up", "--yes", "--adopt", "--dir", str(tmp_path)], _context(docker)) == 0
assert docker.calls == [(tmp_path, ["up", "-d", "--remove-orphans", "--force-recreate"])]
def test_containers_from_this_folder_are_not_recreated(self, tmp_path):
docker = FakeDocker(project_dirs={str(tmp_path)})
assert _run(["up", "--yes", "--dir", str(tmp_path)], _context(docker)) == 0
assert docker.calls == [(tmp_path, ["up", "-d", "--remove-orphans"])]
def test_consent_can_be_given_at_the_prompt(self, tmp_path):
docker = FakeDocker(project_dirs={"/srv/old-docsgpt"})
prompter = FakePrompter([True, "local", "docsgpt"])