-
Notifications
You must be signed in to change notification settings - Fork 531
Repo manager with parsing logic #566
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
Changes from all commits
425dd9f
bfe3a00
9dba217
a9c970d
c4a221e
112c048
86856fa
6dffafa
f4c8909
e2dd43f
2ac1c8e
18e143f
1525055
d29a1ac
006e76d
09d35f7
c3bec4f
c7837af
873fa2c
efa2e91
2b027a2
8332239
6a2d1a4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,13 +5,18 @@ | |||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| from dotenv import load_dotenv | ||||||||||||||||||||||||||||||||||
| from fastapi import HTTPException | ||||||||||||||||||||||||||||||||||
| from sqlalchemy import or_, select | ||||||||||||||||||||||||||||||||||
| from sqlalchemy.ext.asyncio import AsyncSession | ||||||||||||||||||||||||||||||||||
| from sqlalchemy import select, or_ | ||||||||||||||||||||||||||||||||||
| from sqlalchemy.orm import Session | ||||||||||||||||||||||||||||||||||
| from uuid6 import uuid7 | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| from app.celery.tasks.parsing_tasks import process_parsing | ||||||||||||||||||||||||||||||||||
| from app.core.config_provider import config_provider | ||||||||||||||||||||||||||||||||||
| from app.modules.code_provider.code_provider_service import CodeProviderService | ||||||||||||||||||||||||||||||||||
| from app.modules.conversations.conversation.conversation_model import ( | ||||||||||||||||||||||||||||||||||
| Conversation, | ||||||||||||||||||||||||||||||||||
| Visibility, | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| from app.modules.parsing.graph_construction.parsing_helper import ParseHelper | ||||||||||||||||||||||||||||||||||
| from app.modules.parsing.graph_construction.parsing_schema import ( | ||||||||||||||||||||||||||||||||||
| ParsingRequest, | ||||||||||||||||||||||||||||||||||
|
|
@@ -22,14 +27,12 @@ | |||||||||||||||||||||||||||||||||
| validate_parsing_input, | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| from app.modules.parsing.utils.repo_name_normalizer import normalize_repo_name | ||||||||||||||||||||||||||||||||||
| from app.modules.projects.projects_model import Project | ||||||||||||||||||||||||||||||||||
| from app.modules.projects.projects_schema import ProjectStatusEnum | ||||||||||||||||||||||||||||||||||
| from app.modules.projects.projects_service import ProjectService | ||||||||||||||||||||||||||||||||||
| from app.modules.utils.email_helper import EmailHelper | ||||||||||||||||||||||||||||||||||
| from app.modules.utils.posthog_helper import PostHogClient | ||||||||||||||||||||||||||||||||||
| from app.modules.conversations.conversation.conversation_model import Conversation | ||||||||||||||||||||||||||||||||||
| from app.modules.conversations.conversation.conversation_model import Visibility | ||||||||||||||||||||||||||||||||||
| from app.modules.projects.projects_model import Project | ||||||||||||||||||||||||||||||||||
| from app.modules.utils.logger import setup_logger | ||||||||||||||||||||||||||||||||||
| from app.modules.utils.posthog_helper import PostHogClient | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| logger = setup_logger(__name__) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
@@ -40,7 +43,7 @@ class ParsingController: | |||||||||||||||||||||||||||||||||
| @staticmethod | ||||||||||||||||||||||||||||||||||
| @validate_parsing_input | ||||||||||||||||||||||||||||||||||
| async def parse_directory( | ||||||||||||||||||||||||||||||||||
| repo_details: ParsingRequest, db: AsyncSession, user: Dict[str, Any] | ||||||||||||||||||||||||||||||||||
| repo_details: ParsingRequest, db: Session, user: Dict[str, Any] | ||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||
| if "email" not in user: | ||||||||||||||||||||||||||||||||||
| user_email = None | ||||||||||||||||||||||||||||||||||
|
|
@@ -98,21 +101,10 @@ async def parse_directory( | |||||||||||||||||||||||||||||||||
| project_manager, | ||||||||||||||||||||||||||||||||||
| db, | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| demo_repos = [ | ||||||||||||||||||||||||||||||||||
| "Portkey-AI/gateway", | ||||||||||||||||||||||||||||||||||
| "crewAIInc/crewAI", | ||||||||||||||||||||||||||||||||||
| "AgentOps-AI/agentops", | ||||||||||||||||||||||||||||||||||
| "calcom/cal.com", | ||||||||||||||||||||||||||||||||||
| "langchain-ai/langchain", | ||||||||||||||||||||||||||||||||||
| "AgentOps-AI/AgentStack", | ||||||||||||||||||||||||||||||||||
| "formbricks/formbricks", | ||||||||||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||
| # Normalize repository name for consistent database lookups | ||||||||||||||||||||||||||||||||||
| normalized_repo_name = normalize_repo_name(repo_name) | ||||||||||||||||||||||||||||||||||
| logger.info( | ||||||||||||||||||||||||||||||||||
| logger.debug( | ||||||||||||||||||||||||||||||||||
| f"Original repo_name: {repo_name}, Normalized: {normalized_repo_name}" | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
@@ -123,8 +115,15 @@ async def parse_directory( | |||||||||||||||||||||||||||||||||
| repo_path=repo_details.repo_path, | ||||||||||||||||||||||||||||||||||
| commit_id=repo_details.commit_id, | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| # First check if this is a demo project that hasn't been accessed by this user yet | ||||||||||||||||||||||||||||||||||
| demo_repos = [ | ||||||||||||||||||||||||||||||||||
| "Portkey-AI/gateway", | ||||||||||||||||||||||||||||||||||
| "crewAIInc/crewAI", | ||||||||||||||||||||||||||||||||||
| "AgentOps-AI/agentops", | ||||||||||||||||||||||||||||||||||
| "calcom/cal.com", | ||||||||||||||||||||||||||||||||||
| "langchain-ai/langchain", | ||||||||||||||||||||||||||||||||||
| "AgentOps-AI/AgentStack", | ||||||||||||||||||||||||||||||||||
| "formbricks/formbricks", | ||||||||||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||||||||||
| if not project and repo_details.repo_name in demo_repos: | ||||||||||||||||||||||||||||||||||
| existing_project = await project_manager.get_global_project_from_db( | ||||||||||||||||||||||||||||||||||
| normalized_repo_name, | ||||||||||||||||||||||||||||||||||
|
|
@@ -151,11 +150,25 @@ async def parse_directory( | |||||||||||||||||||||||||||||||||
| repo_name | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| asyncio.create_task( | ||||||||||||||||||||||||||||||||||
| task = asyncio.create_task( | ||||||||||||||||||||||||||||||||||
| CodeProviderService(db).get_project_structure_async( | ||||||||||||||||||||||||||||||||||
| new_project_id | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| def _on_structure_done(t: asyncio.Task) -> None: | ||||||||||||||||||||||||||||||||||
| if t.cancelled(): | ||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||
| exc = t.exception() | ||||||||||||||||||||||||||||||||||
| except asyncio.CancelledError: | ||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||
| if exc is not None: | ||||||||||||||||||||||||||||||||||
| logger.exception( | ||||||||||||||||||||||||||||||||||
| "Failed to get project structure", exc_info=exc | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| task.add_done_callback(_on_structure_done) | ||||||||||||||||||||||||||||||||||
| # Duplicate the graph under the new repo ID | ||||||||||||||||||||||||||||||||||
| await parsing_service.duplicate_graph( | ||||||||||||||||||||||||||||||||||
| old_project_id, new_project_id | ||||||||||||||||||||||||||||||||||
|
|
@@ -165,12 +178,24 @@ async def parse_directory( | |||||||||||||||||||||||||||||||||
| await project_manager.update_project_status( | ||||||||||||||||||||||||||||||||||
| new_project_id, ProjectStatusEnum.READY | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| create_task( | ||||||||||||||||||||||||||||||||||
| email_task = create_task( | ||||||||||||||||||||||||||||||||||
| EmailHelper().send_email( | ||||||||||||||||||||||||||||||||||
| user_email, repo_name, repo_details.branch_name | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| def _on_email_done(t: asyncio.Task) -> None: | ||||||||||||||||||||||||||||||||||
| if t.cancelled(): | ||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||
| exc = t.exception() | ||||||||||||||||||||||||||||||||||
| except asyncio.CancelledError: | ||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||
| if exc is not None: | ||||||||||||||||||||||||||||||||||
| logger.exception("Failed to send email", exc_info=exc) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| email_task.add_done_callback(_on_email_done) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||
| "project_id": new_project_id, | ||||||||||||||||||||||||||||||||||
| "status": ProjectStatusEnum.READY.value, | ||||||||||||||||||||||||||||||||||
|
|
@@ -210,8 +235,10 @@ async def parse_directory( | |||||||||||||||||||||||||||||||||
| # If project exists but commit doesn't match or status is not READY, reparse | ||||||||||||||||||||||||||||||||||
| cleanup_graph = True | ||||||||||||||||||||||||||||||||||
| logger.info( | ||||||||||||||||||||||||||||||||||
| f"Submitting parsing task for existing project {project_id} " | ||||||||||||||||||||||||||||||||||
| f"(is_latest={is_latest}, status={project.status})" | ||||||||||||||||||||||||||||||||||
| "Submitting parsing task for existing project.", | ||||||||||||||||||||||||||||||||||
| project_id=project_id, | ||||||||||||||||||||||||||||||||||
| is_latest=is_latest, | ||||||||||||||||||||||||||||||||||
| status=project.status, | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| process_parsing.delay( | ||||||||||||||||||||||||||||||||||
| repo_details.model_dump(), | ||||||||||||||||||||||||||||||||||
|
|
@@ -258,10 +285,10 @@ async def parse_directory( | |||||||||||||||||||||||||||||||||
| async def handle_new_project( | ||||||||||||||||||||||||||||||||||
| repo_details: ParsingRequest, | ||||||||||||||||||||||||||||||||||
| user_id: str, | ||||||||||||||||||||||||||||||||||
| user_email: str, | ||||||||||||||||||||||||||||||||||
| user_email: str | None, | ||||||||||||||||||||||||||||||||||
| new_project_id: str, | ||||||||||||||||||||||||||||||||||
| project_manager: ProjectService, | ||||||||||||||||||||||||||||||||||
| db: AsyncSession, | ||||||||||||||||||||||||||||||||||
| db: Session, | ||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||
|
Comment on lines
286
to
292
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unused If this is intentionally unused, consider renaming to 🧹 Suggested fix- db: Session,
+ _db: Session,📝 Committable suggestion
Suggested change
🧰 Tools🪛 Ruff (0.14.14)[warning] 291-291: Unused static method argument: (ARG004) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
| response = { | ||||||||||||||||||||||||||||||||||
| "project_id": new_project_id, | ||||||||||||||||||||||||||||||||||
|
|
@@ -278,9 +305,9 @@ async def handle_new_project( | |||||||||||||||||||||||||||||||||
| repo_details.commit_id, | ||||||||||||||||||||||||||||||||||
| repo_details.repo_path, | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| asyncio.create_task( | ||||||||||||||||||||||||||||||||||
| CodeProviderService(db).get_project_structure_async(new_project_id) | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| # asyncio.create_task( | ||||||||||||||||||||||||||||||||||
| # CodeProviderService(db).get_project_structure_async(new_project_id) | ||||||||||||||||||||||||||||||||||
| # ) | ||||||||||||||||||||||||||||||||||
| if not user_email: | ||||||||||||||||||||||||||||||||||
| user_email = None | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Skip email task when
user_emailis missing.user_emailis now optional; creating a send task withNonewill just log background errors. Guard it.💡 Suggested fix
🤖 Prompt for AI Agents