Fix deployment page link id resolution (#6365)

This commit is contained in:
João Moura
2026-06-27 03:19:46 -03:00
committed by GitHub
parent e1ddb32e56
commit 04adff1e0e
2 changed files with 96 additions and 5 deletions

View File

@@ -18,7 +18,7 @@ from crewai_cli.utils import fetch_and_json_env_file, get_project_name
console = Console()
_MISSING_LOCKFILE_ERROR_CODES = {"missing_lockfile"}
_DEPLOYMENT_ID_KEYS = ("deployment_id", "deploymentId")
_DEPLOYMENT_FALLBACK_IDENTIFIER_KEYS = ("id", "uuid")
_DEPLOYMENT_FALLBACK_IDENTIFIER_KEYS = ("id",)
def _run_predeploy_validation(
@@ -223,7 +223,7 @@ class DeployCommand(BaseCommand, PlusAPIMixin):
getattr(self.plus_api_client, "base_url", None)
or DEFAULT_CREWAI_ENTERPRISE_URL
)
deployment_url = _deployment_page_url(base_url, json_response)
deployment_url = self._deployment_page_url(json_response, base_url)
if not deployment_url:
return
@@ -239,6 +239,52 @@ class DeployCommand(BaseCommand, PlusAPIMixin):
style="yellow",
)
def _deployment_page_url(
self,
json_response: dict[str, Any],
base_url: str,
) -> str | None:
"""Build the deployment show URL, resolving UUID-only responses if needed."""
deployment_url = _deployment_page_url(base_url, json_response)
if deployment_url:
return deployment_url
identifier = self._deployment_identifier_from_status(json_response)
if not identifier:
return None
return (
f"{base_url.rstrip('/')}/crewai_plus/deployments/"
f"{quote(identifier, safe='')}"
)
def _deployment_identifier_from_status(
self,
json_response: dict[str, Any],
) -> str | None:
"""Resolve the deployment page id from status without failing the command."""
crew_uuid = json_response.get("uuid")
if not crew_uuid:
return None
try:
response = self.plus_api_client.crew_status_by_uuid(str(crew_uuid))
except Exception:
return None
if not getattr(response, "is_success", False):
return None
try:
status_response = response.json()
except ValueError:
return None
if not isinstance(status_response, dict):
return None
return _deployment_identifier(status_response)
def deploy(self, uuid: str | None = None, skip_validate: bool = False) -> None:
"""
Deploy a crew using either UUID or project name.

View File

@@ -187,13 +187,13 @@ def test_deployment_page_url_prefers_nested_deployment_id_over_crew_uuid():
)
def test_deployment_page_url_falls_back_to_nested_uuid():
def test_deployment_page_url_does_not_use_uuid_as_deployment_id():
assert (
deploy_main._deployment_page_url(
"https://app.crewai.com/",
{"deployment": {"uuid": "deployment-uuid"}},
{"uuid": "crew-uuid", "deployment": {"uuid": "deployment-uuid"}},
)
== "https://app.crewai.com/crewai_plus/deployments/deployment-uuid"
is None
)
@@ -353,6 +353,51 @@ class TestDeployCommand(unittest.TestCase):
"https://app.crewai.com/crewai_plus/deployments/128687"
)
def test_display_creation_success_resolves_deployment_page_id_from_status(self):
status_response = MagicMock()
status_response.is_success = True
status_response.json.return_value = {
"uuid": "new-uuid",
"id": 128774,
"status": "created",
}
self.mock_client.crew_status_by_uuid.return_value = status_response
with patch("sys.stdout", new=StringIO()) as fake_out:
self.deploy_command._display_creation_success(
{"uuid": "new-uuid", "status": "created"}
)
output = fake_out.getvalue()
self.assertIn("crewai deploy push --uuid new-uuid", output)
self.assertIn(
"https://app.crewai.com/crewai_plus/deployments/128774",
output,
)
self.assertNotIn(
"https://app.crewai.com/crewai_plus/deployments/new-uuid",
output,
)
self.mock_client.crew_status_by_uuid.assert_called_once_with("new-uuid")
self.mock_browser_open.assert_called_once_with(
"https://app.crewai.com/crewai_plus/deployments/128774"
)
def test_open_deployment_page_does_not_open_uuid_url_when_status_lookup_fails(
self,
):
status_response = MagicMock()
status_response.is_success = False
self.mock_client.crew_status_by_uuid.return_value = status_response
with patch("sys.stdout", new=StringIO()) as fake_out:
self.deploy_command._open_deployment_page({"uuid": "new-uuid"})
output = fake_out.getvalue()
self.mock_client.crew_status_by_uuid.assert_called_once_with("new-uuid")
self.mock_browser_open.assert_not_called()
self.assertNotIn("deployments/new-uuid", output)
def test_display_logs(self):
with patch("sys.stdout", new=StringIO()) as fake_out:
self.deploy_command._display_logs(