diff --git a/docs/explanation/cryptography.rst b/docs/explanation/cryptography.rst index 343884d904..fcc1523dbe 100644 --- a/docs/explanation/cryptography.rst +++ b/docs/explanation/cryptography.rst @@ -282,7 +282,7 @@ is invoked by the consuming application. .. _Apt: https://wiki.debian.org/AptCLI .. _Bazaar: https://launchpad.net/bzr -.. _Craft Application cryptography: https://canonical-craft-application.readthedocs-hosted.com/en/latest/explanation/cryptography/ +.. _Craft Application cryptography: https://documentation.ubuntu.com/craft-application/latest/explanation/cryptography/ .. _Craft Archives cryptography: https://documentation.ubuntu.com/craft-archives/latest/explanation/cryptography/ .. _Craft Parts cryptography: https://documentation.ubuntu.com/craft-parts/latest/explanation/cryptography/ .. _Craft Providers cryptography: https://documentation.ubuntu.com/craft-providers/latest/explanation/cryptography/ diff --git a/snapcraft/store/client.py b/snapcraft/store/client.py index e4686b76ea..d9ee01756d 100644 --- a/snapcraft/store/client.py +++ b/snapcraft/store/client.py @@ -576,6 +576,11 @@ def notify_upload( # noqa: PLR0913 (too-many-arguments) raise errors.SnapcraftError( f"Issues while processing snap:\n{error_string}" ) + if status.get("code") == "error": + raise errors.SnapcraftError( + f"Store processing failed with status: {human_status!r}. " + "Please check the automated review on the Snap Store." + ) break time.sleep(_POLL_DELAY) diff --git a/tests/unit/store/test_client.py b/tests/unit/store/test_client.py index e44f0d0151..8ac35f996b 100644 --- a/tests/unit/store/test_client.py +++ b/tests/unit/store/test_client.py @@ -2277,3 +2277,38 @@ def test_on_prem_list_releases( headers={"Content-Type": "application/json", "Accept": "application/json"}, ) ] + + +def test_notify_upload_error_status_raises_error(mocker): + """Test that notify_upload raises SnapcraftError if store processing returns code 'error'.""" + status_url = "https://dashboard.snapcraft.io/dev/api/snap-push/123/status/" + + # Use the exact class we found from grep + test_client = client.StoreClientCLI() + + post_response = mocker.Mock() + post_response.json.return_value = {"status_details_url": status_url} + + get_response = mocker.Mock() + get_response.json.return_value = { + "processed": True, + "code": "error", + "errors": [], + "revision": 1, + } + + mocker.patch.object( + test_client, "request", side_effect=[post_response, get_response] + ) + + with pytest.raises( + errors.SnapcraftError, match="Store processing failed with status" + ): + test_client.notify_upload( + snap_name="test-snap", + upload_id="upload-123", + snap_file_size=1024, + built_at=None, + channels=None, + components=None, + )