mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-07-01 13:18:10 +00:00
fix(cli): sync missing lockfile before deploy
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
from typing import Any
|
||||
|
||||
from crewai_core.plus_api import CreateCrewPayload
|
||||
@@ -58,6 +60,28 @@ def _env_summary(env_vars: dict[str, str]) -> str:
|
||||
return f"{len(env_vars)} env vars: {keys}"
|
||||
|
||||
|
||||
def _ensure_lockfile_for_deploy() -> None:
|
||||
"""Create a uv lockfile before deploy when a project has not been run yet."""
|
||||
project_root = Path.cwd()
|
||||
if not (project_root / "pyproject.toml").is_file():
|
||||
return
|
||||
if (project_root / "uv.lock").is_file() or (project_root / "poetry.lock").is_file():
|
||||
return
|
||||
|
||||
from crewai_cli.install_crew import install_crew
|
||||
|
||||
console.print(
|
||||
"No lockfile found. Installing dependencies before deployment...",
|
||||
style="bold blue",
|
||||
)
|
||||
try:
|
||||
install_crew([], raise_on_error=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise SystemExit(e.returncode) from e
|
||||
except Exception as e:
|
||||
raise SystemExit(1) from e
|
||||
|
||||
|
||||
class DeployCommand(BaseCommand, PlusAPIMixin):
|
||||
"""
|
||||
A class to handle deployment-related operations for CrewAI projects.
|
||||
@@ -116,6 +140,7 @@ class DeployCommand(BaseCommand, PlusAPIMixin):
|
||||
uuid (Optional[str]): The UUID of the crew to deploy.
|
||||
skip_validate (bool): Skip pre-deploy validation checks.
|
||||
"""
|
||||
_ensure_lockfile_for_deploy()
|
||||
if not _run_predeploy_validation(skip_validate):
|
||||
return
|
||||
self._telemetry.start_deployment_span(uuid)
|
||||
@@ -161,6 +186,7 @@ class DeployCommand(BaseCommand, PlusAPIMixin):
|
||||
confirm (bool): Whether to skip the interactive confirmation prompt.
|
||||
skip_validate (bool): Skip pre-deploy validation checks.
|
||||
"""
|
||||
_ensure_lockfile_for_deploy()
|
||||
if not _run_predeploy_validation(skip_validate):
|
||||
return
|
||||
self._telemetry.create_crew_deployment_span()
|
||||
|
||||
@@ -2,16 +2,84 @@ import sys
|
||||
import unittest
|
||||
from io import StringIO
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
from unittest.mock import MagicMock, Mock, patch
|
||||
|
||||
import pytest
|
||||
import json
|
||||
|
||||
import crewai_cli.deploy.main as deploy_main
|
||||
import httpx
|
||||
from crewai_cli.deploy.main import DeployCommand
|
||||
from crewai_cli.utils import parse_toml
|
||||
|
||||
|
||||
def test_ensure_lockfile_for_deploy_runs_install_when_lock_missing(
|
||||
monkeypatch, tmp_path: Path
|
||||
):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / "pyproject.toml").write_text("[project]\nname = 'demo'\n")
|
||||
calls = []
|
||||
|
||||
def fake_install_crew(proxy_options, *, raise_on_error=False):
|
||||
calls.append((proxy_options, raise_on_error))
|
||||
|
||||
monkeypatch.setattr("crewai_cli.install_crew.install_crew", fake_install_crew)
|
||||
|
||||
deploy_main._ensure_lockfile_for_deploy()
|
||||
|
||||
assert calls == [([], True)]
|
||||
|
||||
|
||||
def test_ensure_lockfile_for_deploy_skips_when_lock_exists(monkeypatch, tmp_path: Path):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / "pyproject.toml").write_text("[project]\nname = 'demo'\n")
|
||||
(tmp_path / "uv.lock").write_text("# lock\n")
|
||||
calls = []
|
||||
|
||||
def fake_install_crew(proxy_options, *, raise_on_error=False):
|
||||
calls.append((proxy_options, raise_on_error))
|
||||
|
||||
monkeypatch.setattr("crewai_cli.install_crew.install_crew", fake_install_crew)
|
||||
|
||||
deploy_main._ensure_lockfile_for_deploy()
|
||||
|
||||
assert calls == []
|
||||
|
||||
|
||||
def test_ensure_lockfile_for_deploy_skips_without_pyproject(
|
||||
monkeypatch, tmp_path: Path
|
||||
):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
calls = []
|
||||
|
||||
def fake_install_crew(proxy_options, *, raise_on_error=False):
|
||||
calls.append((proxy_options, raise_on_error))
|
||||
|
||||
monkeypatch.setattr("crewai_cli.install_crew.install_crew", fake_install_crew)
|
||||
|
||||
deploy_main._ensure_lockfile_for_deploy()
|
||||
|
||||
assert calls == []
|
||||
|
||||
|
||||
def test_ensure_lockfile_for_deploy_failure_exits_nonzero(
|
||||
monkeypatch, tmp_path: Path
|
||||
):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / "pyproject.toml").write_text("[project]\nname = 'demo'\n")
|
||||
|
||||
def fake_install_crew(proxy_options, *, raise_on_error=False):
|
||||
raise subprocess.CalledProcessError(42, ["uv", "sync"])
|
||||
|
||||
monkeypatch.setattr("crewai_cli.install_crew.install_crew", fake_install_crew)
|
||||
|
||||
with pytest.raises(SystemExit) as exc_info:
|
||||
deploy_main._ensure_lockfile_for_deploy()
|
||||
|
||||
assert exc_info.value.code == 42
|
||||
|
||||
|
||||
class TestDeployCommand(unittest.TestCase):
|
||||
@patch("crewai_cli.command.get_auth_token")
|
||||
@patch("crewai_cli.deploy.main.get_project_name")
|
||||
|
||||
Reference in New Issue
Block a user