Add new file
This commit is contained in:
+192
@@ -0,0 +1,192 @@
|
||||
package action
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/rockliang/poimen/workflows/internal/lock"
|
||||
)
|
||||
|
||||
// CloneRepoInput is input to CloneRepoActivity.
|
||||
type CloneRepoInput struct {
|
||||
RemoteURL string
|
||||
TargetRepoPath string
|
||||
}
|
||||
|
||||
// CloneRepoActivity clones a repo if it doesn't exist, or fetches if it does.
|
||||
func CloneRepoActivity(ctx context.Context, in CloneRepoInput) error {
|
||||
// Check if repo already exists
|
||||
gitDir := filepath.Join(in.TargetRepoPath, ".git")
|
||||
if _, err := os.Stat(gitDir); err == nil {
|
||||
// Repo exists, fetch latest
|
||||
cmd := exec.CommandContext(ctx, "git", "-C", in.TargetRepoPath, "fetch", "origin")
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("git fetch failed: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Repo doesn't exist, clone it
|
||||
cmd := exec.CommandContext(ctx, "git", "clone", in.RemoteURL, in.TargetRepoPath)
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("git clone failed: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GitWorktreeAddInput is input to GitWorktreeAddActivity.
|
||||
type GitWorktreeAddInput struct {
|
||||
RepoPath string
|
||||
TaskID string
|
||||
}
|
||||
|
||||
// GitWorktreeAddActivity creates a new git worktree for a task.
|
||||
func GitWorktreeAddActivity(ctx context.Context, in GitWorktreeAddInput) (string, error) {
|
||||
// Acquire lock to synchronize worktree creation
|
||||
lockPath := filepath.Join(in.RepoPath, "orchestrator.lock")
|
||||
if err := lock.Acquire(lockPath); err != nil {
|
||||
return "", fmt.Errorf("failed to acquire lock: %w", err)
|
||||
}
|
||||
defer lock.Release(lockPath)
|
||||
|
||||
// Create worktrees directory if it doesn't exist
|
||||
worktreesDir := filepath.Join(in.RepoPath, "worktrees")
|
||||
if err := os.MkdirAll(worktreesDir, 0755); err != nil {
|
||||
return "", fmt.Errorf("failed to create worktrees dir: %w", err)
|
||||
}
|
||||
|
||||
worktreePath := filepath.Join(worktreesDir, in.TaskID)
|
||||
branch := "task/" + in.TaskID
|
||||
|
||||
// Create worktree
|
||||
cmd := exec.CommandContext(ctx, "git", "-C", in.RepoPath, "worktree", "add", "-b", branch, worktreePath, "origin/main")
|
||||
if err := cmd.Run(); err != nil {
|
||||
return "", fmt.Errorf("git worktree add failed: %w", err)
|
||||
}
|
||||
|
||||
return worktreePath, nil
|
||||
}
|
||||
|
||||
// GitCommitInput is input to GitCommitActivity.
|
||||
type GitCommitInput struct {
|
||||
WorktreePath string
|
||||
Message string
|
||||
}
|
||||
|
||||
// GitCommitActivity commits changes in a worktree.
|
||||
func GitCommitActivity(ctx context.Context, in GitCommitInput) error {
|
||||
// Stage all changes
|
||||
cmd := exec.CommandContext(ctx, "git", "-C", in.WorktreePath, "add", "-A")
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("git add failed: %w", err)
|
||||
}
|
||||
|
||||
// Commit
|
||||
cmd = exec.CommandContext(ctx, "git", "-C", in.WorktreePath, "commit", "-m", in.Message)
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("git commit failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GitPushInput is input to GitPushActivity.
|
||||
type GitPushInput struct {
|
||||
RepoPath string
|
||||
}
|
||||
|
||||
// GitPushActivity pushes changes to origin.
|
||||
func GitPushActivity(ctx context.Context, in GitPushInput) error {
|
||||
// Acquire lock to synchronize push
|
||||
lockPath := filepath.Join(in.RepoPath, "orchestrator.lock")
|
||||
if err := lock.Acquire(lockPath); err != nil {
|
||||
return fmt.Errorf("failed to acquire lock: %w", err)
|
||||
}
|
||||
defer lock.Release(lockPath)
|
||||
|
||||
cmd := exec.CommandContext(ctx, "git", "-C", in.RepoPath, "push", "origin", "main")
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("git push failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GitSquashMergeInput is input to GitSquashMergeActivity.
|
||||
type GitSquashMergeInput struct {
|
||||
RepoPath string
|
||||
Branches []string
|
||||
Message string
|
||||
}
|
||||
|
||||
// GitSquashMergeActivity performs a squash merge of multiple branches into main.
|
||||
func GitSquashMergeActivity(ctx context.Context, in GitSquashMergeInput) error {
|
||||
// Acquire lock to synchronize merge
|
||||
lockPath := filepath.Join(in.RepoPath, "orchestrator.lock")
|
||||
if err := lock.Acquire(lockPath); err != nil {
|
||||
return fmt.Errorf("failed to acquire lock: %w", err)
|
||||
}
|
||||
defer lock.Release(lockPath)
|
||||
|
||||
// Fetch origin main
|
||||
cmd := exec.CommandContext(ctx, "git", "-C", in.RepoPath, "fetch", "origin", "main")
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("git fetch failed: %w", err)
|
||||
}
|
||||
|
||||
// Checkout main and pull with ff-only
|
||||
cmd = exec.CommandContext(ctx, "git", "-C", in.RepoPath, "checkout", "main")
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("git checkout main failed: %w", err)
|
||||
}
|
||||
|
||||
cmd = exec.CommandContext(ctx, "git", "-C", in.RepoPath, "pull", "--ff-only", "origin", "main")
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("git pull failed: %w", err)
|
||||
}
|
||||
|
||||
// Squash merge each branch
|
||||
for _, branch := range in.Branches {
|
||||
cmd = exec.CommandContext(ctx, "git", "-C", in.RepoPath, "merge", "--squash", branch)
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("git merge --squash %s failed: %w", branch, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Commit squashed changes
|
||||
cmd = exec.CommandContext(ctx, "git", "-C", in.RepoPath, "commit", "-m", in.Message)
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("git commit failed: %w", err)
|
||||
}
|
||||
|
||||
// Push to origin
|
||||
cmd = exec.CommandContext(ctx, "git", "-C", in.RepoPath, "push", "origin", "main")
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("git push failed: %w", err)
|
||||
}
|
||||
|
||||
// Clean up worktrees and branches
|
||||
for _, branch := range in.Branches {
|
||||
taskID := branch[len("task/"):]
|
||||
worktreePath := filepath.Join(in.RepoPath, "worktrees", taskID)
|
||||
|
||||
// Remove worktree
|
||||
cmd = exec.CommandContext(ctx, "git", "-C", in.RepoPath, "worktree", "remove", worktreePath, "--force")
|
||||
if err := cmd.Run(); err != nil {
|
||||
// Log error but continue cleanup
|
||||
fmt.Printf("warning: failed to remove worktree %s: %v\n", worktreePath, err)
|
||||
}
|
||||
|
||||
// Delete branch
|
||||
cmd = exec.CommandContext(ctx, "git", "-C", in.RepoPath, "branch", "-D", branch)
|
||||
if err := cmd.Run(); err != nil {
|
||||
// Log error but continue cleanup
|
||||
fmt.Printf("warning: failed to delete branch %s: %v\n", branch, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user