diff --git a/src/crewai/cli/cli.py b/src/crewai/cli/cli.py index 9617caa58..c45db44e7 100644 --- a/src/crewai/cli/cli.py +++ b/src/crewai/cli/cli.py @@ -14,7 +14,7 @@ from .reset_memories_command import reset_memories_command from .run_crew import run_crew from .train_crew import train_crew -deploy_cmd = DeployCommand("myCrew_test") +deploy_cmd = DeployCommand() @click.group() diff --git a/src/crewai/cli/deploy/main.py b/src/crewai/cli/deploy/main.py index b28a52e68..9dde56766 100644 --- a/src/crewai/cli/deploy/main.py +++ b/src/crewai/cli/deploy/main.py @@ -1,24 +1,133 @@ +import json +import os +from os import getenv + +import requests +from rich import print + +from .utils import fetch_and_json_env_file, get_git_remote_url, get_project_name + + +def get_auth_token(): + return os.environ.get( + "TOKEN", "958303356b9a21884a83ddb6e774cc06c6f1dd0e04222fbc5a4e8a9ae02c140e" + ) + + class DeployCommand: - def __init__(self, project_name): - self.project_name = project_name + def __init__(self): + # self.base_url = os.environ.get("BASE_URL", "https://www.crewai.com/api") + self.base_url = getenv("BASE_URL", "http://localhost:3000/crewai_plus/api") + + self.project_name = get_project_name() + self.remote_repo_url = get_git_remote_url() def deploy(self): print("Deploying the crew...") + response = requests.post( + f"{self.base_url}/crews/by-name/{self.project_name}/deploy", + headers={"Authorization": f"Bearer {get_auth_token()}"}, + ) + print(response.json()) def create_crew(self): print("Creating deployment...") + env_vars = fetch_and_json_env_file() + payload = { + "deploy": { + "name": self.project_name, + "repo_clone_url": self.remote_repo_url, + "env": env_vars, + } + } + response = requests.post( + f"{self.base_url}/crews", + data=json.dumps(payload), + headers={ + "Authorization": f"Bearer {get_auth_token()}", + "Content-type": "application/json", + }, + ) + print(response.json()) def list_crews(self): - print("Listing all deployments...") + print("Listing all Crews") + + response = requests.get( + f"{self.base_url}/crews", + headers={"Authorization": f"Bearer {get_auth_token()}"}, + ) + crews_data = response.json() + if response.status_code == 200: + print() + if len(crews_data): + for crew_data in crews_data: + print( + f"- {crew_data['name']} ({crew_data['uuid']}) [blue]\[{crew_data['status']}]" + ) + else: + print("You don't have any crews yet. Let's create one!") + print() + print("\t[green]crewai create --name \[name]") def get_crew_status(self): print("Getting deployment status...") + response = requests.get( + f"{self.base_url}/crews/by-name/{self.project_name}/status", + headers={"Authorization": f"Bearer {get_auth_token()}"}, + ) + if response.status_code == 200: + status_data = response.json() + print(status_data) + print("Name:\t", status_data["name"]) + print("Status:\t", status_data["status"]) + print() + print("usage:") + print(f"\tcrewai inputs --name \"{status_data['name']}\" ") + print( + f"\tcrewai kickoff --name \"{status_data['name']}\" --inputs [INPUTS]" + ) + else: + print(response.json()) - def get_crew_logs(self): + def get_crew_logs(self, log_type="deployment"): print("Getting deployment logs...") + response = requests.get( + f"{self.base_url}/crews/by-name/{self.project_name}/logs/{log_type}", + headers={"Authorization": f"Bearer {get_auth_token()}"}, + ) + + if response.status_code == 200: + log_messages = response.json() + for log_message in log_messages: + print( + f"{log_message['timestamp']} - {log_message['level']}: {log_message['message']}" + ) + else: + print(response.text) def remove_crew(self): print("Removing deployment...") + response = requests.delete( + f"{self.base_url}/crews/by-name/{self.project_name}", + headers={"Authorization": f"Bearer {get_auth_token()}"}, + ) + if response.status_code == 204: + print(f"Crew '{self.project_name}' removed successfully.") def signup(self): - print("Signing up for deployment...") + print("Signing Up") + response = requests.get(f"{self.base_url}/signup_link") + if response.status_code == 200: + token = response.json()["token"] + signup_link = response.json()["signup_link"] + print("Temporary credentials: ", token) + print( + "We are trying to open the following signup link below.\n" + "If it doesn't open to you, copy-and-paste into our browser to procceed." + ) + print() + print(signup_link) + # webbrowser.open(signup_link, new=2) + else: + print(response.text) diff --git a/src/crewai/cli/deploy/utils.py b/src/crewai/cli/deploy/utils.py new file mode 100644 index 000000000..606f12876 --- /dev/null +++ b/src/crewai/cli/deploy/utils.py @@ -0,0 +1,75 @@ +import re +import subprocess + +import tomllib + + +def get_git_remote_url(): + try: + # Run the git remote -v command + result = subprocess.run( + ["git", "remote", "-v"], capture_output=True, text=True, check=True + ) + + # Get the output + output = result.stdout + + # Parse the output to find the origin URL + matches = re.findall(r"origin\s+(.*?)\s+\(fetch\)", output) + + if matches: + return matches[0] # Return the first match (origin URL) + else: + print("No origin remote found.") + return None + + except subprocess.CalledProcessError as e: + print(f"Error running trying to fetch the Git Repository: {e}") + return None + except FileNotFoundError: + print("Git command not found. Make sure Git is installed and in your PATH.") + + return None + + +def get_project_name(pyproject_path: str = "pyproject.toml"): + try: + # Read the pyproject.toml file + with open(pyproject_path, "rb") as f: + pyproject_content = tomllib.load(f) + + # Extract the project name + project_name = pyproject_content["tool"]["poetry"]["name"] + + return project_name + except FileNotFoundError: + print(f"Error: {pyproject_path} not found.") + except KeyError: + print("Error: 'name' not found in [tool.poetry] section.") + except tomllib.TOMLDecodeError: + print(f"Error: {pyproject_path} is not a valid TOML file.") + + return None + + +def fetch_and_json_env_file(env_file_path: str = ".env") -> dict: + try: + # Read the .env file + with open(env_file_path, "r") as f: + env_content = f.read() + + # Parse the .env file content to a dictionary + env_dict = {} + for line in env_content.splitlines(): + if line.strip() and not line.strip().startswith("#"): + key, value = line.split("=", 1) + env_dict[key.strip()] = value.strip() + + return env_dict + + except FileNotFoundError: + print(f"Error: {env_file_path} not found.") + except Exception as e: + print(f"Error reading the .env file: {e}") + + return {}