mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-09 16:18:30 +00:00
This commit adds two commands to the CLI:
- `crewai tool publish`
- Builds the project using Poetry
- Uploads the tarball to CrewAI's tool repository
- `crewai tool install my-tool`
- Adds my-tool's index to Poetry and its credentials
- Installs my-tool from the custom index
230 lines
7.8 KiB
Python
230 lines
7.8 KiB
Python
import unittest
|
|
import unittest.mock
|
|
from crewai.cli.tools.main import ToolCommand
|
|
from io import StringIO
|
|
from unittest.mock import patch, MagicMock
|
|
|
|
|
|
class TestToolCommand(unittest.TestCase):
|
|
@patch("crewai.cli.tools.main.subprocess.run")
|
|
@patch("crewai.cli.plus_api.PlusAPI.get_tool")
|
|
def test_install_success(self, mock_get, mock_subprocess_run):
|
|
mock_get_response = MagicMock()
|
|
mock_get_response.status_code = 200
|
|
mock_get_response.json.return_value = {
|
|
"handle": "sample-tool",
|
|
"repository": {
|
|
"handle": "sample-repo",
|
|
"url": "https://example.com/repo",
|
|
"credentials": "my_very_secret",
|
|
},
|
|
}
|
|
mock_get.return_value = mock_get_response
|
|
mock_subprocess_run.return_value = MagicMock(stderr=None)
|
|
|
|
tool_command = ToolCommand()
|
|
|
|
with patch("sys.stdout", new=StringIO()) as fake_out:
|
|
tool_command.install("sample-tool")
|
|
output = fake_out.getvalue()
|
|
|
|
mock_get.assert_called_once_with("sample-tool")
|
|
mock_subprocess_run.assert_any_call(
|
|
[
|
|
"poetry",
|
|
"source",
|
|
"add",
|
|
"--priority=explicit",
|
|
"crewai-sample-repo",
|
|
"https://example.com/repo",
|
|
],
|
|
text=True,
|
|
check=True,
|
|
)
|
|
mock_subprocess_run.assert_any_call(
|
|
[
|
|
"poetry",
|
|
"config",
|
|
"http-basic.crewai-sample-repo",
|
|
"my_very_secret",
|
|
'""',
|
|
],
|
|
capture_output=False,
|
|
text=True,
|
|
check=True,
|
|
)
|
|
mock_subprocess_run.assert_any_call(
|
|
["poetry", "add", "--source", "crewai-sample-repo", "sample-tool"],
|
|
capture_output=False,
|
|
text=True,
|
|
check=True,
|
|
)
|
|
|
|
self.assertIn("Succesfully installed sample-tool", output)
|
|
|
|
@patch("crewai.cli.plus_api.PlusAPI.get_tool")
|
|
def test_install_tool_not_found(self, mock_get):
|
|
mock_get_response = MagicMock()
|
|
mock_get_response.status_code = 404
|
|
mock_get.return_value = mock_get_response
|
|
|
|
tool_command = ToolCommand()
|
|
|
|
with patch("sys.stdout", new=StringIO()) as fake_out:
|
|
with self.assertRaises(SystemExit):
|
|
tool_command.install("non-existent-tool")
|
|
output = fake_out.getvalue()
|
|
|
|
mock_get.assert_called_once_with("non-existent-tool")
|
|
self.assertIn("No tool found with this name", output)
|
|
|
|
@patch("crewai.cli.plus_api.PlusAPI.get_tool")
|
|
def test_install_api_error(self, mock_get):
|
|
mock_get_response = MagicMock()
|
|
mock_get_response.status_code = 500
|
|
mock_get.return_value = mock_get_response
|
|
|
|
tool_command = ToolCommand()
|
|
|
|
with patch("sys.stdout", new=StringIO()) as fake_out:
|
|
with self.assertRaises(SystemExit):
|
|
tool_command.install("error-tool")
|
|
output = fake_out.getvalue()
|
|
|
|
mock_get.assert_called_once_with("error-tool")
|
|
self.assertIn("Failed to get tool details", output)
|
|
|
|
@patch("crewai.cli.tools.main.get_project_name", return_value="sample-tool")
|
|
@patch("crewai.cli.tools.main.get_project_version", return_value="1.0.0")
|
|
@patch(
|
|
"crewai.cli.tools.main.get_project_description", return_value="A sample tool"
|
|
)
|
|
@patch("crewai.cli.tools.main.subprocess.run")
|
|
@patch(
|
|
"crewai.cli.tools.main.os.listdir", return_value=["sample-tool-1.0.0.tar.gz"]
|
|
)
|
|
@patch(
|
|
"crewai.cli.tools.main.open",
|
|
new_callable=unittest.mock.mock_open,
|
|
read_data=b"sample tarball content",
|
|
)
|
|
@patch("crewai.cli.plus_api.PlusAPI.publish_tool")
|
|
def test_publish_success(
|
|
self,
|
|
mock_publish,
|
|
mock_open,
|
|
mock_listdir,
|
|
mock_subprocess_run,
|
|
mock_get_project_description,
|
|
mock_get_project_version,
|
|
mock_get_project_name,
|
|
):
|
|
mock_publish_response = MagicMock()
|
|
mock_publish_response.status_code = 200
|
|
mock_publish_response.json.return_value = {"handle": "sample-tool"}
|
|
mock_publish.return_value = mock_publish_response
|
|
|
|
tool_command = ToolCommand()
|
|
tool_command.publish(is_public=True)
|
|
|
|
mock_get_project_name.assert_called_once_with(require=True)
|
|
mock_get_project_version.assert_called_once_with(require=True)
|
|
mock_get_project_description.assert_called_once_with(require=False)
|
|
mock_subprocess_run.assert_called_once_with(
|
|
["poetry", "build", "-f", "sdist", "--output", unittest.mock.ANY],
|
|
check=True,
|
|
capture_output=False,
|
|
)
|
|
mock_open.assert_called_once_with(unittest.mock.ANY, "rb")
|
|
mock_publish.assert_called_once_with(
|
|
handle="sample-tool",
|
|
is_public=True,
|
|
version="1.0.0",
|
|
description="A sample tool",
|
|
encoded_file=unittest.mock.ANY,
|
|
)
|
|
|
|
@patch("crewai.cli.tools.main.get_project_name", return_value="sample-tool")
|
|
@patch("crewai.cli.tools.main.get_project_version", return_value="1.0.0")
|
|
@patch(
|
|
"crewai.cli.tools.main.get_project_description", return_value="A sample tool"
|
|
)
|
|
@patch("crewai.cli.tools.main.subprocess.run")
|
|
@patch(
|
|
"crewai.cli.tools.main.os.listdir", return_value=["sample-tool-1.0.0.tar.gz"]
|
|
)
|
|
@patch(
|
|
"crewai.cli.tools.main.open",
|
|
new_callable=unittest.mock.mock_open,
|
|
read_data=b"sample tarball content",
|
|
)
|
|
@patch("crewai.cli.plus_api.PlusAPI.publish_tool")
|
|
def test_publish_failure(
|
|
self,
|
|
mock_publish,
|
|
mock_open,
|
|
mock_listdir,
|
|
mock_subprocess_run,
|
|
mock_get_project_description,
|
|
mock_get_project_version,
|
|
mock_get_project_name,
|
|
):
|
|
mock_publish_response = MagicMock()
|
|
mock_publish_response.status_code = 422
|
|
mock_publish_response.json.return_value = {"name": ["is already taken"]}
|
|
mock_publish.return_value = mock_publish_response
|
|
|
|
tool_command = ToolCommand()
|
|
|
|
with patch("sys.stdout", new=StringIO()) as fake_out:
|
|
with self.assertRaises(SystemExit):
|
|
tool_command.publish(is_public=True)
|
|
output = fake_out.getvalue()
|
|
|
|
mock_publish.assert_called_once()
|
|
self.assertIn("Failed to publish tool", output)
|
|
self.assertIn("Name is already taken", output)
|
|
|
|
@patch("crewai.cli.tools.main.get_project_name", return_value="sample-tool")
|
|
@patch("crewai.cli.tools.main.get_project_version", return_value="1.0.0")
|
|
@patch(
|
|
"crewai.cli.tools.main.get_project_description", return_value="A sample tool"
|
|
)
|
|
@patch("crewai.cli.tools.main.subprocess.run")
|
|
@patch(
|
|
"crewai.cli.tools.main.os.listdir", return_value=["sample-tool-1.0.0.tar.gz"]
|
|
)
|
|
@patch(
|
|
"crewai.cli.tools.main.open",
|
|
new_callable=unittest.mock.mock_open,
|
|
read_data=b"sample tarball content",
|
|
)
|
|
@patch("crewai.cli.plus_api.PlusAPI.publish_tool")
|
|
def test_publish_api_error(
|
|
self,
|
|
mock_publish,
|
|
mock_open,
|
|
mock_listdir,
|
|
mock_subprocess_run,
|
|
mock_get_project_description,
|
|
mock_get_project_version,
|
|
mock_get_project_name,
|
|
):
|
|
mock_publish_response = MagicMock()
|
|
mock_publish_response.status_code = 500
|
|
mock_publish.return_value = mock_publish_response
|
|
|
|
tool_command = ToolCommand()
|
|
|
|
with patch("sys.stdout", new=StringIO()) as fake_out:
|
|
with self.assertRaises(SystemExit):
|
|
tool_command.publish(is_public=True)
|
|
output = fake_out.getvalue()
|
|
|
|
mock_publish.assert_called_once()
|
|
self.assertIn("Failed to publish tool", output)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|