Skip to content

Commit

Permalink
chore: config feedback (#610)
Browse files Browse the repository at this point in the history
  • Loading branch information
caroljung-cg authored Feb 22, 2025
1 parent 17fa0bc commit b5ef76e
Show file tree
Hide file tree
Showing 24 changed files with 96 additions and 136 deletions.
23 changes: 10 additions & 13 deletions src/codegen/cli/commands/config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
from rich.table import Table

from codegen.configs.constants import ENV_FILENAME, GLOBAL_ENV_FILE
from codegen.configs.session_manager import session_manager
from codegen.configs.user_config import UserConfig
from codegen.shared.path import get_git_root_path


@click.group(name="config")
Expand All @@ -16,8 +16,7 @@ def config_command():


@config_command.command(name="list")
@click.option("--global", "is_global", is_flag=True, help="Lists the global configuration values")
def list_command(is_global: bool):
def list_command():
"""List current configuration values."""

def flatten_dict(data: dict, prefix: str = "") -> dict:
Expand All @@ -33,7 +32,7 @@ def flatten_dict(data: dict, prefix: str = "") -> dict:
items[full_key] = value
return items

config = _get_user_config(is_global)
config = _get_user_config()
flat_config = flatten_dict(config.to_dict())
sorted_items = sorted(flat_config.items(), key=lambda x: x[0])

Expand Down Expand Up @@ -82,10 +81,9 @@ def flatten_dict(data: dict, prefix: str = "") -> dict:

@config_command.command(name="get")
@click.argument("key")
@click.option("--global", "is_global", is_flag=True, help="Get the global configuration value")
def get_command(key: str, is_global: bool):
def get_command(key: str):
"""Get a configuration value."""
config = _get_user_config(is_global)
config = _get_user_config()
if not config.has_key(key):
rich.print(f"[red]Error: Configuration key '{key}' not found[/red]")
return
Expand All @@ -98,10 +96,9 @@ def get_command(key: str, is_global: bool):
@config_command.command(name="set")
@click.argument("key")
@click.argument("value")
@click.option("--global", "is_global", is_flag=True, help="Sets the global configuration value")
def set_command(key: str, value: str, is_global: bool):
def set_command(key: str, value: str):
"""Set a configuration value and write to .env"""
config = _get_user_config(is_global)
config = _get_user_config()
if not config.has_key(key):
rich.print(f"[red]Error: Configuration key '{key}' not found[/red]")
return
Expand All @@ -118,10 +115,10 @@ def set_command(key: str, value: str, is_global: bool):
rich.print(f"[green]Successfully set {key}=[magenta]{value}[/magenta] and saved to {ENV_FILENAME}[/green]")


def _get_user_config(is_global: bool) -> UserConfig:
if is_global or (active_session_path := session_manager.get_active_session()) is None:
def _get_user_config() -> UserConfig:
if (project_root := get_git_root_path()) is None:
env_filepath = GLOBAL_ENV_FILE
else:
env_filepath = active_session_path / ENV_FILENAME
env_filepath = project_root / ENV_FILENAME

return UserConfig(env_filepath)
2 changes: 1 addition & 1 deletion src/codegen/cli/commands/init/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from codegen.cli.commands.init.render import get_success_message
from codegen.cli.rich.codeblocks import format_command
from codegen.cli.workspace.initialize_workspace import initialize_codegen
from codegen.git.utils.path import get_git_root_path
from codegen.shared.path import get_git_root_path


@click.command(name="init")
Expand Down
10 changes: 7 additions & 3 deletions src/codegen/cli/env/global_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,24 @@ def _parse_env(self) -> Environment:
def _load_dotenv(self) -> None:
env_file = find_dotenv(filename=f".env.{self.ENV}")
# if env specific .env file does not exist, try to load .env
load_dotenv(env_file or None)
load_dotenv(env_file or None, override=True)

def _get_env_var(self, var_name, required: bool = False) -> str:
if self.ENV == "local":
return ""

value = os.environ.get(var_name)
if value:
if value := os.environ.get(var_name):
return value

if required:
msg = f"Environment variable {var_name} is not set with ENV={self.ENV}!"
raise ValueError(msg)
return ""

def __repr__(self) -> str:
# Returns all env vars in a readable format
return "\n".join([f"{k}={v}" for k, v in self.__dict__.items()])


# NOTE: load and store envvars once
global_env = GlobalEnv()
14 changes: 6 additions & 8 deletions src/codegen/configs/models/base_config.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from abc import ABC
from pathlib import Path

from dotenv import set_key
from dotenv import load_dotenv, set_key
from pydantic_settings import BaseSettings, SettingsConfigDict

from codegen.configs.constants import ENV_FILENAME, GLOBAL_ENV_FILE
from codegen.configs.session_manager import session_root
from codegen.shared.path import get_git_root_path


class BaseConfig(BaseSettings, ABC):
Expand All @@ -18,20 +18,18 @@ class BaseConfig(BaseSettings, ABC):

def __init__(self, prefix: str, env_filepath: Path | None = None, *args, **kwargs) -> None:
if env_filepath is None:
root_path = session_root
root_path = get_git_root_path()
if root_path is not None:
env_filepath = root_path / ENV_FILENAME

# Only include env files that exist
env_filepaths = []
if GLOBAL_ENV_FILE.exists():
env_filepaths.append(GLOBAL_ENV_FILE)
load_dotenv(GLOBAL_ENV_FILE, override=True)

if env_filepath and env_filepath.exists() and env_filepath != GLOBAL_ENV_FILE:
env_filepaths.append(env_filepath)
load_dotenv(env_filepath, override=True)

self.model_config["env_prefix"] = f"{prefix.upper()}_" if len(prefix) > 0 else ""
self.model_config["env_file"] = env_filepaths

super().__init__(*args, **kwargs)

@property
Expand Down
3 changes: 0 additions & 3 deletions src/codegen/configs/models/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,3 @@ def full_name(self) -> str | None:
if self.owner is not None:
return f"{self.owner}/{self.name}"
return None


DefaultRepoConfig = RepositoryConfig()
3 changes: 0 additions & 3 deletions src/codegen/configs/models/secrets.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,3 @@ def __init__(self, prefix: str = "", *args, **kwargs) -> None:
github_token: str | None = None
openai_api_key: str | None = None
linear_api_key: str | None = None


DefaultSecrets = SecretsConfig()
32 changes: 1 addition & 31 deletions src/codegen/configs/session_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import json
from pathlib import Path

from codegen.configs.constants import CODEGEN_DIR_NAME, SESSION_FILE
from codegen.configs.constants import SESSION_FILE


class SessionManager:
Expand Down Expand Up @@ -61,34 +61,4 @@ def __str__(self) -> str:
return f"GlobalConfig:\n Active Session: {active}\n Sessions:\n {sessions_str}\n Global Session:\n {self.session_config}"


def _get_project_root() -> Path | None:
"""Get the active codegen directory."""
active_session = session_manager.get_active_session()
if active_session:
return active_session

try:
path = Path.cwd().resolve()
except FileNotFoundError:
# Current directory is not accessible
return None

while True:
codegen_path = path / CODEGEN_DIR_NAME
git_path = path / ".git"

if codegen_path.exists():
return path
if git_path.exists():
return path

parent = path.parent.resolve()
if parent == path: # We've reached the root directory
break
path = parent

return None


session_manager = SessionManager()
session_root = _get_project_root()
8 changes: 4 additions & 4 deletions src/codegen/configs/user_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ def to_dict(self) -> dict:
for key, value in self.repository.model_dump().items():
config_dict[f"{self.repository.env_prefix}{key}".upper()] = value

# Add secrets configs with 'secrets_' prefix
for key, value in self.secrets.model_dump().items():
config_dict[f"{self.secrets.env_prefix}{key}".upper()] = value

# Add feature flags configs with 'feature_flags_' prefix
for key, value in self.codebase.model_dump().items():
config_dict[f"{self.codebase.env_prefix}{key}".upper()] = value

# Add secrets configs
for key, value in self.secrets.model_dump().items():
config_dict[f"{self.secrets.env_prefix}{key}".upper()] = value
return config_dict

def has_key(self, full_key: str) -> bool:
Expand Down
4 changes: 2 additions & 2 deletions src/codegen/extensions/lsp/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from lsprotocol.types import INITIALIZE, InitializeParams, InitializeResult
from pygls.protocol import LanguageServerProtocol, lsp_method

from codegen.configs.models.codebase import DefaultCodebaseConfig
from codegen.configs.models.codebase import CodebaseConfig
from codegen.extensions.lsp.io import LSPIO
from codegen.extensions.lsp.progress import LSPProgress
from codegen.extensions.lsp.utils import get_path
Expand All @@ -26,7 +26,7 @@ def _init_codebase(self, params: InitializeParams) -> None:
root = get_path(params.root_uri)
else:
root = os.getcwd()
config = DefaultCodebaseConfig.model_copy(update={"full_range_index": True})
config = CodebaseConfig().model_copy(update={"full_range_index": True})
io = LSPIO(self.workspace)
self._server.codebase = Codebase(repo_path=str(root), config=config, io=io, progress=progress)
self._server.progress_manager = progress
Expand Down
5 changes: 3 additions & 2 deletions src/codegen/git/clients/git_repo_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from github.Tag import Tag
from github.Workflow import Workflow

from codegen.configs.models.secrets import SecretsConfig
from codegen.git.clients.github_client import GithubClient
from codegen.git.schemas.repo_config import RepoConfig
from codegen.git.utils.format import format_comparison
Expand All @@ -29,9 +30,9 @@ class GitRepoClient:
gh_client: GithubClient
_repo: Repository

def __init__(self, repo_config: RepoConfig, access_token: str) -> None:
def __init__(self, repo_config: RepoConfig, access_token: str | None = None) -> None:
self.repo_config = repo_config
self.gh_client = self._create_github_client(token=access_token)
self.gh_client = self._create_github_client(token=access_token or SecretsConfig().github_token)
self._repo = self._create_client()

def _create_github_client(self, token: str) -> GithubClient:
Expand Down
6 changes: 3 additions & 3 deletions src/codegen/git/repo_operator/repo_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from github.IssueComment import IssueComment
from github.PullRequest import PullRequest

from codegen.configs.models.secrets import DefaultSecrets
from codegen.configs.models.secrets import SecretsConfig
from codegen.git.clients.git_repo_client import GitRepoClient
from codegen.git.configs.constants import CODEGEN_BOT_EMAIL, CODEGEN_BOT_NAME
from codegen.git.repo_operator.local_git_repo import LocalGitRepo
Expand Down Expand Up @@ -58,7 +58,7 @@ def __init__(
) -> None:
assert repo_config is not None
self.repo_config = repo_config
self.access_token = access_token or DefaultSecrets.github_token
self.access_token = access_token or SecretsConfig().github_token
self.base_dir = repo_config.base_dir
self.bot_commit = bot_commit

Expand Down Expand Up @@ -839,7 +839,7 @@ def create_from_repo(cls, repo_path: str, url: str, access_token: str | None = N
url (str): Git URL of the repository
access_token (str | None): Optional GitHub API key for operations that need GitHub access
"""
access_token = access_token or DefaultSecrets.github_token
access_token = access_token or SecretsConfig().github_token
if access_token:
url = add_access_token_to_url(url=url, token=access_token)

Expand Down
11 changes: 4 additions & 7 deletions src/codegen/runner/clients/codebase_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import logging

from codegen.configs.models import secrets
from codegen.configs.models.secrets import SecretsConfig
from codegen.git.schemas.repo_config import RepoConfig
from codegen.runner.clients.server_client import LocalServerClient
from codegen.runner.models.apis import SANDBOX_SERVER_PORT
Expand All @@ -16,11 +16,9 @@ class CodebaseClient(LocalServerClient):
"""Client for interacting with the locally hosted sandbox server."""

repo_config: RepoConfig
git_access_token: str | None

def __init__(self, repo_config: RepoConfig, git_access_token: str | None, host: str = "127.0.0.1", port: int = SANDBOX_SERVER_PORT):
def __init__(self, repo_config: RepoConfig, host: str = "127.0.0.1", port: int = SANDBOX_SERVER_PORT):
self.repo_config = repo_config
self.git_access_token = git_access_token
super().__init__(server_path=RUNNER_SERVER_PATH, host=host, port=port)

def _get_envs(self) -> dict:
Expand All @@ -29,9 +27,8 @@ def _get_envs(self) -> dict:
"REPOSITORY_LANGUAGE": self.repo_config.language.value,
"REPOSITORY_OWNER": self.repo_config.organization_name,
"REPOSITORY_PATH": str(self.repo_config.repo_path),
"GITHUB_TOKEN": SecretsConfig().github_token,
}
if self.git_access_token is not None:
codebase_envs["GITHUB_TOKEN"] = self.git_access_token

envs.update(codebase_envs)
return envs
Expand All @@ -40,5 +37,5 @@ def _get_envs(self) -> dict:
if __name__ == "__main__":
test_config = RepoConfig.from_repo_path("/Users/caroljung/git/codegen/codegen-agi")
test_config.full_name = "codegen-sh/codegen-agi"
client = CodebaseClient(test_config, secrets.github_token)
client = CodebaseClient(test_config)
print(client.healthcheck())
4 changes: 2 additions & 2 deletions src/codegen/runner/sandbox/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ class SandboxRunner:
codebase: CodebaseType
executor: SandboxExecutor

def __init__(self, repo_config: RepoConfig, access_token: str) -> None:
def __init__(self, repo_config: RepoConfig) -> None:
self.repo = repo_config
self.op = RepoOperator(repo_config=self.repo, access_token=access_token, setup_option=SetupOption.PULL_OR_CLONE)
self.op = RepoOperator(repo_config=self.repo, setup_option=SetupOption.PULL_OR_CLONE)
self.commit = self.op.git_cli.head.commit

async def warmup(self) -> None:
Expand Down
16 changes: 8 additions & 8 deletions src/codegen/runner/sandbox/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
import psutil
from fastapi import FastAPI

from codegen.configs.models.repository import DefaultRepoConfig
from codegen.configs.models.secrets import DefaultSecrets
from codegen.configs.models.repository import RepositoryConfig
from codegen.git.schemas.repo_config import RepoConfig
from codegen.runner.enums.warmup_state import WarmupState
from codegen.runner.models.apis import (
Expand Down Expand Up @@ -40,15 +39,16 @@ async def lifespan(server: FastAPI):
global runner

try:
server_info = ServerInfo(repo_name=DefaultRepoConfig.full_name or DefaultRepoConfig.name)
default_repo_config = RepositoryConfig()
server_info = ServerInfo(repo_name=default_repo_config.full_name or default_repo_config.name)
logger.info(f"Starting up sandbox fastapi server for repo_name={server_info.repo_name}")
repo_config = RepoConfig(
name=DefaultRepoConfig.name,
full_name=DefaultRepoConfig.full_name,
base_dir=os.path.dirname(DefaultRepoConfig.path),
language=ProgrammingLanguage(DefaultRepoConfig.language.upper()),
name=default_repo_config.name,
full_name=default_repo_config.full_name,
base_dir=os.path.dirname(default_repo_config.path),
language=ProgrammingLanguage(default_repo_config.language.upper()),
)
runner = SandboxRunner(repo_config=repo_config, access_token=DefaultSecrets.github_token)
runner = SandboxRunner(repo_config=repo_config)
server_info.warmup_state = WarmupState.PENDING
await runner.warmup()
server_info.warmup_state = WarmupState.COMPLETED
Expand Down
3 changes: 1 addition & 2 deletions src/codegen/sdk/code_generation/codegen_sdk_codebase.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import os.path

from codegen.configs.models.codebase import DefaultCodebaseConfig
from codegen.sdk.code_generation.current_code_codebase import get_codegen_codebase_base_path, get_current_code_codebase
from codegen.sdk.core.codebase import Codebase

Expand All @@ -12,5 +11,5 @@ def get_codegen_sdk_subdirectories() -> list[str]:

def get_codegen_sdk_codebase() -> Codebase:
"""Grabs a Codebase w/ GraphSitter content. Responsible for figuring out where it is, e.g. in Modal or local"""
codebase = get_current_code_codebase(DefaultCodebaseConfig, subdirectories=get_codegen_sdk_subdirectories())
codebase = get_current_code_codebase(subdirectories=get_codegen_sdk_subdirectories())
return codebase
Loading

0 comments on commit b5ef76e

Please sign in to comment.