mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-09 16:18:30 +00:00
fix: ensure env-vars are written in upper case (#3072)
When creating a Crew via the CLI and selecting the Azure provider, the generated .env file had environment variables in lowercase. This commit ensures that all environment variables are written in uppercase.
This commit is contained in:
@@ -252,7 +252,7 @@ def write_env_file(folder_path, env_vars):
|
|||||||
env_file_path = folder_path / ".env"
|
env_file_path = folder_path / ".env"
|
||||||
with open(env_file_path, "w") as file:
|
with open(env_file_path, "w") as file:
|
||||||
for key, value in env_vars.items():
|
for key, value in env_vars.items():
|
||||||
file.write(f"{key}={value}\n")
|
file.write(f"{key.upper()}={value}\n")
|
||||||
|
|
||||||
|
|
||||||
def get_crews(crew_path: str = "crew.py", require: bool = False) -> list[Crew]:
|
def get_crews(crew_path: str = "crew.py", require: bool = False) -> list[Crew]:
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ from click.testing import CliRunner
|
|||||||
|
|
||||||
from crewai.cli.create_crew import create_crew, create_folder_structure
|
from crewai.cli.create_crew import create_crew, create_folder_structure
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def runner():
|
def runner():
|
||||||
return CliRunner()
|
return CliRunner()
|
||||||
@@ -25,7 +24,7 @@ def temp_dir():
|
|||||||
def test_create_folder_structure_strips_single_trailing_slash():
|
def test_create_folder_structure_strips_single_trailing_slash():
|
||||||
with tempfile.TemporaryDirectory() as temp_dir:
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
folder_path, folder_name, class_name = create_folder_structure("hello/", parent_folder=temp_dir)
|
folder_path, folder_name, class_name = create_folder_structure("hello/", parent_folder=temp_dir)
|
||||||
|
|
||||||
assert folder_name == "hello"
|
assert folder_name == "hello"
|
||||||
assert class_name == "Hello"
|
assert class_name == "Hello"
|
||||||
assert folder_path.name == "hello"
|
assert folder_path.name == "hello"
|
||||||
@@ -36,7 +35,7 @@ def test_create_folder_structure_strips_single_trailing_slash():
|
|||||||
def test_create_folder_structure_strips_multiple_trailing_slashes():
|
def test_create_folder_structure_strips_multiple_trailing_slashes():
|
||||||
with tempfile.TemporaryDirectory() as temp_dir:
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
folder_path, folder_name, class_name = create_folder_structure("hello///", parent_folder=temp_dir)
|
folder_path, folder_name, class_name = create_folder_structure("hello///", parent_folder=temp_dir)
|
||||||
|
|
||||||
assert folder_name == "hello"
|
assert folder_name == "hello"
|
||||||
assert class_name == "Hello"
|
assert class_name == "Hello"
|
||||||
assert folder_path.name == "hello"
|
assert folder_path.name == "hello"
|
||||||
@@ -47,7 +46,7 @@ def test_create_folder_structure_strips_multiple_trailing_slashes():
|
|||||||
def test_create_folder_structure_handles_complex_name_with_trailing_slash():
|
def test_create_folder_structure_handles_complex_name_with_trailing_slash():
|
||||||
with tempfile.TemporaryDirectory() as temp_dir:
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
folder_path, folder_name, class_name = create_folder_structure("my-awesome_project/", parent_folder=temp_dir)
|
folder_path, folder_name, class_name = create_folder_structure("my-awesome_project/", parent_folder=temp_dir)
|
||||||
|
|
||||||
assert folder_name == "my_awesome_project"
|
assert folder_name == "my_awesome_project"
|
||||||
assert class_name == "MyAwesomeProject"
|
assert class_name == "MyAwesomeProject"
|
||||||
assert folder_path.name == "my_awesome_project"
|
assert folder_path.name == "my_awesome_project"
|
||||||
@@ -58,7 +57,7 @@ def test_create_folder_structure_handles_complex_name_with_trailing_slash():
|
|||||||
def test_create_folder_structure_normal_name_unchanged():
|
def test_create_folder_structure_normal_name_unchanged():
|
||||||
with tempfile.TemporaryDirectory() as temp_dir:
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
folder_path, folder_name, class_name = create_folder_structure("hello", parent_folder=temp_dir)
|
folder_path, folder_name, class_name = create_folder_structure("hello", parent_folder=temp_dir)
|
||||||
|
|
||||||
assert folder_name == "hello"
|
assert folder_name == "hello"
|
||||||
assert class_name == "Hello"
|
assert class_name == "Hello"
|
||||||
assert folder_path.name == "hello"
|
assert folder_path.name == "hello"
|
||||||
@@ -73,9 +72,9 @@ def test_create_folder_structure_with_parent_folder():
|
|||||||
with tempfile.TemporaryDirectory() as temp_dir:
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
parent_path = Path(temp_dir) / "parent"
|
parent_path = Path(temp_dir) / "parent"
|
||||||
parent_path.mkdir()
|
parent_path.mkdir()
|
||||||
|
|
||||||
folder_path, folder_name, class_name = create_folder_structure("child/", parent_folder=parent_path)
|
folder_path, folder_name, class_name = create_folder_structure("child/", parent_folder=parent_path)
|
||||||
|
|
||||||
assert folder_name == "child"
|
assert folder_name == "child"
|
||||||
assert class_name == "Child"
|
assert class_name == "Child"
|
||||||
assert folder_path.name == "child"
|
assert folder_path.name == "child"
|
||||||
@@ -88,18 +87,18 @@ def test_create_folder_structure_with_parent_folder():
|
|||||||
@mock.patch("crewai.cli.create_crew.load_env_vars")
|
@mock.patch("crewai.cli.create_crew.load_env_vars")
|
||||||
def test_create_crew_with_trailing_slash_creates_valid_project(mock_load_env, mock_write_env, mock_copy_template, temp_dir):
|
def test_create_crew_with_trailing_slash_creates_valid_project(mock_load_env, mock_write_env, mock_copy_template, temp_dir):
|
||||||
mock_load_env.return_value = {}
|
mock_load_env.return_value = {}
|
||||||
|
|
||||||
with tempfile.TemporaryDirectory() as work_dir:
|
with tempfile.TemporaryDirectory() as work_dir:
|
||||||
with mock.patch("crewai.cli.create_crew.create_folder_structure") as mock_create_folder:
|
with mock.patch("crewai.cli.create_crew.create_folder_structure") as mock_create_folder:
|
||||||
mock_folder_path = Path(work_dir) / "test_project"
|
mock_folder_path = Path(work_dir) / "test_project"
|
||||||
mock_create_folder.return_value = (mock_folder_path, "test_project", "TestProject")
|
mock_create_folder.return_value = (mock_folder_path, "test_project", "TestProject")
|
||||||
|
|
||||||
create_crew("test-project/", skip_provider=True)
|
create_crew("test-project/", skip_provider=True)
|
||||||
|
|
||||||
mock_create_folder.assert_called_once_with("test-project/", None)
|
mock_create_folder.assert_called_once_with("test-project/", None)
|
||||||
mock_copy_template.assert_called()
|
mock_copy_template.assert_called()
|
||||||
copy_calls = mock_copy_template.call_args_list
|
copy_calls = mock_copy_template.call_args_list
|
||||||
|
|
||||||
for call in copy_calls:
|
for call in copy_calls:
|
||||||
args = call[0]
|
args = call[0]
|
||||||
if len(args) >= 5:
|
if len(args) >= 5:
|
||||||
@@ -112,14 +111,14 @@ def test_create_crew_with_trailing_slash_creates_valid_project(mock_load_env, mo
|
|||||||
@mock.patch("crewai.cli.create_crew.load_env_vars")
|
@mock.patch("crewai.cli.create_crew.load_env_vars")
|
||||||
def test_create_crew_with_multiple_trailing_slashes(mock_load_env, mock_write_env, mock_copy_template, temp_dir):
|
def test_create_crew_with_multiple_trailing_slashes(mock_load_env, mock_write_env, mock_copy_template, temp_dir):
|
||||||
mock_load_env.return_value = {}
|
mock_load_env.return_value = {}
|
||||||
|
|
||||||
with tempfile.TemporaryDirectory() as work_dir:
|
with tempfile.TemporaryDirectory() as work_dir:
|
||||||
with mock.patch("crewai.cli.create_crew.create_folder_structure") as mock_create_folder:
|
with mock.patch("crewai.cli.create_crew.create_folder_structure") as mock_create_folder:
|
||||||
mock_folder_path = Path(work_dir) / "test_project"
|
mock_folder_path = Path(work_dir) / "test_project"
|
||||||
mock_create_folder.return_value = (mock_folder_path, "test_project", "TestProject")
|
mock_create_folder.return_value = (mock_folder_path, "test_project", "TestProject")
|
||||||
|
|
||||||
create_crew("test-project///", skip_provider=True)
|
create_crew("test-project///", skip_provider=True)
|
||||||
|
|
||||||
mock_create_folder.assert_called_once_with("test-project///", None)
|
mock_create_folder.assert_called_once_with("test-project///", None)
|
||||||
|
|
||||||
|
|
||||||
@@ -128,21 +127,21 @@ def test_create_crew_with_multiple_trailing_slashes(mock_load_env, mock_write_en
|
|||||||
@mock.patch("crewai.cli.create_crew.load_env_vars")
|
@mock.patch("crewai.cli.create_crew.load_env_vars")
|
||||||
def test_create_crew_normal_name_still_works(mock_load_env, mock_write_env, mock_copy_template, temp_dir):
|
def test_create_crew_normal_name_still_works(mock_load_env, mock_write_env, mock_copy_template, temp_dir):
|
||||||
mock_load_env.return_value = {}
|
mock_load_env.return_value = {}
|
||||||
|
|
||||||
with tempfile.TemporaryDirectory() as work_dir:
|
with tempfile.TemporaryDirectory() as work_dir:
|
||||||
with mock.patch("crewai.cli.create_crew.create_folder_structure") as mock_create_folder:
|
with mock.patch("crewai.cli.create_crew.create_folder_structure") as mock_create_folder:
|
||||||
mock_folder_path = Path(work_dir) / "normal_project"
|
mock_folder_path = Path(work_dir) / "normal_project"
|
||||||
mock_create_folder.return_value = (mock_folder_path, "normal_project", "NormalProject")
|
mock_create_folder.return_value = (mock_folder_path, "normal_project", "NormalProject")
|
||||||
|
|
||||||
create_crew("normal-project", skip_provider=True)
|
create_crew("normal-project", skip_provider=True)
|
||||||
|
|
||||||
mock_create_folder.assert_called_once_with("normal-project", None)
|
mock_create_folder.assert_called_once_with("normal-project", None)
|
||||||
|
|
||||||
|
|
||||||
def test_create_folder_structure_handles_spaces_and_dashes_with_slash():
|
def test_create_folder_structure_handles_spaces_and_dashes_with_slash():
|
||||||
with tempfile.TemporaryDirectory() as temp_dir:
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
folder_path, folder_name, class_name = create_folder_structure("My Cool-Project/", parent_folder=temp_dir)
|
folder_path, folder_name, class_name = create_folder_structure("My Cool-Project/", parent_folder=temp_dir)
|
||||||
|
|
||||||
assert folder_name == "my_cool_project"
|
assert folder_name == "my_cool_project"
|
||||||
assert class_name == "MyCoolProject"
|
assert class_name == "MyCoolProject"
|
||||||
assert folder_path.name == "my_cool_project"
|
assert folder_path.name == "my_cool_project"
|
||||||
@@ -155,7 +154,7 @@ def test_create_folder_structure_raises_error_for_invalid_names():
|
|||||||
invalid_cases = [
|
invalid_cases = [
|
||||||
("123project/", "cannot start with a digit"),
|
("123project/", "cannot start with a digit"),
|
||||||
("True/", "reserved Python keyword"),
|
("True/", "reserved Python keyword"),
|
||||||
("False/", "reserved Python keyword"),
|
("False/", "reserved Python keyword"),
|
||||||
("None/", "reserved Python keyword"),
|
("None/", "reserved Python keyword"),
|
||||||
("class/", "reserved Python keyword"),
|
("class/", "reserved Python keyword"),
|
||||||
("def/", "reserved Python keyword"),
|
("def/", "reserved Python keyword"),
|
||||||
@@ -163,7 +162,7 @@ def test_create_folder_structure_raises_error_for_invalid_names():
|
|||||||
("", "empty or contain only whitespace"),
|
("", "empty or contain only whitespace"),
|
||||||
("@#$/", "contains no valid characters"),
|
("@#$/", "contains no valid characters"),
|
||||||
]
|
]
|
||||||
|
|
||||||
for invalid_name, expected_error in invalid_cases:
|
for invalid_name, expected_error in invalid_cases:
|
||||||
with pytest.raises(ValueError, match=expected_error):
|
with pytest.raises(ValueError, match=expected_error):
|
||||||
create_folder_structure(invalid_name, parent_folder=temp_dir)
|
create_folder_structure(invalid_name, parent_folder=temp_dir)
|
||||||
@@ -179,20 +178,20 @@ def test_create_folder_structure_validates_names():
|
|||||||
("hello.world/", "helloworld", "HelloWorld"),
|
("hello.world/", "helloworld", "HelloWorld"),
|
||||||
("hello@world/", "helloworld", "HelloWorld"),
|
("hello@world/", "helloworld", "HelloWorld"),
|
||||||
]
|
]
|
||||||
|
|
||||||
for valid_name, expected_folder, expected_class in valid_cases:
|
for valid_name, expected_folder, expected_class in valid_cases:
|
||||||
folder_path, folder_name, class_name = create_folder_structure(valid_name, parent_folder=temp_dir)
|
folder_path, folder_name, class_name = create_folder_structure(valid_name, parent_folder=temp_dir)
|
||||||
assert folder_name == expected_folder
|
assert folder_name == expected_folder
|
||||||
assert class_name == expected_class
|
assert class_name == expected_class
|
||||||
|
|
||||||
assert folder_name.isidentifier(), f"folder_name '{folder_name}' should be valid Python identifier"
|
assert folder_name.isidentifier(), f"folder_name '{folder_name}' should be valid Python identifier"
|
||||||
assert not keyword.iskeyword(folder_name), f"folder_name '{folder_name}' should not be Python keyword"
|
assert not keyword.iskeyword(folder_name), f"folder_name '{folder_name}' should not be Python keyword"
|
||||||
assert not folder_name[0].isdigit(), f"folder_name '{folder_name}' should not start with digit"
|
assert not folder_name[0].isdigit(), f"folder_name '{folder_name}' should not start with digit"
|
||||||
|
|
||||||
assert class_name.isidentifier(), f"class_name '{class_name}' should be valid Python identifier"
|
assert class_name.isidentifier(), f"class_name '{class_name}' should be valid Python identifier"
|
||||||
assert not keyword.iskeyword(class_name), f"class_name '{class_name}' should not be Python keyword"
|
assert not keyword.iskeyword(class_name), f"class_name '{class_name}' should not be Python keyword"
|
||||||
assert folder_path.parent == Path(temp_dir)
|
assert folder_path.parent == Path(temp_dir)
|
||||||
|
|
||||||
if folder_path.exists():
|
if folder_path.exists():
|
||||||
shutil.rmtree(folder_path)
|
shutil.rmtree(folder_path)
|
||||||
|
|
||||||
@@ -202,13 +201,13 @@ def test_create_folder_structure_validates_names():
|
|||||||
@mock.patch("crewai.cli.create_crew.load_env_vars")
|
@mock.patch("crewai.cli.create_crew.load_env_vars")
|
||||||
def test_create_crew_with_parent_folder_and_trailing_slash(mock_load_env, mock_write_env, mock_copy_template, temp_dir):
|
def test_create_crew_with_parent_folder_and_trailing_slash(mock_load_env, mock_write_env, mock_copy_template, temp_dir):
|
||||||
mock_load_env.return_value = {}
|
mock_load_env.return_value = {}
|
||||||
|
|
||||||
with tempfile.TemporaryDirectory() as work_dir:
|
with tempfile.TemporaryDirectory() as work_dir:
|
||||||
parent_path = Path(work_dir) / "parent"
|
parent_path = Path(work_dir) / "parent"
|
||||||
parent_path.mkdir()
|
parent_path.mkdir()
|
||||||
|
|
||||||
create_crew("child-crew/", skip_provider=True, parent_folder=parent_path)
|
create_crew("child-crew/", skip_provider=True, parent_folder=parent_path)
|
||||||
|
|
||||||
crew_path = parent_path / "child_crew"
|
crew_path = parent_path / "child_crew"
|
||||||
assert crew_path.exists()
|
assert crew_path.exists()
|
||||||
assert not (crew_path / "src").exists()
|
assert not (crew_path / "src").exists()
|
||||||
@@ -224,23 +223,56 @@ def test_create_folder_structure_folder_name_validation():
|
|||||||
("for/", "reserved Python keyword"),
|
("for/", "reserved Python keyword"),
|
||||||
("@#$invalid/", "contains no valid characters.*Python module name"),
|
("@#$invalid/", "contains no valid characters.*Python module name"),
|
||||||
]
|
]
|
||||||
|
|
||||||
for invalid_name, expected_error in folder_invalid_cases:
|
for invalid_name, expected_error in folder_invalid_cases:
|
||||||
with pytest.raises(ValueError, match=expected_error):
|
with pytest.raises(ValueError, match=expected_error):
|
||||||
create_folder_structure(invalid_name, parent_folder=temp_dir)
|
create_folder_structure(invalid_name, parent_folder=temp_dir)
|
||||||
|
|
||||||
valid_cases = [
|
valid_cases = [
|
||||||
("hello-world/", "hello_world"),
|
("hello-world/", "hello_world"),
|
||||||
("my.project/", "myproject"),
|
("my.project/", "myproject"),
|
||||||
("test@123/", "test123"),
|
("test@123/", "test123"),
|
||||||
("valid_name/", "valid_name"),
|
("valid_name/", "valid_name"),
|
||||||
]
|
]
|
||||||
|
|
||||||
for valid_name, expected_folder in valid_cases:
|
for valid_name, expected_folder in valid_cases:
|
||||||
folder_path, folder_name, class_name = create_folder_structure(valid_name, parent_folder=temp_dir)
|
folder_path, folder_name, class_name = create_folder_structure(valid_name, parent_folder=temp_dir)
|
||||||
assert folder_name == expected_folder
|
assert folder_name == expected_folder
|
||||||
assert folder_name.isidentifier()
|
assert folder_name.isidentifier()
|
||||||
assert not keyword.iskeyword(folder_name)
|
assert not keyword.iskeyword(folder_name)
|
||||||
|
|
||||||
if folder_path.exists():
|
if folder_path.exists():
|
||||||
shutil.rmtree(folder_path)
|
shutil.rmtree(folder_path)
|
||||||
|
|
||||||
|
@mock.patch("crewai.cli.create_crew.create_folder_structure")
|
||||||
|
@mock.patch("crewai.cli.create_crew.copy_template")
|
||||||
|
@mock.patch("crewai.cli.create_crew.load_env_vars")
|
||||||
|
@mock.patch("crewai.cli.create_crew.get_provider_data")
|
||||||
|
@mock.patch("crewai.cli.create_crew.select_provider")
|
||||||
|
@mock.patch("crewai.cli.create_crew.select_model")
|
||||||
|
@mock.patch("click.prompt")
|
||||||
|
def test_env_vars_are_uppercased_in_env_file(
|
||||||
|
mock_prompt,
|
||||||
|
mock_select_model,
|
||||||
|
mock_select_provider,
|
||||||
|
mock_get_provider_data,
|
||||||
|
mock_load_env_vars,
|
||||||
|
mock_copy_template,
|
||||||
|
mock_create_folder_structure,
|
||||||
|
tmp_path
|
||||||
|
):
|
||||||
|
crew_path = tmp_path / "test_crew"
|
||||||
|
crew_path.mkdir()
|
||||||
|
mock_create_folder_structure.return_value = (crew_path, "test_crew", "TestCrew")
|
||||||
|
|
||||||
|
mock_load_env_vars.return_value = {}
|
||||||
|
mock_get_provider_data.return_value = {"openai": ["gpt-4"]}
|
||||||
|
mock_select_provider.return_value = "azure"
|
||||||
|
mock_select_model.return_value = "azure/openai"
|
||||||
|
mock_prompt.return_value = "fake-api-key"
|
||||||
|
|
||||||
|
create_crew("Test Crew")
|
||||||
|
|
||||||
|
env_file_path = crew_path / ".env"
|
||||||
|
content = env_file_path.read_text()
|
||||||
|
assert "MODEL=" in content
|
||||||
Reference in New Issue
Block a user