Skip to content

Commit 76104c6

Browse files
authored
Rpatel/codebase snapshot (#698)
# Motivation <!-- Why is this change necessary? --> # Content <!-- Please include a summary of the change --> # Testing <!-- How was the change tested? --> # Please check the following before marking your PR as ready for review - [ ] I have added tests for my changes - [ ] I have updated the documentation or added new documentation as needed --------- Co-authored-by: rushilpatel0 <[email protected]>
1 parent de7f33a commit 76104c6

File tree

21 files changed

+3774
-64
lines changed

21 files changed

+3774
-64
lines changed

codegen-examples/examples/codegen_app/app.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
########################################################################################################################
1717

1818
# Create the cg_app
19-
cg = CodegenApp(name="codegen-test", repos=["codegen-sh/Kevin-s-Adventure-Game"])
19+
cg = CodegenApp(name="codegen-test", repo="codegen-sh/Kevin-s-Adventure-Game")
2020

2121

2222
@cg.slack.event("app_mention")
@@ -26,7 +26,7 @@ async def handle_mention(event: SlackEvent):
2626

2727
# Codebase
2828
logger.info("[CODEBASE] Initializing codebase")
29-
codebase = cg.get_codebase("codegen-sh/Kevin-s-Adventure-Game")
29+
codebase = cg.get_codebase()
3030

3131
# Code Agent
3232
logger.info("[CODE_AGENT] Initializing code agent")
@@ -43,7 +43,7 @@ async def handle_mention(event: SlackEvent):
4343
def handle_pr(event: PullRequestLabeledEvent):
4444
logger.info("PR labeled")
4545
logger.info(f"PR head sha: {event.pull_request.head.sha}")
46-
codebase = cg.get_codebase("codegen-sh/Kevin-s-Adventure-Game")
46+
codebase = cg.get_codebase()
4747

4848
# =====[ Check out commit ]=====
4949
# Might require fetch?
@@ -62,7 +62,7 @@ def handle_pr(event: PullRequestLabeledEvent):
6262
@cg.linear.event("Issue")
6363
def handle_issue(event: LinearEvent):
6464
logger.info(f"Issue created: {event}")
65-
codebase = cg.get_codebase("codegen-sh/Kevin-s-Adventure-Game")
65+
codebase = cg.get_codebase()
6666
return {"message": "Linear Issue event", "num_files": len(codebase.files), "num_functions": len(codebase.functions)}
6767

6868

@@ -74,7 +74,7 @@ def handle_issue(event: LinearEvent):
7474

7575
# For deploying local package
7676
REPO_URL = "https://github.com/codegen-sh/codegen-sdk.git"
77-
COMMIT_ID = "26dafad2c319968e14b90806d42c6c7aaa627bb0"
77+
COMMIT_ID = "6a0e101718c247c01399c60b7abf301278a41786"
7878

7979
# Create the base image with dependencies
8080
base_image = (
@@ -97,4 +97,5 @@ def handle_issue(event: LinearEvent):
9797
@app.function(image=base_image, secrets=[modal.Secret.from_dotenv()])
9898
@modal.asgi_app()
9999
def fastapi_app():
100+
print("Starting codegen fastapi app")
100101
return cg.app
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from app import app
2+
3+
app = app
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
ANTHROPIC_API_KEY="..."
2+
SLACK_BOT_TOKEN="..."
3+
GITHUB_TOKEN="..."

codegen-examples/examples/snapshot_event_handler/README.md

Whitespace-only changes.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from event_handlers import app
2+
3+
app = app
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
from codegen.agents.code_agent import CodeAgent
2+
from codegen.extensions.events.codegen_app import CodegenApp
3+
from codegen.extensions.linear.types import LinearEvent
4+
from codegen.extensions.slack.types import SlackEvent
5+
from codegen.extensions.events.modal.base import CodebaseEventsApp, EventRouterMixin
6+
from codegen.extensions.github.types.pull_request import PullRequestLabeledEvent
7+
from pr_tasks import lint_for_dev_import_violations, review_with_codegen_agent
8+
from typing import Literal
9+
from dotenv import load_dotenv
10+
from fastapi import FastAPI, Request
11+
from classy_fastapi import Routable, post
12+
import modal
13+
import logging
14+
15+
load_dotenv(".env")
16+
17+
18+
logging.basicConfig(level=logging.INFO, force=True)
19+
logger = logging.getLogger(__name__)
20+
21+
codegen_events_app = modal.App("codegen-events-router")
22+
23+
SNAPSHOT_DICT_ID = "codegen-events-codebase-snapshots"
24+
25+
26+
REPO_URL = "https://github.com/codegen-sh/codegen-sdk.git"
27+
COMMIT_ID = "f398107d31bbd53fc77bc9c5f8763d2dc8fcae5b"
28+
29+
# Create the base image with dependencies
30+
base_image = (
31+
modal.Image.debian_slim(python_version="3.13")
32+
.apt_install("git")
33+
.pip_install(
34+
# =====[ Codegen ]=====
35+
# "codegen",
36+
f"git+{REPO_URL}@{COMMIT_ID}",
37+
# =====[ Rest ]=====
38+
"openai>=1.1.0",
39+
"fastapi[standard]",
40+
"slack_sdk",
41+
"classy-fastapi>=0.6.1",
42+
)
43+
)
44+
45+
46+
event_handlers_app = modal.App("codegen-event-handlers")
47+
48+
49+
@event_handlers_app.cls(image=base_image, secrets=[modal.Secret.from_dotenv(".env")], enable_memory_snapshot=True, container_idle_timeout=300)
50+
class CustomEventHandlersAPI(CodebaseEventsApp):
51+
commit: str = modal.parameter(default="79114f67ccfe8700416cd541d1c7c43659a95342")
52+
repo_org: str = modal.parameter(default="codegen-sh")
53+
repo_name: str = modal.parameter(default="Kevin-s-Adventure-Game")
54+
snapshot_index_id: str = SNAPSHOT_DICT_ID
55+
56+
def setup_handlers(self, cg: CodegenApp):
57+
@cg.slack.event("app_mention")
58+
async def handle_mention(event: SlackEvent):
59+
logger.info("[APP_MENTION] Received cg_app_mention event")
60+
61+
# Codebase
62+
logger.info("[CODEBASE] Initializing codebase")
63+
codebase = cg.get_codebase()
64+
65+
# Code Agent
66+
logger.info("[CODE_AGENT] Initializing code agent")
67+
agent = CodeAgent(codebase=codebase)
68+
69+
logger.info("[CODE_AGENT] Running code agent")
70+
response = agent.run(event.text)
71+
72+
cg.slack.client.chat_postMessage(channel=event.channel, text=response, thread_ts=event.ts)
73+
74+
return {"message": "Mentioned", "received_text": event.text, "response": response}
75+
76+
@cg.github.event("pull_request:labeled")
77+
def handle_pr(event: PullRequestLabeledEvent):
78+
logger.info("PR labeled")
79+
logger.info(f"PR head sha: {event.pull_request.head.sha}")
80+
81+
codebase = cg.get_codebase()
82+
logger.info(f"Codebase: {codebase.name} codebase.repo: {codebase.repo_path}")
83+
84+
# =====[ Check out commit ]=====
85+
# Might require fetch?
86+
logger.info("> Checking out commit")
87+
codebase.checkout(commit=event.pull_request.head.sha)
88+
89+
logger.info("> Running PR Lints")
90+
# LINT CODEMOD
91+
lint_for_dev_import_violations(codebase, event)
92+
93+
# REVIEW CODEMOD
94+
review_with_codegen_agent(codebase, event)
95+
96+
return {"message": "PR event handled", "num_files": len(codebase.files), "num_functions": len(codebase.functions)}
97+
98+
@cg.linear.event("Issue")
99+
def handle_issue(event: LinearEvent):
100+
logger.info(f"Issue created: {event}")
101+
codebase = cg.get_codebase()
102+
return {"message": "Linear Issue event", "num_files": len(codebase.files), "num_functions": len(codebase.functions)}
103+
104+
105+
@codegen_events_app.cls(image=base_image, secrets=[modal.Secret.from_dotenv(".env")])
106+
class WebhookEventRouterAPI(EventRouterMixin, Routable):
107+
snapshot_index_id: str = SNAPSHOT_DICT_ID
108+
109+
def get_event_handler_cls(self):
110+
modal_cls = modal.Cls.from_name(app_name="Events", name="CustomEventHandlersAPI")
111+
return modal_cls
112+
113+
@post("/{org}/{repo}/{provider}/events")
114+
async def handle_event(self, org: str, repo: str, provider: Literal["slack", "github", "linear"], request: Request):
115+
# Define the route for the webhook url sink, it will need to indicate the repo repo org, and the provider
116+
return await super().handle_event(org, repo, provider, request)
117+
118+
@modal.asgi_app()
119+
def api(self):
120+
"""Run the FastAPI app with the Router."""
121+
event_api = FastAPI()
122+
route_view = WebhookEventRouterAPI()
123+
event_api.include_router(route_view.router)
124+
return event_api
125+
126+
127+
# Setup a cron job to trigger updates to the codebase snapshots.
128+
@codegen_events_app.function(schedule=modal.Cron("*/10 * * * *"), image=base_image, secrets=[modal.Secret.from_dotenv(".env")])
129+
def refresh_repository_snapshots():
130+
WebhookEventRouterAPI().refresh_repository_snapshots(snapshot_index_id=SNAPSHOT_DICT_ID)
131+
132+
133+
app = modal.App("Events", secrets=[modal.Secret.from_dotenv(".env")])
134+
app.include(event_handlers_app)
135+
app.include(codegen_events_app)
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import logging
2+
from codegen.agents.code_agent import CodeAgent
3+
from codegen.extensions.github.types.pull_request import PullRequestLabeledEvent
4+
5+
from codegen.extensions.langchain.tools import GithubCreatePRCommentTool, GithubCreatePRReviewCommentTool, GithubViewPRTool
6+
from codegen.sdk.core.codebase import Codebase
7+
8+
logging.basicConfig(level=logging.INFO, force=True)
9+
logger = logging.getLogger(__name__)
10+
11+
12+
def lint_for_dev_import_violations(codebase: Codebase, event: PullRequestLabeledEvent):
13+
patch, commit_shas, modified_symbols = codebase.get_modified_symbols_in_pr(event.pull_request.number)
14+
modified_files = set(commit_shas.keys())
15+
16+
DIR_NAME = "packages/next/src/client/components/react-dev-overlay"
17+
directory = codebase.get_directory(DIR_NAME)
18+
19+
# Initialize a list to store all violations
20+
violations = []
21+
22+
print("modified_files", modified_files)
23+
24+
# Check if directory exists before proceeding
25+
if directory is not None and hasattr(directory, "files"):
26+
for file in directory.files:
27+
print("checking file", file.filepath)
28+
for imp in file.inbound_imports:
29+
print("file", imp.file.filepath)
30+
print("checking import", imp.import_statement)
31+
# Check if the import is from outside the directory and is in the modified files
32+
if imp.file not in directory and imp.file.filepath in modified_files:
33+
# Skip require statements
34+
if "require" in imp.import_statement:
35+
continue
36+
violation = f"- Violation in `{file.filepath}`: Importing from `{imp.file.filepath}` ([link]({imp.github_url}))"
37+
violations.append(violation)
38+
logger.info(f"Found violation: {violation}")
39+
40+
# Only create a PR comment if violations are found
41+
if violations:
42+
review_attention_message = "## Dev Import Violations Found\n\n"
43+
review_attention_message += "The following files have imports that violate development overlay rules:\n\n"
44+
review_attention_message += "\n".join(violations)
45+
review_attention_message += "\n\nPlease ensure that development imports are not imported in production code."
46+
47+
# Create PR comment with the formatted message
48+
codebase._op.create_pr_comment(event.pull_request.number, review_attention_message)
49+
50+
51+
def review_with_codegen_agent(codebase: Codebase, event: PullRequestLabeledEvent):
52+
review_initial_message = "CodegenBot is starting to review the PR please wait..."
53+
comment = codebase._op.create_pr_comment(event.number, review_initial_message)
54+
# Define tools first
55+
pr_tools = [
56+
GithubViewPRTool(codebase),
57+
GithubCreatePRCommentTool(codebase),
58+
GithubCreatePRReviewCommentTool(codebase),
59+
]
60+
61+
# Create agent with the defined tools
62+
agent = CodeAgent(codebase=codebase, tools=pr_tools)
63+
64+
# Using a prompt from SWE Bench
65+
prompt = f"""
66+
Hey CodegenBot!
67+
68+
Here's a SWE task for you. Please Review this pull request!
69+
{event.pull_request.url}
70+
Do not terminate until have reviewed the pull request and are satisfied with your review.
71+
72+
Review this Pull request like the señor ingenier you are
73+
be explicit about the changes, produce a short summary, and point out possible improvements where pressent dont be self congratulatory stick to the facts
74+
use the tools at your disposal to create propper pr reviews include code snippets if needed, and suggest improvements if feel its necesary
75+
"""
76+
# Run the agent
77+
agent.run(prompt)
78+
comment.delete()
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
[project]
2+
name = "codegen-examples"
3+
version = "0.0.0"
4+
readme = "README.md"
5+
requires-python = ">=3.12, <3.14"
6+
dependencies = [
7+
"fastapi-utils>=0.8.0",
8+
"fastapi[standard]>=0.115.9",
9+
"modal>=0.73.72",
10+
"fastapi-restful[all]>=0.6.0",
11+
"classy-fastapi>=0.6.1",
12+
"codegen@git+https://github.com/codegen-sh/codegen-sdk.git@f398107d31bbd53fc77bc9c5f8763d2dc8fcae5b",
13+
]
14+
license = { file = "LICENSE" }
15+
classifiers = [
16+
"License :: OSI Approved :: Apache Software License",
17+
"Intended Audience :: Developers",
18+
"Programming Language :: Python :: 3.12",
19+
"Programming Language :: Python :: 3.13",
20+
"Topic :: Software Development",
21+
"Development Status :: 4 - Beta",
22+
"Environment :: MacOS X",
23+
"Programming Language :: Python :: 3",
24+
"Programming Language :: Python",
25+
]
26+
27+
[tool.ruff]
28+
line-length = 200
29+
exclude = ["**/input_repo/**", "**/output_repo/**", "**/repositories/**"]
30+
31+
[tool.uv]
32+
cache-keys = [{ git = { commit = true, tags = true } }]

0 commit comments

Comments
 (0)