From 85135c99ce9731d38b64caf59834fdf3c2f0ecc5 Mon Sep 17 00:00:00 2001 From: Romamo Date: Fri, 2 Oct 2026 11:54:55 +0300 Subject: [PATCH] fix: migrate resolves --env-file and --data paths against the project The argparse CLI ran migrate inside the project directory, so a relative env file or source URL file meant one there. The treaty port resolved them against the current directory instead. Found rewriting the LedgrAI deployment runbook for the new CLI. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015MJdwagp7FxuuxminHgv2V --- CHANGELOG.md | 3 +++ sdk/src/cloudfall/app.py | 5 +++-- sdk/tests/test_app.py | 23 ++++++++++++++++++++++- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f84c6cf..5d8f064 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -194,6 +194,9 @@ Notable changes to Cloudfall. The format follows ### Fixed +- `migrate --env-file NAME=PATH` and `--data NAME=PATH` resolve a relative + path against the project again, as every other path does; since the + move to treaty they resolved against the current directory - `migrate --build` and the `cloudfall-mcp` `build_artifact` tool read the release from the engine's treaty envelope, under `data`. Since the engine moved to treaty every build step failed with "artifact builder returned no diff --git a/sdk/src/cloudfall/app.py b/sdk/src/cloudfall/app.py index 6634477..5f0475d 100644 --- a/sdk/src/cloudfall/app.py +++ b/sdk/src/cloudfall/app.py @@ -2078,12 +2078,13 @@ def options(self, fleet: Fleet) -> MigrateOptions: plan_file=fleet.path(self.plan_file), builds=_pairs(self.build, "build"), releases=_pairs(self.release, "release"), + # Relative to the project, as every other path here is. environment_files={ - component: Path(value) + component: fleet.path(Path(value)) for component, value in _pairs(self.env_file, "env-file").items() }, data_migrations={ - database: Path(value) + database: fleet.path(Path(value)) for database, value in _pairs(self.data, "data").items() }, execute=self.yes, diff --git a/sdk/tests/test_app.py b/sdk/tests/test_app.py index 80d6915..272c30a 100644 --- a/sdk/tests/test_app.py +++ b/sdk/tests/test_app.py @@ -7,13 +7,16 @@ from pathlib import Path import pytest -from cloudfall.app import app +from cloudfall.app import Fleet, MigrateArgs, app from cloudfall.cli import main from cloudfall.commands import CLI_COMMANDS +from cloudfall.resources import default_schema_directory +from cloudfall.validation import validate_config ROOT = Path(__file__).parents[2] EXAMPLES = ROOT / "config" / "examples" COMPLIANT = ROOT / "config" / "tests" / "observed" / "compliant" +SCHEMAS = default_schema_directory() def test_the_contract_marks_exactly_the_commands_treaty_runs() -> None: @@ -84,3 +87,21 @@ def test_a_drift_report_keeps_the_order_the_checks_ran_in( report = json.loads(capsys.readouterr().out)["data"] assert code == 83 assert report["servers"][0]["checks"][0]["check"] == "server_type.id" + + +def test_migrate_resolves_env_and_data_files_against_the_project( + tmp_path: Path, +) -> None: + """The argparse CLI ran migrate inside the project; relative paths meant it.""" + fleet = Fleet(EXAMPLES, validate_config(EXAMPLES, SCHEMAS)) + args = MigrateArgs( + env_file=("crm-backend=tmp/env/crm.env",), + data=(f"crm={tmp_path / 'source.url'}",), + ) + + options = args.options(fleet) + + assert options.environment_files == { + "crm-backend": EXAMPLES / "tmp/env/crm.env" + } + assert options.data_migrations == {"crm": tmp_path / "source.url"}