Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion charmcraft/application/commands/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from overrides import override # pyright: ignore[reportUnknownVariableType]

from charmcraft import models, utils
from charmcraft.services.project import ProjectService

OVERVIEW = """\
Command remote-build sends the current project to be built
Expand Down Expand Up @@ -106,7 +107,8 @@ def _run(self, parsed_args: argparse.Namespace, **kwargs: Any) -> int | None:
return 77 # permission denied from sysexits.h

builder = self._services.remote_build
project = cast(models.Charm, self._services.project)
project_service = cast("ProjectService", self._services.project)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
project_service = cast("ProjectService", self._services.project)
project_service = cast("ProjectService", self._services.get("project"))

project = cast("models.Charm", project_service.get())
Comment on lines +110 to +111
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The double-cast here was sadly necessary as self._services.project was returning AppService rather than ProjectService, and then .get() was returning craft_application.models.Project rather than Charmcraft's.

config = cast(dict[str, Any], self.config)
project_dir = (
pathlib.Path(config.get("global_args", {}).get("project_dir") or ".")
Expand Down
5 changes: 5 additions & 0 deletions docs/release-notes/charmcraft-4.2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@ The following issues have been resolved in Charmcraft 4.2.1:
- `#2620 <https://github.com/canonical/charmcraft/issues/2620>`__ Multi-base shorthand
notation fails on v4.2.0

The following issues have been resolved in Charmcraft 4.2.2:

- `#2598 <https://github.com/canonical/charmcraft/issues/2598>`__ Remote build fails
when getting project name

Contributors
------------

Expand Down
48 changes: 48 additions & 0 deletions tests/unit/commands/test_remote.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright 2026 Canonical Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# For further info, check https://github.com/canonical/charmcraft

"""Unit tests for remote-build"""

import argparse

from pytest_mock import MockerFixture

from charmcraft import services
from charmcraft.application import APP_METADATA
from charmcraft.application.commands.remote import RemoteBuild
from charmcraft.services.project import ProjectService


def test_remote_build_project_name_attr_regression(
mocker: MockerFixture, service_factory: services.ServiceFactory
) -> None:
"""Regression test for https://github.com/canonical/charmcraft/issues/2598

The project service was being erroneously cast as the project model, causing
a later access to the `.name` field not be caught by linters.
"""
remote_build_cmd = RemoteBuild({"app": APP_METADATA, "services": service_factory})
namespace = argparse.Namespace(
launchpad_accept_public_upload=True,
recover=False,
launchpad_timeout=0,
)
mocker.patch("charmcraft.services.remotebuild.RemoteBuildService")
project_spy = mocker.spy(ProjectService, "get")

remote_build_cmd.run(namespace)

project_spy.assert_called_once()
Loading