Skip to content

chore: config feedback #610

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Feb 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -15,7 +15,7 @@
user_email: str | None = None

def __init__(self, prefix: str = "REPOSITORY", *args, **kwargs) -> None:
super().__init__(prefix=prefix, *args, **kwargs)

Check failure on line 18 in src/codegen/configs/models/repository.py

View workflow job for this annotation

GitHub Actions / mypy

error: "__init__" of "BaseConfig" gets multiple values for keyword argument "prefix" [misc]

def _initialize(
self,
Expand All @@ -26,17 +26,14 @@

@property
def base_dir(self) -> str:
return os.path.dirname(self.path)

Check failure on line 29 in src/codegen/configs/models/repository.py

View workflow job for this annotation

GitHub Actions / mypy

error: Value of type variable "AnyOrLiteralStr" of "dirname" cannot be "str | None" [type-var]

Check failure on line 29 in src/codegen/configs/models/repository.py

View workflow job for this annotation

GitHub Actions / mypy

error: Incompatible return value type (got "str | None", expected "str") [return-value]

@property
def name(self) -> str:
return os.path.basename(self.path)

Check failure on line 33 in src/codegen/configs/models/repository.py

View workflow job for this annotation

GitHub Actions / mypy

error: Value of type variable "AnyOrLiteralStr" of "basename" cannot be "str | None" [type-var]

Check failure on line 33 in src/codegen/configs/models/repository.py

View workflow job for this annotation

GitHub Actions / mypy

error: Incompatible return value type (got "str | None", expected "str") [return-value]

@property
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 @@ -9,11 +9,8 @@
"""

def __init__(self, prefix: str = "", *args, **kwargs) -> None:
super().__init__(prefix=prefix, *args, **kwargs)

Check failure on line 12 in src/codegen/configs/models/secrets.py

View workflow job for this annotation

GitHub Actions / mypy

error: "__init__" of "BaseConfig" gets multiple values for keyword argument "prefix" [misc]

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 @@ -48,7 +48,7 @@
with open(SESSION_FILE, "w") as f:
json.dump(self.__dict__(), f)

def __dict__(self) -> dict:

Check failure on line 51 in src/codegen/configs/session_manager.py

View workflow job for this annotation

GitHub Actions / mypy

error: Signature of "__dict__" incompatible with supertype "object" [override]
return {
"active_session_path": self.active_session_path,
"sessions": self.sessions,
Expand All @@ -58,37 +58,7 @@
active = self.active_session_path or "None"
sessions_str = "\n ".join(self.sessions) if self.sessions else "None"

return f"GlobalConfig:\n Active Session: {active}\n Sessions:\n {sessions_str}\n Global Session:\n {self.session_config}"

Check failure on line 61 in src/codegen/configs/session_manager.py

View workflow job for this annotation

GitHub Actions / mypy

error: "SessionManager" has no attribute "session_config" [attr-defined]


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 @@
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)

Check failure on line 35 in src/codegen/git/clients/git_repo_client.py

View workflow job for this annotation

GitHub Actions / mypy

error: Argument "token" to "_create_github_client" of "GitRepoClient" has incompatible type "str | None"; expected "str" [arg-type]
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
Loading