this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: retry clone if not found

+80 -8
+71 -5
controller/activities/git.go
··· 2 2 3 3 import ( 4 4 "context" 5 + "crypto/sha256" 6 + "fmt" 5 7 "os" 6 8 "os/exec" 7 9 "path/filepath" ··· 10 12 "go.temporal.io/sdk/activity" 11 13 ) 12 14 15 + // generateRepoPath creates a deterministic path for the repository based on URL and revision 16 + func generateRepoPath(url string, revision string) string { 17 + // Create a hash of the URL and revision for a deterministic path 18 + hash := sha256.Sum256([]byte(url + ":" + revision)) 19 + hashStr := fmt.Sprintf("%x", hash)[:16] // Use first 16 chars of hash 20 + 21 + // Use /tmp/cloudlab-repos/ as base directory 22 + return filepath.Join("/tmp", "cloudlab-repos", hashStr) 23 + } 24 + 25 + // checkRepoStatus checks if repository exists and returns the current commit hash 26 + func checkRepoStatus(ctx context.Context, path string, revision string) (exists bool, currentHash string) { 27 + // Check if .git directory exists 28 + gitDir := filepath.Join(path, ".git") 29 + if _, err := os.Stat(gitDir); os.IsNotExist(err) { 30 + return false, "" 31 + } 32 + 33 + // Get current commit hash 34 + cmd := exec.CommandContext(ctx, "git", "rev-parse", "HEAD") 35 + cmd.Dir = path 36 + output, err := cmd.Output() 37 + if err != nil { 38 + return false, "" 39 + } 40 + 41 + currentHash = strings.TrimSpace(string(output)) 42 + return true, currentHash 43 + } 44 + 45 + // isCommitAvailable checks if the desired commit/revision is available in the repository 46 + func isCommitAvailable(ctx context.Context, path string, revision string) bool { 47 + // Try to resolve the revision to a commit hash 48 + cmd := exec.CommandContext(ctx, "git", "rev-parse", revision) 49 + cmd.Dir = path 50 + _, err := cmd.Output() 51 + return err == nil 52 + } 53 + 13 54 func Clone(ctx context.Context, url string, revision string) (string, error) { 14 55 logger := activity.GetLogger(ctx) 15 - logger.Info("Cloning", "url", url, "revision", revision) 56 + logger.Info("Ensuring repository availability", "url", url, "revision", revision) 16 57 17 - path, err := os.MkdirTemp("", "infra-") 18 - if err != nil { 19 - return "", err 58 + // Create deterministic path based on URL and revision to enable reuse 59 + path := generateRepoPath(url, revision) 60 + 61 + // Check if repository already exists and has the correct revision 62 + if repoExists, currentHash := checkRepoStatus(ctx, path, revision); repoExists { 63 + if currentHash == revision || isCommitAvailable(ctx, path, revision) { 64 + logger.Info("Repository already available with correct revision", "path", path) 65 + return path, nil 66 + } 67 + logger.Info("Repository exists but wrong revision, will update", "path", path, "current", currentHash, "desired", revision) 20 68 } 21 69 70 + // Ensure parent directory exists 71 + if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { 72 + return "", fmt.Errorf("failed to create parent directory: %w", err) 73 + } 74 + 75 + // Remove existing directory if it exists but is inconsistent 76 + if _, err := os.Stat(path); err == nil { 77 + logger.Info("Removing existing inconsistent repository", "path", path) 78 + if err := os.RemoveAll(path); err != nil { 79 + return "", fmt.Errorf("failed to remove existing repository: %w", err) 80 + } 81 + } 82 + 83 + // Clone the repository 84 + logger.Info("Cloning repository", "url", url, "revision", revision, "path", path) 22 85 cmd := exec.CommandContext(ctx, "git", "clone", "--branch", revision, url, path) 23 86 if err := cmd.Run(); err != nil { 24 - return "", err 87 + // Clean up the directory if clone fails 88 + os.RemoveAll(path) 89 + return "", fmt.Errorf("failed to clone repository: %w", err) 25 90 } 26 91 92 + logger.Info("Successfully cloned repository", "path", path) 27 93 return path, nil 28 94 } 29 95
+8 -2
controller/activities/terragrunt.go
··· 32 32 return PruneGraph(ctx, graph, changedFiles) 33 33 } 34 34 35 - func TerragruntApply(ctx context.Context, repoPath string, modulePath string, stack string) error { 35 + func TerragruntApply(ctx context.Context, repoUrl string, revision string, modulePath string, stack string) error { 36 36 logger := activity.GetLogger(ctx) 37 - logger.Info("Running terragrunt apply", "module", modulePath, "stack", stack) 37 + logger.Info("Running terragrunt apply", "module", modulePath, "stack", stack, "repo", repoUrl, "revision", revision) 38 + 39 + // Ensure repository is available (clone if necessary) 40 + repoPath, err := Clone(ctx, repoUrl, revision) 41 + if err != nil { 42 + return fmt.Errorf("failed to ensure repository is available: %w", err) 43 + } 38 44 39 45 fullPath := filepath.Join(repoPath, "infra", stack, modulePath) 40 46
+1 -1
controller/workflows/infra.go
··· 74 74 } 75 75 moduleCtx := workflow.WithActivityOptions(ctx, moduleActivityOptions) 76 76 77 - future := workflow.ExecuteActivity(moduleCtx, activities.TerragruntApply, path, moduleName, input.Stack) 77 + future := workflow.ExecuteActivity(moduleCtx, activities.TerragruntApply, input.Url, input.Revision, moduleName, input.Stack) 78 78 futures = append(futures, future) 79 79 } 80 80