mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-13 01:58:30 +00:00
feat: add first iteration of CLI Deploy
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
75
src/crewai/cli/deploy/utils.py
Normal file
75
src/crewai/cli/deploy/utils.py
Normal file
@@ -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 {}
|
||||
Reference in New Issue
Block a user