forked from cleveragents/cleveragents-core
294 lines
11 KiB
Python
294 lines
11 KiB
Python
"""Step definitions for environment variable extraction feature."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
import yaml
|
|
from behave import given, then, when
|
|
|
|
from cleveragents.discovery.env_variables import EnvironmentVariableExtractor
|
|
|
|
|
|
@given("a Plandex directory with environment variable documentation")
|
|
def step_given_plandex_with_env_docs(context: Any) -> None:
|
|
"""Set up Plandex directory with environment documentation."""
|
|
# Use the Plandex directory from environment.py
|
|
context.plandex_root = getattr(context, "plandex_root", Path("/app/plandex"))
|
|
context.extractor = EnvironmentVariableExtractor(context.plandex_root)
|
|
|
|
|
|
@when("I extract environment variables from documentation")
|
|
def step_extract_from_docs(context: Any) -> None:
|
|
"""Extract environment variables from documentation."""
|
|
context.extractor.extract_from_documentation()
|
|
context.doc_variables = context.extractor.variables.copy()
|
|
|
|
|
|
@then("the extractor should find documented variables")
|
|
def step_should_find_documented_vars(context: Any) -> None:
|
|
"""Verify documented variables were found."""
|
|
assert len(context.doc_variables) > 0, "Should find documented variables"
|
|
# Check for some known variables
|
|
var_names = list(context.doc_variables.keys())
|
|
assert any("PLANDEX" in name for name in var_names), "Should find PLANDEX variables"
|
|
assert any("OPENAI" in name for name in var_names), "Should find OpenAI variables"
|
|
|
|
|
|
@then("each variable should have a description")
|
|
def step_each_var_has_description(context: Any) -> None:
|
|
"""Verify each variable has a description."""
|
|
for var_name, var_info in context.doc_variables.items():
|
|
if "documentation" in var_info.get("sources", []):
|
|
assert "description" in var_info, f"{var_name} should have description"
|
|
# Most documented variables should have descriptions
|
|
if var_info["description"]:
|
|
assert len(var_info["description"]) > 0
|
|
|
|
|
|
@then("each variable should have a proposed CleverAgents name")
|
|
def step_each_var_has_proposed_name(context: Any) -> None:
|
|
"""Verify each variable has a proposed name."""
|
|
for var_name, var_info in context.doc_variables.items():
|
|
assert "proposed_cleveragents_name" in var_info, (
|
|
f"{var_name} should have proposed name"
|
|
)
|
|
assert var_info["proposed_cleveragents_name"], (
|
|
f"{var_name} proposed name should not be empty"
|
|
)
|
|
|
|
# Check naming conventions
|
|
if var_name.startswith("PLANDEX_"):
|
|
assert var_info["proposed_cleveragents_name"].startswith("CLEVERAGENTS_"), (
|
|
f"{var_name} should map to CLEVERAGENTS_ prefix"
|
|
)
|
|
|
|
|
|
@given("a Plandex directory with Go source files")
|
|
def step_given_plandex_with_go_source(context: Any) -> None:
|
|
"""Set up Plandex directory with Go source."""
|
|
context.plandex_root = Path("plandex")
|
|
context.extractor = EnvironmentVariableExtractor(context.plandex_root)
|
|
|
|
|
|
@when("I extract environment variables from Go code")
|
|
def step_extract_from_go_code(context: Any) -> None:
|
|
"""Extract environment variables from Go source."""
|
|
context.extractor.extract_from_go_source()
|
|
context.code_variables = context.extractor.variables.copy()
|
|
|
|
|
|
@then("the extractor should find code-referenced variables")
|
|
def step_should_find_code_vars(context: Any) -> None:
|
|
"""Verify code-referenced variables were found."""
|
|
assert len(context.code_variables) > 0, "Should find code-referenced variables"
|
|
|
|
# Check that some have code in sources
|
|
code_sourced = [
|
|
v for v in context.code_variables.values() if "code" in v.get("sources", [])
|
|
]
|
|
assert len(code_sourced) > 0, "Should have variables sourced from code"
|
|
|
|
|
|
@then("usage locations should be tracked")
|
|
def step_usage_locations_tracked(context: Any) -> None:
|
|
"""Verify usage locations are tracked."""
|
|
vars_with_locations = [
|
|
v for v in context.code_variables.values() if v.get("usage_locations")
|
|
]
|
|
assert len(vars_with_locations) > 0, "Should track usage locations"
|
|
|
|
# Check format of locations
|
|
for var_info in vars_with_locations:
|
|
for location in var_info["usage_locations"]:
|
|
assert ":" in location, f"Location should have file:line format: {location}"
|
|
|
|
|
|
@then("variables should be categorized by source location")
|
|
def step_vars_categorized(context: Any) -> None:
|
|
"""Verify variables are categorized."""
|
|
categories = set()
|
|
for var_info in context.code_variables.values():
|
|
if "category" in var_info:
|
|
categories.add(var_info["category"])
|
|
|
|
assert len(categories) > 0, "Should have categories"
|
|
# Should have some expected categories
|
|
expected = {"CLI", "Server", "General", "LLM Providers"}
|
|
assert len(categories.intersection(expected)) > 0, (
|
|
f"Should have expected categories, found: {categories}"
|
|
)
|
|
|
|
|
|
@given("an extracted set of environment variables")
|
|
def step_given_extracted_vars(context: Any) -> None:
|
|
"""Set up extracted variables."""
|
|
context.plandex_root = Path("plandex")
|
|
context.extractor = EnvironmentVariableExtractor(context.plandex_root)
|
|
context.results = context.extractor.extract_all()
|
|
|
|
|
|
@when("I generate the mapping table")
|
|
def step_generate_mapping(context: Any) -> None:
|
|
"""Generate mapping table."""
|
|
context.mapping = context.extractor.generate_mapping_table()
|
|
|
|
|
|
@then("PLANDEX variables should map to CLEVERAGENTS equivalents")
|
|
def step_plandex_maps_to_cleveragents(context: Any) -> None:
|
|
"""Verify PLANDEX variables map correctly."""
|
|
plandex_vars = [k for k in context.mapping if k.startswith("PLANDEX_")]
|
|
for old_name in plandex_vars:
|
|
new_name = context.mapping[old_name]
|
|
assert new_name.startswith("CLEVERAGENTS_"), (
|
|
f"{old_name} should map to CLEVERAGENTS_ prefix, got {new_name}"
|
|
)
|
|
|
|
|
|
@then("provider-specific variables should remain unchanged")
|
|
def step_provider_vars_unchanged(context: Any) -> None:
|
|
"""Verify provider variables remain unchanged."""
|
|
provider_prefixes = ["OPENAI_", "ANTHROPIC_", "GEMINI_", "AZURE_", "AWS_"]
|
|
|
|
for var_name in context.results["variables"]:
|
|
for prefix in provider_prefixes:
|
|
if var_name.startswith(prefix):
|
|
# Provider vars might not be in mapping if unchanged
|
|
if var_name in context.mapping:
|
|
assert context.mapping[var_name] == var_name, (
|
|
f"Provider variable {var_name} should remain unchanged"
|
|
)
|
|
|
|
|
|
@then("generic variables should get CLEVERAGENTS prefix")
|
|
def step_generic_vars_get_prefix(context: Any) -> None:
|
|
"""Verify generic variables get CLEVERAGENTS prefix."""
|
|
generic_vars = ["PORT", "DATABASE_URL", "GOENV"]
|
|
|
|
for var_name in generic_vars:
|
|
if var_name in context.results["variables"]:
|
|
proposed = context.results["variables"][var_name][
|
|
"proposed_cleveragents_name"
|
|
]
|
|
if not var_name.startswith("CLEVERAGENTS_"):
|
|
assert proposed.startswith("CLEVERAGENTS_"), (
|
|
f"Generic variable {var_name} should get CLEVERAGENTS_ prefix"
|
|
)
|
|
|
|
|
|
@when("I identify conflicts")
|
|
def step_identify_conflicts(context: Any) -> None:
|
|
"""Identify conflicts."""
|
|
context.conflicts = context.extractor.identify_conflicts()
|
|
|
|
|
|
@then("PLANDEX_ prefixed variables should be flagged for migration")
|
|
def step_plandex_flagged(context: Any) -> None:
|
|
"""Verify PLANDEX variables are flagged."""
|
|
migration_conflicts = [
|
|
c for c in context.conflicts if c.get("type") == "migration_required"
|
|
]
|
|
|
|
if any(k.startswith("PLANDEX_") for k in context.results["variables"]):
|
|
assert len(migration_conflicts) > 0, (
|
|
"Should flag PLANDEX variables for migration"
|
|
)
|
|
|
|
|
|
@then("development-only variables should be identified")
|
|
def step_dev_vars_identified(context: Any) -> None:
|
|
"""Verify development variables are identified."""
|
|
dev_conflicts = [
|
|
c for c in context.conflicts if c.get("type") == "development_only"
|
|
]
|
|
|
|
# If there are PLANDEX_DEV variables, they should be flagged
|
|
dev_vars = [k for k in context.results["variables"] if "PLANDEX_DEV" in k]
|
|
if dev_vars:
|
|
assert len(dev_conflicts) > 0, "Should identify development-only variables"
|
|
|
|
|
|
@then("migration guidance should be provided")
|
|
def step_migration_guidance(context: Any) -> None:
|
|
"""Verify migration guidance is provided."""
|
|
for conflict in context.conflicts:
|
|
assert "description" in conflict, "Conflict should have description"
|
|
assert "old_name" in conflict, "Conflict should have old name"
|
|
assert "new_name" in conflict, "Conflict should have new name"
|
|
assert "type" in conflict, "Conflict should have type"
|
|
|
|
|
|
@when("I save the results")
|
|
def step_save_results(context: Any) -> None:
|
|
"""Save extraction results."""
|
|
import tempfile
|
|
|
|
context.temp_dir = tempfile.mkdtemp()
|
|
context.extractor.save_results(context.temp_dir)
|
|
context.output_dir = Path(context.temp_dir)
|
|
|
|
|
|
@then("a JSON file should be created")
|
|
def step_json_created(context: Any) -> None:
|
|
"""Verify JSON file creation."""
|
|
json_file = context.output_dir / "env_variables.json"
|
|
assert json_file.exists(), "JSON file should be created"
|
|
|
|
# Verify it's valid JSON
|
|
with json_file.open() as f:
|
|
data = json.load(f)
|
|
assert "variables" in data
|
|
assert "conflicts" in data
|
|
assert "mapping" in data
|
|
assert "statistics" in data
|
|
|
|
|
|
@then("a YAML file should be created")
|
|
def step_yaml_created(context: Any) -> None:
|
|
"""Verify YAML file creation."""
|
|
yaml_file = context.output_dir / "env_variables.yaml"
|
|
assert yaml_file.exists(), "YAML file should be created"
|
|
|
|
# Verify it's valid YAML
|
|
with yaml_file.open() as f:
|
|
data = yaml.safe_load(f)
|
|
assert "variables" in data
|
|
assert "conflicts" in data
|
|
assert "mapping" in data
|
|
assert "statistics" in data
|
|
|
|
|
|
@then("a mapping text file should be created")
|
|
def step_mapping_file_created(context: Any) -> None:
|
|
"""Verify mapping text file creation."""
|
|
mapping_file = context.output_dir / "env_mapping.txt"
|
|
assert mapping_file.exists(), "Mapping file should be created"
|
|
|
|
# Verify content format
|
|
with mapping_file.open() as f:
|
|
content = f.read()
|
|
assert "Environment Variable Mapping" in content
|
|
assert "->" in content # Should have mapping arrows
|
|
|
|
|
|
@then("a migration guide should be generated")
|
|
def step_migration_guide_created(context: Any) -> None:
|
|
"""Verify migration guide creation."""
|
|
guide_file = context.output_dir / "env_migration_guide.md"
|
|
assert guide_file.exists(), "Migration guide should be created"
|
|
|
|
# Verify content
|
|
with guide_file.open() as f:
|
|
content = f.read()
|
|
assert "# Environment Variable Migration Guide" in content
|
|
assert "## Overview" in content
|
|
assert "## Variable Mappings" in content
|
|
assert "| Old Name | New Name |" in content # Table header
|
|
|
|
# Clean up temp directory
|
|
import shutil
|
|
|
|
shutil.rmtree(context.temp_dir)
|