Skip to content

Commit 99ea24b

Browse files
finswimmerabn
authored andcommitted
feat: add confirmation step
1 parent 0b12771 commit 99ea24b

File tree

3 files changed

+75
-26
lines changed

3 files changed

+75
-26
lines changed

src/poetry/config/config_source.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,32 +39,46 @@ class ConfigSourceMigration:
3939
new_key: str | None
4040
value_migration: dict[Any, Any] = dataclasses.field(default_factory=dict)
4141

42-
def apply(self, config_source: ConfigSource, io: IO | None = None) -> None:
42+
def dry_run(self, config_source: ConfigSource, io: IO | None = None) -> bool:
4343
io = io or NullIO()
4444

4545
try:
4646
old_value = config_source.get_property(self.old_key)
4747
except PropertyNotFoundError:
48-
return
48+
return False
4949

5050
new_value = (
5151
self.value_migration[old_value] if self.value_migration else old_value
5252
)
5353

54-
config_source.remove_property(self.old_key)
55-
5654
msg = f"<c1>{self.old_key}</c1> = <c2>{json.dumps(old_value)}</c2>"
5755

5856
if self.new_key is not None and new_value is not UNSET:
5957
msg += f" -> <c1>{self.new_key}</c1> = <c2>{json.dumps(new_value)}</c2>"
60-
config_source.add_property(self.new_key, new_value)
6158
elif self.new_key is None:
6259
msg += " -> <c1>Removed from config</c1>"
6360
elif self.new_key and new_value is UNSET:
6461
msg += f" -> <c1>{self.new_key}</c1> = <c2>Not explicit set</c2>"
6562

6663
io.write_line(msg)
6764

65+
return True
66+
67+
def apply(self, config_source: ConfigSource) -> None:
68+
try:
69+
old_value = config_source.get_property(self.old_key)
70+
except PropertyNotFoundError:
71+
return
72+
73+
new_value = (
74+
self.value_migration[old_value] if self.value_migration else old_value
75+
)
76+
77+
config_source.remove_property(self.old_key)
78+
79+
if self.new_key is not None and new_value is not UNSET:
80+
config_source.add_property(self.new_key, new_value)
81+
6882

6983
def drop_empty_config_category(
7084
keys: list[str], config: dict[Any, Any]

src/poetry/console/commands/config.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -357,9 +357,22 @@ def _migrate(self) -> None:
357357

358358
config_source = FileConfigSource(config_file)
359359

360-
self.io.write_line("Starting config migration ...")
360+
self.io.write_line("Checking for required migrations ...")
361361

362-
for migration in CONFIG_MIGRATIONS:
363-
migration.apply(config_source, io=self.io)
362+
required_migrations = [
363+
migration
364+
for migration in CONFIG_MIGRATIONS
365+
if migration.dry_run(config_source, io=self.io)
366+
]
364367

365-
self.io.write_line("Config migration successfully done.")
368+
if not required_migrations:
369+
self.io.write_line("Already up to date.")
370+
return
371+
372+
if not self.io.is_interactive() or self.confirm(
373+
"Proceed with migration?: ", False
374+
):
375+
for migration in required_migrations:
376+
migration.apply(config_source)
377+
378+
self.io.write_line("Config migration successfully done.")

tests/console/commands/test_config.py

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -569,32 +569,54 @@ def test_config_solver_lazy_wheel(
569569
assert not repo._lazy_wheel
570570

571571

572+
current_config = """\
573+
[experimental]
574+
system-git-client = true
575+
576+
[virtualenvs]
577+
prefer-active-python = false
578+
"""
579+
580+
config_migrated = """\
581+
system-git-client = true
582+
583+
[virtualenvs]
584+
use-poetry-python = true
585+
"""
586+
587+
588+
@pytest.mark.parametrize(
589+
["proceed", "expected_config"],
590+
[
591+
("yes", config_migrated),
592+
("no", current_config),
593+
],
594+
)
572595
def test_config_migrate(
573-
tester: CommandTester, mocker: MockerFixture, tmp_path: Path
596+
proceed: str,
597+
expected_config: str,
598+
tester: CommandTester,
599+
mocker: MockerFixture,
600+
tmp_path: Path,
574601
) -> None:
575602
config_dir = tmp_path / "config"
576603
mocker.patch("poetry.locations.CONFIG_DIR", config_dir)
577604

578605
config_file = Path(config_dir / "config.toml")
579-
config_data = textwrap.dedent("""\
580-
[experimental]
581-
system-git-client = true
582-
583-
[virtualenvs]
584-
prefer-active-python = false
585-
""")
586606
with config_file.open("w") as fh:
587-
fh.write(config_data)
588-
589-
tester.execute("--migrate")
607+
fh.write(current_config)
590608

591-
expected_config = textwrap.dedent("""\
592-
system-git-client = true
609+
tester.execute("--migrate", inputs=proceed)
593610

594-
[virtualenvs]
595-
use-poetry-python = true
611+
expected_output = textwrap.dedent("""\
612+
Checking for required migrations ...
613+
experimental.system-git-client = true -> system-git-client = true
614+
virtualenvs.prefer-active-python = false -> virtualenvs.use-poetry-python = true
596615
""")
597616

617+
output = tester.io.fetch_output()
618+
assert output.startswith(expected_output)
619+
598620
with config_file.open("r") as fh:
599621
assert fh.read() == expected_config
600622

@@ -612,7 +634,7 @@ def test_config_migrate_local_config(tester: CommandTester, poetry: Poetry) -> N
612634
with local_config.open("w") as fh:
613635
fh.write(config_data)
614636

615-
tester.execute("--migrate --local")
637+
tester.execute("--migrate --local", inputs="yes")
616638

617639
expected_config = textwrap.dedent("""\
618640
system-git-client = true
@@ -629,4 +651,4 @@ def test_config_migrate_local_config_should_raise_if_not_found(
629651
tester: CommandTester,
630652
) -> None:
631653
with pytest.raises(RuntimeError, match="No local config file found"):
632-
tester.execute("--migrate --local")
654+
tester.execute("--migrate --local", inputs="yes")

0 commit comments

Comments
 (0)