diff --git a/CHANGELOG.md b/CHANGELOG.md index 674411a76..b632fd4bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Positional `apm install ` now exits non-zero when all packages fail + validation, matching manifest installs for reliable CI scripting. (#2131) - Fresh checkouts with declared consumer targets no longer remain `apm audit --ci`-red for files those targets cannot restore: `apm install` now removes stale `deployed_files` entries outside the legitimate target diff --git a/src/apm_cli/commands/install.py b/src/apm_cli/commands/install.py index 503a38a08..6e5a43384 100644 --- a/src/apm_cli/commands/install.py +++ b/src/apm_cli/commands/install.py @@ -1530,7 +1530,8 @@ def install( # noqa: PLR0913 ) # Short-circuit: all packages failed validation -- nothing to install if outcome.all_failed: - return + summary_rendered = True + sys.exit(1) # Note: Empty validated_packages is OK if packages are already in apm.yml; # only_packages is derived from validation outcomes below. diff --git a/tests/integration/test_wave7_marketplace_install_coverage.py b/tests/integration/test_wave7_marketplace_install_coverage.py index d8ec7718b..dc3bb000e 100644 --- a/tests/integration/test_wave7_marketplace_install_coverage.py +++ b/tests/integration/test_wave7_marketplace_install_coverage.py @@ -1056,8 +1056,8 @@ def test_install_package_validation_failure(self, runner: CliRunner, tmp_path: P ), ): result = runner.invoke(cli, ["install", "owner/nonexistent"]) - # All validations failed → exit - assert result.exit_code != 0 or "not accessible" in result.output + # All validations failed, so the command must report failure. + assert result.exit_code == 1 # =========================================================================== diff --git a/tests/unit/test_install_command.py b/tests/unit/test_install_command.py index 825b61aa0..d4f42aa94 100644 --- a/tests/unit/test_install_command.py +++ b/tests/unit/test_install_command.py @@ -337,6 +337,17 @@ def test_install_auto_created_apm_yml_has_correct_metadata( assert "description" in config assert "APM project" in config["description"] + @patch("apm_cli.commands.install._validate_package_exists", return_value=False) + def test_install_positional_url_total_validation_failure_exits_one(self, mock_validate): + """A positional URL that cannot be validated must fail the command.""" + with self._chdir_tmp(): + result = self.runner.invoke(cli, ["install", "https://127.0.0.1:1/org/repo.git"]) + + assert result.exit_code == 1 + assert "All packages failed validation" in result.output + assert "Install interrupted" not in result.output + mock_validate.assert_called() + @patch("apm_cli.commands.install._validate_package_exists") def test_install_invalid_package_format_with_no_apm_yml(self, mock_validate): """Test that invalid package format fails gracefully even with auto-bootstrap."""