forked from cardosofelipe/fast-next-template
- Add Celery app configuration with Redis broker/backend - Add task modules: agent, workflow, cost, git, sync - Add task stubs for: - Agent execution (spawn, heartbeat, terminate) - Workflow orchestration (start sprint, checkpoint, code review) - Cost tracking (record usage, calculate, generate report) - Git operations (clone, commit, push, sync) - External sync (import issues, export updates) - Add task tests directory structure - Configure for production-ready Celery setup Implements #18 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
226 lines
5.6 KiB
Python
226 lines
5.6 KiB
Python
# app/tasks/git.py
|
|
"""
|
|
Git operation tasks for Syndarix.
|
|
|
|
These tasks handle Git operations for projects:
|
|
- Cloning repositories
|
|
- Creating branches
|
|
- Committing changes
|
|
- Pushing to remotes
|
|
- Creating pull requests
|
|
|
|
Tasks are routed to the 'git' queue for dedicated processing.
|
|
All operations are scoped by project_id for multi-tenancy.
|
|
"""
|
|
|
|
import logging
|
|
from typing import Any
|
|
|
|
from app.celery_app import celery_app
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@celery_app.task(bind=True, name="app.tasks.git.clone_repository")
|
|
def clone_repository(
|
|
self,
|
|
project_id: str,
|
|
repo_url: str,
|
|
branch: str = "main",
|
|
) -> dict[str, Any]:
|
|
"""
|
|
Clone a repository for a project.
|
|
|
|
This task clones a Git repository to the project workspace:
|
|
1. Prepare workspace directory
|
|
2. Clone repository with credentials
|
|
3. Checkout specified branch
|
|
4. Update project metadata
|
|
|
|
Args:
|
|
project_id: UUID of the project
|
|
repo_url: Git repository URL (HTTPS or SSH)
|
|
branch: Branch to checkout (default: main)
|
|
|
|
Returns:
|
|
dict with status and project_id
|
|
"""
|
|
logger.info(
|
|
f"Cloning repository {repo_url} for project {project_id} on branch {branch}"
|
|
)
|
|
|
|
# TODO: Implement repository cloning
|
|
# This will involve:
|
|
# 1. Getting project credentials from secrets store
|
|
# 2. Creating workspace directory
|
|
# 3. Running git clone with proper auth
|
|
# 4. Checking out the target branch
|
|
# 5. Updating project record with clone status
|
|
|
|
return {
|
|
"status": "pending",
|
|
"project_id": project_id,
|
|
}
|
|
|
|
|
|
@celery_app.task(bind=True, name="app.tasks.git.commit_changes")
|
|
def commit_changes(
|
|
self,
|
|
project_id: str,
|
|
message: str,
|
|
files: list[str] | None = None,
|
|
) -> dict[str, Any]:
|
|
"""
|
|
Commit changes in a project repository.
|
|
|
|
This task creates a Git commit:
|
|
1. Stage specified files (or all if None)
|
|
2. Create commit with message
|
|
3. Update commit history record
|
|
|
|
Args:
|
|
project_id: UUID of the project
|
|
message: Commit message (follows conventional commits)
|
|
files: List of files to stage, or None for all staged
|
|
|
|
Returns:
|
|
dict with status and project_id
|
|
"""
|
|
logger.info(
|
|
f"Committing changes for project {project_id}: {message}"
|
|
)
|
|
|
|
# TODO: Implement commit operation
|
|
# This will involve:
|
|
# 1. Loading project workspace path
|
|
# 2. Running git add for specified files
|
|
# 3. Running git commit with message
|
|
# 4. Recording commit hash in database
|
|
|
|
return {
|
|
"status": "pending",
|
|
"project_id": project_id,
|
|
}
|
|
|
|
|
|
@celery_app.task(bind=True, name="app.tasks.git.create_branch")
|
|
def create_branch(
|
|
self,
|
|
project_id: str,
|
|
branch_name: str,
|
|
from_ref: str = "HEAD",
|
|
) -> dict[str, Any]:
|
|
"""
|
|
Create a new branch in a project repository.
|
|
|
|
This task creates a Git branch:
|
|
1. Checkout from reference
|
|
2. Create new branch
|
|
3. Update branch tracking
|
|
|
|
Args:
|
|
project_id: UUID of the project
|
|
branch_name: Name of the new branch (e.g., feature/123-description)
|
|
from_ref: Reference to branch from (default: HEAD)
|
|
|
|
Returns:
|
|
dict with status and project_id
|
|
"""
|
|
logger.info(
|
|
f"Creating branch {branch_name} from {from_ref} for project {project_id}"
|
|
)
|
|
|
|
# TODO: Implement branch creation
|
|
# This will involve:
|
|
# 1. Loading project workspace
|
|
# 2. Running git checkout -b from_ref
|
|
# 3. Recording branch in database
|
|
|
|
return {
|
|
"status": "pending",
|
|
"project_id": project_id,
|
|
}
|
|
|
|
|
|
@celery_app.task(bind=True, name="app.tasks.git.create_pull_request")
|
|
def create_pull_request(
|
|
self,
|
|
project_id: str,
|
|
title: str,
|
|
body: str,
|
|
head_branch: str,
|
|
base_branch: str = "main",
|
|
) -> dict[str, Any]:
|
|
"""
|
|
Create a pull request for a project.
|
|
|
|
This task creates a PR on the external Git provider:
|
|
1. Push branch if needed
|
|
2. Create PR via API (Gitea, GitHub, GitLab)
|
|
3. Store PR reference
|
|
|
|
Args:
|
|
project_id: UUID of the project
|
|
title: PR title
|
|
body: PR description (markdown)
|
|
head_branch: Branch with changes
|
|
base_branch: Target branch (default: main)
|
|
|
|
Returns:
|
|
dict with status and project_id
|
|
"""
|
|
logger.info(
|
|
f"Creating PR '{title}' from {head_branch} to {base_branch} for project {project_id}"
|
|
)
|
|
|
|
# TODO: Implement PR creation
|
|
# This will involve:
|
|
# 1. Loading project and Git provider config
|
|
# 2. Ensuring head_branch is pushed
|
|
# 3. Calling provider API to create PR
|
|
# 4. Storing PR URL and number
|
|
|
|
return {
|
|
"status": "pending",
|
|
"project_id": project_id,
|
|
}
|
|
|
|
|
|
@celery_app.task(bind=True, name="app.tasks.git.push_changes")
|
|
def push_changes(
|
|
self,
|
|
project_id: str,
|
|
branch: str,
|
|
force: bool = False,
|
|
) -> dict[str, Any]:
|
|
"""
|
|
Push changes to remote repository.
|
|
|
|
This task pushes commits to the remote:
|
|
1. Verify authentication
|
|
2. Push branch to remote
|
|
3. Handle push failures
|
|
|
|
Args:
|
|
project_id: UUID of the project
|
|
branch: Branch to push
|
|
force: Whether to force push (use with caution)
|
|
|
|
Returns:
|
|
dict with status and project_id
|
|
"""
|
|
logger.info(
|
|
f"Pushing branch {branch} for project {project_id} (force={force})"
|
|
)
|
|
|
|
# TODO: Implement push operation
|
|
# This will involve:
|
|
# 1. Loading project credentials
|
|
# 2. Running git push (with --force if specified)
|
|
# 3. Handling authentication and conflicts
|
|
|
|
return {
|
|
"status": "pending",
|
|
"project_id": project_id,
|
|
}
|