Skip to content

Commit 64162e9

Browse files
authored
Merge pull request #246 from LalitDeore/fix-git-issue
fix workflow backup issue for azure devops
2 parents 3f1edfd + a690289 commit 64162e9

File tree

1 file changed

+114
-52
lines changed

1 file changed

+114
-52
lines changed

cloudSync.go

Lines changed: 114 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,12 @@ import (
2424
"github.com/go-git/go-billy/v5/memfs"
2525
"github.com/go-git/go-git/v5"
2626
"github.com/go-git/go-git/v5/config"
27+
2728
//"github.com/go-git/go-git/v5/plumbing"
2829
"github.com/go-git/go-git/v5/plumbing/object"
30+
"github.com/go-git/go-git/v5/plumbing/protocol/packp/capability"
31+
"github.com/go-git/go-git/v5/plumbing/transport"
32+
gitHttp "github.com/go-git/go-git/v5/plumbing/transport/http"
2933
"github.com/go-git/go-git/v5/storage/memory"
3034

3135
uuid "github.com/satori/go.uuid"
@@ -1112,7 +1116,12 @@ func SetGitWorkflow(ctx context.Context, workflow Workflow, org *Org) error {
11121116
}
11131117

11141118
if len(org.Defaults.WorkflowUploadBranch) == 0 {
1115-
org.Defaults.WorkflowUploadBranch = "master"
1119+
// Default to 'main' for Azure DevOps, 'master' for others
1120+
if strings.Contains(org.Defaults.WorkflowUploadRepo, "dev.azure.com") {
1121+
org.Defaults.WorkflowUploadBranch = "main"
1122+
} else {
1123+
org.Defaults.WorkflowUploadBranch = "master"
1124+
}
11161125
}
11171126

11181127
if org.Defaults.WorkflowUploadRepo == "" || org.Defaults.WorkflowUploadToken == "" {
@@ -1122,18 +1131,8 @@ func SetGitWorkflow(ctx context.Context, workflow Workflow, org *Org) error {
11221131
}
11231132

11241133
org.Defaults.WorkflowUploadRepo = strings.TrimSpace(org.Defaults.WorkflowUploadRepo)
1125-
if strings.HasPrefix(org.Defaults.WorkflowUploadRepo, "https://") {
1126-
org.Defaults.WorkflowUploadRepo = strings.Replace(org.Defaults.WorkflowUploadRepo, "https://", "", 1)
1127-
org.Defaults.WorkflowUploadRepo = strings.Replace(org.Defaults.WorkflowUploadRepo, "http://", "", 1)
1128-
}
1129-
1130-
if strings.HasSuffix(org.Defaults.WorkflowUploadRepo, ".git") {
1131-
org.Defaults.WorkflowUploadRepo = strings.TrimSuffix(org.Defaults.WorkflowUploadRepo, ".git")
1132-
}
1133-
1134-
//log.Printf("[DEBUG] Uploading workflow %s to repo %s for org %s (%s)", workflow.ID, org.Defaults.WorkflowUploadRepo, org.Name, org.Id)
11351134

1136-
// Remove images
1135+
// Remove images from workflow before backup
11371136
workflow.Image = ""
11381137
for actionIndex, _ := range workflow.Actions {
11391138
workflow.Actions[actionIndex].LargeImage = ""
@@ -1155,12 +1154,39 @@ func SetGitWorkflow(ctx context.Context, workflow Workflow, org *Org) error {
11551154
return err
11561155
}
11571156

1158-
commitMessage := fmt.Sprintf("User '%s' updated workflow '%s' with status '%s'", workflow.UpdatedBy, workflow.Name, workflow.Status)
1159-
urlEncodedPassword := url.QueryEscape(org.Defaults.WorkflowUploadToken)
1160-
location := fmt.Sprintf("https://%s:%s@%s.git", org.Defaults.WorkflowUploadUsername, urlEncodedPassword, org.Defaults.WorkflowUploadRepo)
1157+
commitMessage := fmt.Sprintf("User '%s' updated workflow '%s' with status '%s' at %s", workflow.UpdatedBy, workflow.Name, workflow.Status, time.Now().Format("2006-01-02 15:04:05"))
1158+
repoURL := org.Defaults.WorkflowUploadRepo
1159+
repoURL = strings.TrimPrefix(repoURL, "https://")
1160+
repoURL = strings.TrimPrefix(repoURL, "http://")
1161+
1162+
var location string
1163+
var isAzureDevOps bool
1164+
1165+
if strings.Contains(repoURL, "dev.azure.com") {
1166+
isAzureDevOps = true
1167+
location = fmt.Sprintf("https://%s", repoURL)
1168+
log.Printf("[DEBUG] Detected Azure DevOps repository")
1169+
} else {
1170+
isAzureDevOps = false
1171+
// Only append .git if the URL contains github.com
1172+
if strings.Contains(repoURL, "github.com") && !strings.HasSuffix(repoURL, ".git") {
1173+
repoURL += ".git"
1174+
}
1175+
1176+
urlEncodedPassword := url.QueryEscape(org.Defaults.WorkflowUploadToken)
1177+
location = fmt.Sprintf("https://%s:%s@%s", org.Defaults.WorkflowUploadUsername, urlEncodedPassword, repoURL)
1178+
1179+
}
1180+
1181+
maskedRepo := location
1182+
if !isAzureDevOps {
1183+
maskedRepo = strings.ReplaceAll(location, org.Defaults.WorkflowUploadToken, "****")
1184+
if urlEncodedPassword := url.QueryEscape(org.Defaults.WorkflowUploadToken); urlEncodedPassword != org.Defaults.WorkflowUploadToken {
1185+
maskedRepo = strings.ReplaceAll(maskedRepo, urlEncodedPassword, "****")
1186+
}
1187+
}
11611188

1162-
newRepoName := strings.Replace(strings.Replace(location, org.Defaults.WorkflowUploadToken, "****", -1), urlEncodedPassword, "****", -1)
1163-
log.Printf("[DEBUG] Uploading workflow %s to repo: %s", workflow.ID, newRepoName)
1189+
log.Printf("[DEBUG] Uploading workflow %s to repo: %s", workflow.ID, maskedRepo)
11641190

11651191
fs := memfs.New()
11661192
if len(workflow.Status) == 0 {
@@ -1170,65 +1196,94 @@ func SetGitWorkflow(ctx context.Context, workflow Workflow, org *Org) error {
11701196
//filePath := fmt.Sprintf("/%s/%s.json", workflow.Status, workflow.ID)
11711197
filePath := fmt.Sprintf("%s/%s/%s_%s.json", workflow.ExecutingOrg.Id, workflow.Status, strings.ReplaceAll(workflow.Name, " ", "-"), workflow.ID)
11721198

1173-
// Specify the file path within the repository
1174-
repo, err := git.Clone(memory.NewStorage(), fs, &git.CloneOptions{
1199+
cloneOptions := &git.CloneOptions{
11751200
URL: location,
1176-
})
1177-
if err != nil {
1178-
newErr := strings.ReplaceAll(err.Error(), org.Defaults.WorkflowUploadToken, "****")
1179-
newErr = strings.ReplaceAll(newErr, urlEncodedPassword, "****")
1180-
1181-
log.Printf("[ERROR] Error cloning repo '%s' (workflow backup): %s", newRepoName, newErr)
1182-
return err
11831201
}
11841202

1185-
// Initialize a new Git repository in memory
1186-
w := &git.Worktree{}
1203+
// For Azure DevOps, add additional auth configuration and capability handling
1204+
if isAzureDevOps {
1205+
transport.UnsupportedCapabilities = []capability.Capability{
1206+
capability.ThinPack,
1207+
}
1208+
1209+
cloneOptions.Auth = &gitHttp.BasicAuth{
1210+
Username: org.Defaults.WorkflowUploadUsername, // Use the username for Azure DevOps
1211+
Password: org.Defaults.WorkflowUploadToken,
1212+
}
1213+
}
11871214

1188-
// Create a new commit with the in-memory file
1189-
w, err = repo.Worktree()
1215+
repo, err := git.Clone(memory.NewStorage(), fs, cloneOptions)
11901216
if err != nil {
1191-
newErr := strings.ReplaceAll(err.Error(), org.Defaults.WorkflowUploadToken, "****")
1192-
newErr = strings.ReplaceAll(newErr, urlEncodedPassword, "****")
1217+
errMsg := err.Error()
1218+
if isAzureDevOps {
1219+
log.Printf("[ERROR] Azure DevOps clone failed. Check: 1) PAT has Code(R/W) permissions, 2) Branch '%s' exists, 3) Repo URL is correct", org.Defaults.WorkflowUploadBranch)
1220+
}
1221+
log.Printf("[ERROR] Error cloning repo '%s': %s", maskedRepo, strings.ReplaceAll(errMsg, org.Defaults.WorkflowUploadToken, "****"))
1222+
return err
1223+
}
11931224

1194-
log.Printf("[ERROR] Error getting worktree for repo '%s' (2): %s", newRepoName, newErr)
1225+
w, err := repo.Worktree()
1226+
if err != nil {
1227+
log.Printf("[ERROR] Error getting worktree for repo '%s': %s", maskedRepo, err)
11951228
return err
11961229
}
11971230

11981231
// Write the byte blob to the in-memory file system
11991232
file, err := fs.Create(filePath)
12001233
if err != nil {
1201-
newErr := strings.ReplaceAll(err.Error(), org.Defaults.WorkflowUploadToken, "****")
1234+
log.Printf("[ERROR] Creating file in repo '%s': %v", maskedRepo, err)
1235+
return err
1236+
}
1237+
defer file.Close()
12021238

1203-
log.Printf("[ERROR] Creating git file: %v", newErr)
1239+
if _, err = io.Copy(file, bytes.NewReader(workflowData)); err != nil {
1240+
log.Printf("[ERROR] Writing data to file: %v", err)
12041241
return err
12051242
}
12061243

1207-
defer file.Close()
1208-
//_, err = io.Copy(file, bytes.NewReader(workflowData))
1209-
_, err = io.Copy(file, bytes.NewReader(workflowData))
1210-
if err != nil {
1211-
log.Printf("[ERROR] Writing data to git file: %v", err)
1244+
if _, err = w.Add(filePath); err != nil {
1245+
log.Printf("[ERROR] Adding file to staging area: %s", err)
12121246
return err
12131247
}
12141248

1215-
// Add the file to the staging area
1216-
_, err = w.Add(filePath)
1249+
// Check if there are any changes to commit
1250+
status, err := w.Status()
12171251
if err != nil {
1218-
log.Printf("[ERROR] Error adding file to git staging area (2): %s", err)
1252+
log.Printf("[ERROR] Getting working tree status: %v", err)
12191253
return err
12201254
}
12211255

1222-
// Commit the changes
1256+
hasChanges := false
1257+
for _, fileStatus := range status {
1258+
if fileStatus.Staging != git.Unmodified {
1259+
hasChanges = true
1260+
break
1261+
}
1262+
}
1263+
1264+
if !hasChanges {
1265+
log.Printf("[INFO] No changes detected for workflow %s (%s). File content is identical to existing version.", workflow.Name, workflow.ID)
1266+
return nil
1267+
}
1268+
1269+
authorName := org.Defaults.WorkflowUploadUsername
1270+
if authorName == "" {
1271+
if isAzureDevOps {
1272+
authorName = "Workflow Automation"
1273+
} else {
1274+
authorName = "Shuffle User"
1275+
}
1276+
}
1277+
12231278
_, err = w.Commit(commitMessage, &git.CommitOptions{
12241279
Author: &object.Signature{
1225-
Name: org.Defaults.WorkflowUploadUsername,
1280+
Name: authorName,
12261281
Email: "",
12271282
When: time.Now(),
12281283
},
12291284
})
12301285
if err != nil {
1231-
log.Printf("[ERROR] Committing git changes: %v (2)", err)
1286+
log.Printf("[ERROR] Committing changes: %v", err)
12321287
return err
12331288
}
12341289

@@ -1237,18 +1292,25 @@ func SetGitWorkflow(ctx context.Context, workflow Workflow, org *Org) error {
12371292
// Push the changes to a remote repository (replace URL with your repository URL)
12381293
// fmt.Sprintf("refs/heads/%s:refs/heads/%s", org.Defaults.WorkflowUploadBranch, org.Defaults.WorkflowUploadBranch)},
12391294
ref := fmt.Sprintf("refs/heads/%s:refs/heads/%s", org.Defaults.WorkflowUploadBranch, org.Defaults.WorkflowUploadBranch)
1240-
err = repo.Push(&git.PushOptions{
1295+
1296+
pushOptions := &git.PushOptions{
12411297
RemoteName: "origin",
12421298
RefSpecs: []config.RefSpec{config.RefSpec(ref)},
1243-
RemoteURL: location,
1244-
})
1299+
}
1300+
1301+
// Set authentication for push operations for both Azure DevOps and GitHub
1302+
pushOptions.Auth = &gitHttp.BasicAuth{
1303+
Username: org.Defaults.WorkflowUploadUsername,
1304+
Password: org.Defaults.WorkflowUploadToken,
1305+
}
1306+
1307+
err = repo.Push(pushOptions)
12451308
if err != nil {
1246-
log.Printf("[ERROR] Change git Push issue: %v (2)", err)
1309+
log.Printf("[ERROR] Git push failed for repo '%s': %v", maskedRepo, err)
12471310
return err
12481311
}
12491312

1250-
log.Printf("[DEBUG] File uploaded successfully to '%s'!", newRepoName)
1251-
1313+
log.Printf("[DEBUG] Workflow successfully uploaded to '%s'!", maskedRepo)
12521314
return nil
12531315
}
12541316

0 commit comments

Comments
 (0)