fix: add proper instrumentation to git clone for debugging
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
- Log clone request with work_dir, URL, and token presence - Log workspace state (is_git_repo, existing remote) - Log all decision points (pull vs clone, clear workspace) - Detect and clear non-empty non-git directories before clone - Capture both stdout and stderr for clone failures - Include exit code in error messages
This commit is contained in:
parent
83b5d1ebb4
commit
9cca5cc41b
@ -68,50 +68,97 @@ type CloneResult struct {
|
|||||||
func (g *GitOperations) CloneRepo(ctx context.Context, workDir, cloneURL string) *CloneResult {
|
func (g *GitOperations) CloneRepo(ctx context.Context, workDir, cloneURL string) *CloneResult {
|
||||||
result := &CloneResult{}
|
result := &CloneResult{}
|
||||||
|
|
||||||
|
g.logger.Info("git clone request",
|
||||||
|
"work_dir", workDir,
|
||||||
|
"clone_url", g.redactToken(cloneURL),
|
||||||
|
"has_token", g.giteaToken != "")
|
||||||
|
|
||||||
if cloneURL == "" {
|
if cloneURL == "" {
|
||||||
result.Error = fmt.Errorf("git clone URL is required")
|
result.Error = fmt.Errorf("git clone URL is required")
|
||||||
|
g.logger.Error("git clone failed: empty URL")
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if already a git repo with the correct remote
|
// Check if already a git repo with the correct remote
|
||||||
if g.isGitRepo(ctx, workDir) {
|
isRepo := g.isGitRepo(ctx, workDir)
|
||||||
|
g.logger.Info("workspace check", "is_git_repo", isRepo, "work_dir", workDir)
|
||||||
|
|
||||||
|
if isRepo {
|
||||||
currentRemote, err := g.runGitOutput(ctx, workDir, "config", "--get", "remote.origin.url")
|
currentRemote, err := g.runGitOutput(ctx, workDir, "config", "--get", "remote.origin.url")
|
||||||
currentRemote = strings.TrimSpace(currentRemote)
|
currentRemote = strings.TrimSpace(currentRemote)
|
||||||
|
g.logger.Info("existing repo detected",
|
||||||
|
"current_remote", g.redactToken(currentRemote),
|
||||||
|
"expected_remote", g.redactToken(cloneURL),
|
||||||
|
"remote_match", currentRemote == cloneURL,
|
||||||
|
"remote_err", err)
|
||||||
|
|
||||||
if err == nil && currentRemote == cloneURL {
|
if err == nil && currentRemote == cloneURL {
|
||||||
// Pull latest changes
|
// Pull latest changes
|
||||||
|
g.logger.Info("pulling latest changes", "work_dir", workDir)
|
||||||
if err := g.runGit(ctx, workDir, "pull", "--ff-only"); err != nil {
|
if err := g.runGit(ctx, workDir, "pull", "--ff-only"); err != nil {
|
||||||
// Pull failed but repo exists - continue with existing state
|
// Pull failed but repo exists - continue with existing state
|
||||||
g.logger.Debug("git pull failed, continuing with existing state", "error", err, "work_dir", workDir)
|
g.logger.Warn("git pull failed, continuing with existing state",
|
||||||
|
"error", err,
|
||||||
|
"work_dir", workDir)
|
||||||
}
|
}
|
||||||
|
g.logger.Info("git clone complete (existing repo)", "cloned", false)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Different remote - clear and re-clone
|
// Different remote - clear and re-clone
|
||||||
|
g.logger.Info("clearing workspace for re-clone", "work_dir", workDir)
|
||||||
if err := g.clearDir(ctx, workDir); err != nil {
|
if err := g.clearDir(ctx, workDir); err != nil {
|
||||||
result.Error = fmt.Errorf("clear workspace: %w", err)
|
result.Error = fmt.Errorf("clear workspace: %w", err)
|
||||||
|
g.logger.Error("failed to clear workspace", "error", result.Error)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if directory exists and is non-empty (would cause clone to fail)
|
||||||
|
if !isRepo {
|
||||||
|
checkCmd := exec.CommandContext(ctx, "sh", "-c", fmt.Sprintf("ls -A %s 2>/dev/null | head -1", workDir))
|
||||||
|
output, _ := checkCmd.Output()
|
||||||
|
if len(strings.TrimSpace(string(output))) > 0 {
|
||||||
|
g.logger.Warn("workspace not empty but not a git repo, clearing",
|
||||||
|
"work_dir", workDir,
|
||||||
|
"first_file", strings.TrimSpace(string(output)))
|
||||||
|
if err := g.clearDir(ctx, workDir); err != nil {
|
||||||
|
result.Error = fmt.Errorf("clear non-empty workspace: %w", err)
|
||||||
|
g.logger.Error("failed to clear non-empty workspace", "error", result.Error)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Inject token for authentication
|
// Inject token for authentication
|
||||||
authCloneURL := cloneURL
|
authCloneURL := cloneURL
|
||||||
if g.giteaToken != "" {
|
if g.giteaToken != "" {
|
||||||
authCloneURL = strings.Replace(cloneURL, "https://", "https://token:"+g.giteaToken+"@", 1)
|
authCloneURL = strings.Replace(cloneURL, "https://", "https://token:"+g.giteaToken+"@", 1)
|
||||||
|
} else {
|
||||||
|
g.logger.Warn("no gitea token configured, clone may fail for private repos")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone the repository
|
// Clone the repository
|
||||||
|
g.logger.Info("executing git clone", "work_dir", workDir)
|
||||||
cmd := exec.CommandContext(ctx, "git", "clone", authCloneURL, workDir)
|
cmd := exec.CommandContext(ctx, "git", "clone", authCloneURL, workDir)
|
||||||
var stderr bytes.Buffer
|
var stdout, stderr bytes.Buffer
|
||||||
|
cmd.Stdout = &stdout
|
||||||
cmd.Stderr = &stderr
|
cmd.Stderr = &stderr
|
||||||
|
|
||||||
if err := cmd.Run(); err != nil {
|
if err := cmd.Run(); err != nil {
|
||||||
errMsg := g.redactToken(stderr.String())
|
errMsg := g.redactToken(stderr.String())
|
||||||
result.Error = fmt.Errorf("git clone failed: %s: %s", err, errMsg)
|
stdoutMsg := g.redactToken(stdout.String())
|
||||||
|
result.Error = fmt.Errorf("git clone exit %v: %s", err, errMsg)
|
||||||
|
g.logger.Error("git clone failed",
|
||||||
|
"error", err,
|
||||||
|
"stderr", errMsg,
|
||||||
|
"stdout", stdoutMsg,
|
||||||
|
"work_dir", workDir)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Cloned = true
|
result.Cloned = true
|
||||||
|
g.logger.Info("git clone complete", "cloned", true, "work_dir", workDir)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user