Skip to content

Commit 818ef15

Browse files
authored
feat: CG-10824: simplify config into .env + autoload (#567)
1 parent 0a8aa5c commit 818ef15

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+552
-935
lines changed

.codegen/.gitignore

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@ examples/
44
prompts/
55
jupyter/
66
.venv/
7+
.env
78
codegen-system-prompt.txt
8-
*.txt
9-
*.pyc
109

1110
# Python cache files
1211
__pycache__/
1312
*.py[cod]
1413
*$py.class
14+
*.txt
15+
*.pyc
1516

16-
# Keep config.toml and codemods
17-
!config.toml
17+
# Keep codemods
1818
!codemods/
1919
!codemods/**

.codegen/config.toml

Lines changed: 0 additions & 29 deletions
This file was deleted.

.github/workflows/unit-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ jobs:
141141
timeout-minutes: 5
142142
env:
143143
GITHUB_WORKSPACE: $GITHUB_WORKSPACE
144-
CODEGEN_SECRETS__GITHUB_TOKEN: ${{ secrets.GHA_PAT }}
144+
SECRETS_GITHUB_TOKEN: ${{ secrets.GHA_PAT }}
145145
run: |
146146
uv run pytest \
147147
-n auto \

codegen-examples/examples/pr_review_bot/run.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22

33
import codegen
44
from codegen import Codebase
5-
from codegen.sdk.codebase.config import CodebaseConfig
6-
from codegen.sdk.secrets import Secrets
7-
from codegen.shared.configs.models.feature_flags import CodebaseFeatureFlags
5+
from codegen.shared.configs.models.codebase import CodebaseConfig
6+
from codegen.shared.configs.models.secrets import SecretsConfig
87

98
github_token = "Your github token"
109
open_ai_key = "your open ai key"
@@ -77,12 +76,8 @@ def run(codebase: Codebase):
7776
"getsentry/sentry",
7877
shallow=False,
7978
language="python",
80-
config=CodebaseConfig(
81-
secrets=Secrets(openai_key=open_ai_key, github_api_key=github_token),
82-
feature_flags=CodebaseFeatureFlags(
83-
sync_enabled=True,
84-
),
85-
),
79+
config=CodebaseConfig(sync_enabled=True),
80+
secrets=SecretsConfig(openai_api_key=open_ai_key, github_token=github_token),
8681
)
8782
review = run(codebase)
8883
print(review)

codegen-examples/examples/sqlalchemy_soft_delete/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ This codemod includes support for running without the graph feature enabled. Thi
127127
To run in no-graph mode:
128128

129129
```python
130-
codebase = Codebase(str(repo_path), language="python", config=CodebaseConfig(feature_flags=GSFeatureFlags(disable_graph=True)))
130+
codebase = Codebase(str(repo_path), language="python", config=CodebaseConfig(disable_graph=True))
131131
```
132132

133133
## Running the Conversion

codegen-examples/examples/sqlalchemy_soft_delete/run.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
from pathlib import Path
44

55
import codegen
6-
from codegen import Codebase
76
from codegen.sdk.core.detached_symbols.function_call import FunctionCall
8-
from codegen.shared.configs.models.feature_flags import CodebaseFeatureFlags
97

108

119
def should_process_join_call(call, soft_delete_models, join_methods):
@@ -93,15 +91,15 @@ def process_soft_deletes(codebase):
9391

9492
if __name__ == "__main__":
9593
from codegen import Codebase
96-
from codegen.sdk.codebase.config import CodebaseConfig
94+
from codegen.shared.configs.models.codebase import CodebaseConfig
9795

9896
repo_path = Path("/tmp/core")
9997
repo_url = "https://github.com/hasgeek/funnel.git"
10098

10199
try:
102100
clone_repo(repo_url, repo_path)
103101
subprocess.run(["git", "-C", str(repo_path), "checkout", "8454e15"], check=True)
104-
codebase = Codebase(str(repo_path), language="python", config=CodebaseConfig(feature_flags=CodebaseFeatureFlags(disable_graph=True)))
102+
codebase = Codebase(str(repo_path), language="python", config=CodebaseConfig(disable_graph=True))
105103
process_soft_deletes(codebase)
106104
finally:
107105
shutil.rmtree(repo_path)

docs/building-with-codegen/dot-codegen.mdx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,12 @@ The environment is created during `codegen init` and used by commands like `code
4646

4747
### Configuration
4848

49-
The `config.toml` file stores your project settings:
49+
The `.env` file stores your project settings:
5050

51-
```toml
52-
organization_name = "your-org"
53-
repo_name = "your-repo"
54-
programming_language = "python" # or other supported language
51+
```env
52+
REPOSITORY_OWNER = "your-org"
53+
REPOSITORY_PATH = "/root/git/your-repo"
54+
REPOSITORY_LANGUAGE = "python" # or other supported language
5555
```
5656

5757
This configuration is used by Codegen to provide language-specific features and proper repository context.

docs/building-with-codegen/parsing-codebases.mdx

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,21 +69,19 @@ You can customize the behavior of your Codebase instance by passing a `CodebaseC
6969

7070
```python
7171
from codegen import Codebase
72-
from codegen.sdk.codebase.config import CodebaseConfig, Secrets
72+
from codegen.shared.configs.models.codebase import CodebaseConfig
73+
from codegen.shared.configs.models.secrets import SecretsConfig
7374

7475
codebase = Codebase(
7576
"path/to/repository",
76-
config=CodebaseConfig(
77-
secrets=Secrets(
78-
openai_key="your-openai-key" # For AI-powered features
79-
),
80-
)
77+
config=CodebaseConfig(debug=True),
78+
secrets=SecretsConfig(openai_api_key="your-openai-key") # For AI-powered features
8179
)
8280
```
8381

84-
The `CodebaseConfig` allows you to configure:
85-
- `secrets`: API keys and other sensitive information needed by the codebase
86-
- `feature_flags`: Toggle specific features like language engines, dependency management, and graph synchronization
82+
- `CodebaseConfig` and `SecretsConfig` allow you to configure
83+
- `config`: Toggle specific features like language engines, dependency management, and graph synchronization
84+
- `secrets`: API keys and other sensitive information needed by the codebase
8785

8886
For a complete list of available feature flags and configuration options, see the [source code on GitHub](https://github.com/codegen-sh/codegen-sdk/blob/develop/src/codegen/sdk/codebase/config.py).
8987

pyproject.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ dependencies = [
5050
"pygit2>=1.16.0",
5151
"unidiff>=0.7.5",
5252
"datamodel-code-generator>=0.26.5",
53-
"toml>=0.10.2",
5453
"PyGithub==2.6.0",
5554
"GitPython==3.1.44",
5655
"psutil>=5.8.0",
@@ -141,7 +140,6 @@ dev-dependencies = [
141140
"pre-commit-uv>=4.1.4",
142141
"austin-dist>=3.7.0",
143142
"uv>=0.4.25",
144-
"cython>=3.0.11",
145143
"deptry>=0.22.0",
146144
"cibuildwheel[uv]>=2.22.0",
147145
"sybil[pytest]>=9.0.0",
@@ -158,6 +156,7 @@ dev-dependencies = [
158156
"jupyterlab>=4.3.5",
159157
"modal>=0.73.25",
160158
"pytest-lsp>=1.0.0b1",
159+
"cython>=3.0.11",
161160
]
162161

163162
[tool.uv.workspace]

src/codegen/cli/auth/session.py

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
from codegen.cli.git.repo import get_git_repo
99
from codegen.cli.rich.codeblocks import format_command
1010
from codegen.git.repo_operator.local_git_repo import LocalGitRepo
11-
from codegen.shared.configs.constants import CODEGEN_DIR_NAME, CONFIG_FILENAME
12-
from codegen.shared.configs.models.session import SessionConfig
13-
from codegen.shared.configs.session_configs import global_config, load_session_config
11+
from codegen.shared.configs.constants import CODEGEN_DIR_NAME, ENV_FILENAME
12+
from codegen.shared.configs.session_manager import session_manager
13+
from codegen.shared.configs.user_config import UserConfig
1414

1515

1616
class CodegenSession:
@@ -19,7 +19,7 @@ class CodegenSession:
1919
repo_path: Path
2020
local_git: LocalGitRepo
2121
codegen_dir: Path
22-
config: SessionConfig
22+
config: UserConfig
2323
existing: bool
2424

2525
def __init__(self, repo_path: Path, git_token: str | None = None) -> None:
@@ -30,16 +30,16 @@ def __init__(self, repo_path: Path, git_token: str | None = None) -> None:
3030
self.repo_path = repo_path
3131
self.local_git = LocalGitRepo(repo_path=repo_path)
3232
self.codegen_dir = repo_path / CODEGEN_DIR_NAME
33-
self.config = load_session_config(self.codegen_dir / CONFIG_FILENAME)
33+
self.config = UserConfig(env_filepath=self.codegen_dir / ENV_FILENAME)
3434
self.config.secrets.github_token = git_token or self.config.secrets.github_token
35-
self.existing = global_config.get_session(repo_path) is not None
35+
self.existing = session_manager.get_session(repo_path) is not None
3636

3737
self._initialize()
38-
global_config.set_active_session(repo_path)
38+
session_manager.set_active_session(repo_path)
3939

4040
@classmethod
4141
def from_active_session(cls) -> "CodegenSession | None":
42-
active_session = global_config.get_active_session()
42+
active_session = session_manager.get_active_session()
4343
if not active_session:
4444
return None
4545

@@ -49,9 +49,8 @@ def _initialize(self) -> None:
4949
"""Initialize the codegen session"""
5050
self._validate()
5151

52-
self.config.repository.repo_path = self.config.repository.repo_path or str(self.local_git.repo_path)
53-
self.config.repository.repo_name = self.config.repository.repo_name or self.local_git.name
54-
self.config.repository.full_name = self.config.repository.full_name or self.local_git.full_name
52+
self.config.repository.path = self.config.repository.path or str(self.local_git.repo_path)
53+
self.config.repository.owner = self.config.repository.owner or self.local_git.owner
5554
self.config.repository.user_name = self.config.repository.user_name or self.local_git.user_name
5655
self.config.repository.user_email = self.config.repository.user_email or self.local_git.user_email
5756
self.config.repository.language = self.config.repository.language or self.local_git.get_language(access_token=self.config.secrets.github_token).upper()
@@ -60,20 +59,13 @@ def _initialize(self) -> None:
6059
def _validate(self) -> None:
6160
"""Validates that the session configuration is correct, otherwise raises an error"""
6261
if not self.codegen_dir.exists():
63-
rich.print(f"\n[bold red]Error:[/bold red] Codegen folder is missing at {self.codegen_dir}")
64-
raise click.Abort()
65-
66-
if not Path(self.config.file_path).exists():
67-
rich.print(f"\n[bold red]Error:[/bold red] Missing config.toml at {self.codegen_dir}")
68-
rich.print("[white]Please remove the codegen folder and reinitialize.[/white]")
69-
rich.print(format_command(f"rm -rf {self.codegen_dir} && codegen init"))
70-
raise click.Abort()
62+
self.codegen_dir.mkdir(parents=True, exist_ok=True)
7163

7264
git_token = self.config.secrets.github_token
7365
if git_token is None:
7466
rich.print("\n[bold yellow]Warning:[/bold yellow] GitHub token not found")
7567
rich.print("To enable full functionality, please set your GitHub token:")
76-
rich.print(format_command("export CODEGEN_SECRETS__GITHUB_TOKEN=<your-token>"))
68+
rich.print(format_command("export SECRETS_GITHUB_TOKEN=<your-token>"))
7769
rich.print("Or pass in as a parameter:")
7870
rich.print(format_command("codegen init --token <your-token>"))
7971

src/codegen/cli/commands/config/main.py

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
import rich_click as click
66
from rich.table import Table
77

8-
from codegen.cli.auth.session import CodegenSession
9-
from codegen.cli.workspace.decorators import requires_init
10-
from codegen.shared.configs.session_configs import global_config
8+
from codegen.shared.configs.constants import CODEGEN_DIR_NAME, ENV_FILENAME, GLOBAL_ENV_FILE
9+
from codegen.shared.configs.session_manager import session_manager
10+
from codegen.shared.configs.user_config import UserConfig
1111

1212

1313
@click.group(name="config")
@@ -17,13 +17,9 @@ def config_command():
1717

1818

1919
@config_command.command(name="list")
20-
@requires_init
2120
@click.option("--global", "is_global", is_flag=True, help="Lists the global configuration values")
22-
def list_command(session: CodegenSession, is_global: bool):
21+
def list_command(is_global: bool):
2322
"""List current configuration values."""
24-
table = Table(title="Configuration Values", border_style="blue", show_header=True)
25-
table.add_column("Key", style="cyan", no_wrap=True)
26-
table.add_column("Value", style="magenta")
2723

2824
def flatten_dict(data: dict, prefix: str = "") -> dict:
2925
items = {}
@@ -38,60 +34,70 @@ def flatten_dict(data: dict, prefix: str = "") -> dict:
3834
items[full_key] = value
3935
return items
4036

41-
# Get flattened config and sort by keys
42-
config = global_config.global_session if is_global else session.config
43-
flat_config = flatten_dict(config.model_dump())
37+
config = _get_user_config(is_global)
38+
flat_config = flatten_dict(config.to_dict())
4439
sorted_items = sorted(flat_config.items(), key=lambda x: x[0])
4540

46-
# Group by top-level prefix
41+
# Create table
42+
table = Table(title="Configuration Values", border_style="blue", show_header=True, title_justify="center")
43+
table.add_column("Key", style="cyan", no_wrap=True)
44+
table.add_column("Value", style="magenta")
45+
46+
# Group by prefix (before underscore)
4747
def get_prefix(item):
48-
return item[0].split(".")[0]
48+
return item[0].split("_")[0]
4949

5050
for prefix, group in groupby(sorted_items, key=get_prefix):
5151
table.add_section()
52-
table.add_row(f"[bold yellow]{prefix}[/bold yellow]", "")
52+
table.add_row(f"[bold yellow]{prefix.title()}[/bold yellow]", "")
5353
for key, value in group:
54-
# Remove the prefix from the displayed key
55-
display_key = key[len(prefix) + 1 :] if "." in key else key
56-
table.add_row(f" {display_key}", str(value))
54+
table.add_row(f" {key}", str(value))
5755

5856
rich.print(table)
5957

6058

6159
@config_command.command(name="get")
62-
@requires_init
6360
@click.argument("key")
6461
@click.option("--global", "is_global", is_flag=True, help="Get the global configuration value")
65-
def get_command(session: CodegenSession, key: str, is_global: bool):
62+
def get_command(key: str, is_global: bool):
6663
"""Get a configuration value."""
67-
config = global_config.global_session if is_global else session.config
68-
value = config.get(key)
69-
if value is None:
64+
config = _get_user_config(is_global)
65+
if not config.has_key(key):
7066
rich.print(f"[red]Error: Configuration key '{key}' not found[/red]")
7167
return
7268

73-
rich.print(f"[cyan]{key}[/cyan] = [magenta]{value}[/magenta]")
69+
value = config.get(key)
70+
71+
rich.print(f"[cyan]{key}[/cyan]=[magenta]{value}[/magenta]")
7472

7573

7674
@config_command.command(name="set")
77-
@requires_init
7875
@click.argument("key")
7976
@click.argument("value")
8077
@click.option("--global", "is_global", is_flag=True, help="Sets the global configuration value")
81-
def set_command(session: CodegenSession, key: str, value: str, is_global: bool):
82-
"""Set a configuration value and write to config.toml."""
83-
config = global_config.global_session if is_global else session.config
84-
cur_value = config.get(key)
85-
if cur_value is None:
78+
def set_command(key: str, value: str, is_global: bool):
79+
"""Set a configuration value and write to .env"""
80+
config = _get_user_config(is_global)
81+
if not config.has_key(key):
8682
rich.print(f"[red]Error: Configuration key '{key}' not found[/red]")
8783
return
8884

89-
if cur_value.lower() != value.lower():
85+
cur_value = config.get(key)
86+
if cur_value is None or cur_value.lower() != value.lower():
9087
try:
9188
config.set(key, value)
9289
except Exception as e:
9390
logging.exception(e)
9491
rich.print(f"[red]{e}[/red]")
9592
return
9693

97-
rich.print(f"[green]Successfully set {key}=[magenta]{value}[/magenta] and saved to config.toml[/green]")
94+
rich.print(f"[green]Successfully set {key}=[magenta]{value}[/magenta] and saved to .env[/green]")
95+
96+
97+
def _get_user_config(is_global: bool) -> UserConfig:
98+
if is_global or (active_session_path := session_manager.get_active_session()) is None:
99+
env_filepath = GLOBAL_ENV_FILE
100+
else:
101+
env_filepath = active_session_path / CODEGEN_DIR_NAME / ENV_FILENAME
102+
103+
return UserConfig(env_filepath)

0 commit comments

Comments
 (0)