From cf7e101b68780875a909bff4e38df8cf25a62a5c Mon Sep 17 00:00:00 2001 From: sergiochan Date: Tue, 10 Mar 2026 17:40:22 -0700 Subject: [PATCH 1/6] Fix publish --build behavior in non-interactive mode --- src/poetry/console/commands/publish.py | 10 +++++++--- tests/console/commands/test_publish.py | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/poetry/console/commands/publish.py b/src/poetry/console/commands/publish.py index 98c0bebe896..3927bffc2cb 100644 --- a/src/poetry/console/commands/publish.py +++ b/src/poetry/console/commands/publish.py @@ -72,9 +72,13 @@ def handle(self) -> int: # Building package first, if told if self.option("build"): - if publisher.files and not self.confirm( - f"There are {len(publisher.files)} files ready for" - " publishing. Build anyway?" + if ( + publisher.files + and self.io.is_interactive() + and not self.confirm( + f"There are {len(publisher.files)} files ready for" + " publishing. Build anyway?" + ) ): self.line_error("Aborted!") diff --git a/tests/console/commands/test_publish.py b/tests/console/commands/test_publish.py index 31723ac8ce3..1272483dd66 100644 --- a/tests/console/commands/test_publish.py +++ b/tests/console/commands/test_publish.py @@ -215,3 +215,18 @@ def test_publish_dist_dir_and_build_options( assert "Publishing simple-project (1.2.3) to PyPI" in output assert "- Uploading simple_project-1.2.3.tar.gz" in error assert "- Uploading simple_project-1.2.3-py2.py3-none-any.whl" in error + + +def test_publish_build_no_interaction_skips_confirmation( + app_tester: ApplicationTester, mocker: MockerFixture +) -> None: + confirm = mocker.patch("poetry.console.commands.publish.PublishCommand.confirm") + command_call = mocker.patch("poetry.console.commands.publish.PublishCommand.call") + publisher_publish = mocker.patch("poetry.publishing.Publisher.publish") + + exit_code = app_tester.execute("publish --build --no-interaction --dry-run") + + assert exit_code == 0 + confirm.assert_not_called() + command_call.assert_called_once_with("build", args="--output dist") + assert publisher_publish.call_count == 1 From 4b2728f900e07b6e975ccd7be23040255a0669c9 Mon Sep 17 00:00:00 2001 From: sergiochan Date: Tue, 10 Mar 2026 17:45:56 -0700 Subject: [PATCH 2/6] test(publish): force pre-existing dist artifacts in no-interaction case --- tests/console/commands/test_publish.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/console/commands/test_publish.py b/tests/console/commands/test_publish.py index 1272483dd66..7eccb50a03c 100644 --- a/tests/console/commands/test_publish.py +++ b/tests/console/commands/test_publish.py @@ -5,6 +5,7 @@ from pathlib import Path from typing import TYPE_CHECKING from typing import NoReturn +from unittest.mock import PropertyMock import pytest import requests @@ -220,6 +221,11 @@ def test_publish_dist_dir_and_build_options( def test_publish_build_no_interaction_skips_confirmation( app_tester: ApplicationTester, mocker: MockerFixture ) -> None: + mocker.patch( + "poetry.publishing.publisher.Publisher.files", + new_callable=PropertyMock, + return_value=[Path("dist/simple_project-1.2.3-py2.py3-none-any.whl")], + ) confirm = mocker.patch("poetry.console.commands.publish.PublishCommand.confirm") command_call = mocker.patch("poetry.console.commands.publish.PublishCommand.call") publisher_publish = mocker.patch("poetry.publishing.Publisher.publish") From 9c427b7522cb43ecbbbe62de0192ff8b1f4d9cd6 Mon Sep 17 00:00:00 2001 From: sergiochan Date: Tue, 10 Mar 2026 18:26:30 -0700 Subject: [PATCH 3/6] test(publish): assert no prompt text in non-interactive mode --- tests/console/commands/test_publish.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/console/commands/test_publish.py b/tests/console/commands/test_publish.py index 7eccb50a03c..3eb5fdd2480 100644 --- a/tests/console/commands/test_publish.py +++ b/tests/console/commands/test_publish.py @@ -233,6 +233,11 @@ def test_publish_build_no_interaction_skips_confirmation( exit_code = app_tester.execute("publish --build --no-interaction --dry-run") assert exit_code == 0 + output = app_tester.io.fetch_output() + error = app_tester.io.fetch_error() + confirm.assert_not_called() + assert "Build anyway?" not in output + assert "Build anyway?" not in error command_call.assert_called_once_with("build", args="--output dist") assert publisher_publish.call_count == 1 From c045dd721aa83d593efbb18b342111ec539ea53b Mon Sep 17 00:00:00 2001 From: sergiochan Date: Sat, 21 Mar 2026 21:56:30 -0700 Subject: [PATCH 4/6] publish: warn in no-interaction mode when dist exists --- src/poetry/console/commands/publish.py | 19 +++++++++++-------- tests/console/commands/test_publish.py | 4 ++++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/poetry/console/commands/publish.py b/src/poetry/console/commands/publish.py index 3927bffc2cb..6cf18a722a6 100644 --- a/src/poetry/console/commands/publish.py +++ b/src/poetry/console/commands/publish.py @@ -72,17 +72,20 @@ def handle(self) -> int: # Building package first, if told if self.option("build"): - if ( - publisher.files - and self.io.is_interactive() - and not self.confirm( + if publisher.files: + if self.io.is_interactive() and not self.confirm( f"There are {len(publisher.files)} files ready for" " publishing. Build anyway?" - ) - ): - self.line_error("Aborted!") + ): + self.line_error("Aborted!") - return 1 + return 1 + + if not self.io.is_interactive(): + self.line_error( + "Warning: Existing distribution files were found in " + f"{dist_dir}; continuing because --no-interaction was set." + ) self.call("build", args=f"--output {dist_dir}") diff --git a/tests/console/commands/test_publish.py b/tests/console/commands/test_publish.py index 3eb5fdd2480..0dbbd31079d 100644 --- a/tests/console/commands/test_publish.py +++ b/tests/console/commands/test_publish.py @@ -239,5 +239,9 @@ def test_publish_build_no_interaction_skips_confirmation( confirm.assert_not_called() assert "Build anyway?" not in output assert "Build anyway?" not in error + assert ( + "Warning: Existing distribution files were found in dist; continuing because" + " --no-interaction was set." + ) in error command_call.assert_called_once_with("build", args="--output dist") assert publisher_publish.call_count == 1 From 4026ef12632028f04bd89f5774cb5e0043843750 Mon Sep 17 00:00:00 2001 From: sergiochan Date: Sun, 22 Mar 2026 04:53:38 -0700 Subject: [PATCH 5/6] publish: emit non-interactive dist warning on stdout --- src/poetry/console/commands/publish.py | 2 +- tests/console/commands/test_publish.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/poetry/console/commands/publish.py b/src/poetry/console/commands/publish.py index 6cf18a722a6..2f900d436df 100644 --- a/src/poetry/console/commands/publish.py +++ b/src/poetry/console/commands/publish.py @@ -82,7 +82,7 @@ def handle(self) -> int: return 1 if not self.io.is_interactive(): - self.line_error( + self.line( "Warning: Existing distribution files were found in " f"{dist_dir}; continuing because --no-interaction was set." ) diff --git a/tests/console/commands/test_publish.py b/tests/console/commands/test_publish.py index 0dbbd31079d..228090236e6 100644 --- a/tests/console/commands/test_publish.py +++ b/tests/console/commands/test_publish.py @@ -242,6 +242,6 @@ def test_publish_build_no_interaction_skips_confirmation( assert ( "Warning: Existing distribution files were found in dist; continuing because" " --no-interaction was set." - ) in error + ) in output command_call.assert_called_once_with("build", args="--output dist") assert publisher_publish.call_count == 1 From 1a0fe5d55fb941dd2ca0bd9ee90f671cc3e63494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20D=C3=B6ring?= <30527984+radoering@users.noreply.github.com> Date: Sat, 28 Mar 2026 12:46:13 +0100 Subject: [PATCH 6/6] align messages and avoid redundant checks --- src/poetry/console/commands/publish.py | 19 ++++++++++--------- tests/console/commands/test_publish.py | 3 +-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/poetry/console/commands/publish.py b/src/poetry/console/commands/publish.py index 2f900d436df..cd9ba7d5f4a 100644 --- a/src/poetry/console/commands/publish.py +++ b/src/poetry/console/commands/publish.py @@ -73,18 +73,19 @@ def handle(self) -> int: # Building package first, if told if self.option("build"): if publisher.files: - if self.io.is_interactive() and not self.confirm( - f"There are {len(publisher.files)} files ready for" - " publishing. Build anyway?" - ): - self.line_error("Aborted!") + if self.io.is_interactive(): + if not self.confirm( + f"There are {len(publisher.files)} files ready for" + f" publishing in {dist_dir}. Build anyway?" + ): + self.line_error("Aborted!") - return 1 + return 1 - if not self.io.is_interactive(): + else: self.line( - "Warning: Existing distribution files were found in " - f"{dist_dir}; continuing because --no-interaction was set." + f"Warning: There are {len(publisher.files)} files " + f"ready for publishing in {dist_dir}. Build anyway!" ) self.call("build", args=f"--output {dist_dir}") diff --git a/tests/console/commands/test_publish.py b/tests/console/commands/test_publish.py index 228090236e6..1f6f44ce3dc 100644 --- a/tests/console/commands/test_publish.py +++ b/tests/console/commands/test_publish.py @@ -240,8 +240,7 @@ def test_publish_build_no_interaction_skips_confirmation( assert "Build anyway?" not in output assert "Build anyway?" not in error assert ( - "Warning: Existing distribution files were found in dist; continuing because" - " --no-interaction was set." + "Warning: There are 1 files ready for publishing in dist. Build anyway!" ) in output command_call.assert_called_once_with("build", args="--output dist") assert publisher_publish.call_count == 1