Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
851df79
fix: defer native LLM client construction when credentials are missing
greysonlalonde Apr 10, 2026
9f61deb
feat: add `crewai deploy validate` pre-deploy validation
greysonlalonde Apr 10, 2026
bbc7392
Merge branch 'main' into feat/cli-predeploy-validation
greysonlalonde Apr 10, 2026
96031fa
Merge branch 'main' into feat/cli-predeploy-validation
greysonlalonde Apr 10, 2026
8312e1c
fix: keep Azure aclose a no-op when the async client was never built
greysonlalonde Apr 11, 2026
9eb4595
fix: avoid forcing lazy client construction in lightweight accessors
greysonlalonde Apr 11, 2026
6f87078
test: update deploy_push CLI tests for new skip_validate kwarg
greysonlalonde Apr 11, 2026
77e6664
test: update test_create_llm_openai_missing_api_key for lazy init
greysonlalonde Apr 11, 2026
ad6d7fa
fix: re-read Azure env vars in lazy client build
greysonlalonde Apr 11, 2026
60e8a4a
fix: recompute is_azure_openai_endpoint after lazy endpoint resolve
greysonlalonde Apr 11, 2026
41403c0
fix: re-read Gemini env vars in lazy client build
greysonlalonde Apr 11, 2026
1dc3108
refactor: route Gemini async paths through _get_async_client
greysonlalonde Apr 11, 2026
760a3f2
test: assert Azure endpoint hostname instead of substring match
greysonlalonde Apr 11, 2026
755b1f2
fix: don't leak sync httpx.Client when building Anthropic async client
greysonlalonde Apr 11, 2026
4c3ff7d
fix: narrow Bedrock _init_clients except to credential errors only
greysonlalonde Apr 11, 2026
1121969
fix: match real provider error messages in missing-extra classifier
greysonlalonde Apr 12, 2026
61c7320
Merge branch 'main' into feat/cli-predeploy-validation
greysonlalonde Apr 12, 2026
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
31 changes: 27 additions & 4 deletions lib/crewai/src/crewai/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -392,10 +392,15 @@ def deploy() -> None:

@deploy.command(name="create")
@click.option("-y", "--yes", is_flag=True, help="Skip the confirmation prompt")
def deploy_create(yes: bool) -> None:
@click.option(
"--skip-validate",
is_flag=True,
help="Skip the pre-deploy validation checks.",
)
def deploy_create(yes: bool, skip_validate: bool) -> None:
"""Create a Crew deployment."""
deploy_cmd = DeployCommand()
deploy_cmd.create_crew(yes)
deploy_cmd.create_crew(yes, skip_validate=skip_validate)


@deploy.command(name="list")
Expand All @@ -407,10 +412,28 @@ def deploy_list() -> None:

@deploy.command(name="push")
@click.option("-u", "--uuid", type=str, help="Crew UUID parameter")
def deploy_push(uuid: str | None) -> None:
@click.option(
"--skip-validate",
is_flag=True,
help="Skip the pre-deploy validation checks.",
)
def deploy_push(uuid: str | None, skip_validate: bool) -> None:
"""Deploy the Crew."""
deploy_cmd = DeployCommand()
deploy_cmd.deploy(uuid=uuid)
deploy_cmd.deploy(uuid=uuid, skip_validate=skip_validate)


@deploy.command(name="validate")
def deploy_validate() -> None:
"""Validate the current project against common deployment failures.

Runs the same pre-deploy checks that `crewai deploy create` and
`crewai deploy push` run automatically, without contacting the platform.
Exits non-zero if any blocking issues are found.
"""
from crewai.cli.deploy.validate import run_validate_command

run_validate_command()


@deploy.command(name="status")
Expand Down
36 changes: 34 additions & 2 deletions lib/crewai/src/crewai/cli/deploy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,35 @@

from crewai.cli import git
from crewai.cli.command import BaseCommand, PlusAPIMixin
from crewai.cli.deploy.validate import validate_project
from crewai.cli.utils import fetch_and_json_env_file, get_project_name


console = Console()


def _run_predeploy_validation(skip_validate: bool) -> bool:
"""Run pre-deploy validation unless skipped.

Returns True if deployment should proceed, False if it should abort.
"""
if skip_validate:
console.print(
"[yellow]Skipping pre-deploy validation (--skip-validate).[/yellow]"
)
return True

console.print("Running pre-deploy validation...", style="bold blue")
validator = validate_project()
if not validator.ok:
console.print(
"\n[bold red]Pre-deploy validation failed. "
"Fix the issues above or re-run with --skip-validate.[/bold red]"
)
return False
return True


class DeployCommand(BaseCommand, PlusAPIMixin):
"""
A class to handle deployment-related operations for CrewAI projects.
Expand Down Expand Up @@ -60,13 +83,16 @@ def _display_logs(self, log_messages: list[dict[str, Any]]) -> None:
f"{log_message['timestamp']} - {log_message['level']}: {log_message['message']}"
)

def deploy(self, uuid: str | None = None) -> None:
def deploy(self, uuid: str | None = None, skip_validate: bool = False) -> None:
"""
Deploy a crew using either UUID or project name.

Args:
uuid (Optional[str]): The UUID of the crew to deploy.
skip_validate (bool): Skip pre-deploy validation checks.
"""
if not _run_predeploy_validation(skip_validate):
return
self._telemetry.start_deployment_span(uuid)
console.print("Starting deployment...", style="bold blue")
if uuid:
Expand All @@ -80,10 +106,16 @@ def deploy(self, uuid: str | None = None) -> None:
self._validate_response(response)
self._display_deployment_info(response.json())

def create_crew(self, confirm: bool = False) -> None:
def create_crew(self, confirm: bool = False, skip_validate: bool = False) -> None:
"""
Create a new crew deployment.

Args:
confirm (bool): Whether to skip the interactive confirmation prompt.
skip_validate (bool): Skip pre-deploy validation checks.
"""
if not _run_predeploy_validation(skip_validate):
return
self._telemetry.create_crew_deployment_span()
console.print("Creating deployment...", style="bold blue")
env_vars = fetch_and_json_env_file()
Expand Down
Loading
Loading