diff --git a/internal/mirroring/post.go b/internal/mirroring/post.go index 5bc05fd..7163d65 100644 --- a/internal/mirroring/post.go +++ b/internal/mirroring/post.go @@ -111,7 +111,7 @@ func (g *GitlabInstance) createGroupFromSource(sourceGroup *gitlab.Group, copyOp } // ============================================================ // -// PROJECT CREATION FUNCTIONS // +// PROJECT CREATION FUNCTIONS // // ============================================================ // // createProjects creates GitLab projects in the destination GitLab instance based on the mirror mapping. @@ -139,7 +139,7 @@ func (destinationGitlab *GitlabInstance) createProjects(sourceGitlab *GitlabInst defer wg.Done() _, err := destinationGitlab.createProject(sourcePath, destinationCopyOptions, sourceGitlab) if err != nil { - errorChan <- fmt.Errorf("failed to create project %s in destination GitLab instance: %s", destinationCopyOptions.DestinationPath, err) + errorChan <- fmt.Errorf("failed to create project %s in destination GitLab instance: %v", destinationCopyOptions.DestinationPath, err) } }(sourceProjectPath, destinationProjectOptions) } @@ -168,7 +168,7 @@ func (destinationGitlab *GitlabInstance) createProject(sourceProjectPath string, // If it does not exist, create it if destinationProject == nil { destinationProject, err = destinationGitlab.createProjectFromSource(sourceProject, projectCreationOptions) - if err != nil { + if err != nil || destinationProject == nil { return nil, []error{fmt.Errorf("failed to create project %s in destination GitLab instance: %s", destinationProjectPath, err)} } } @@ -215,7 +215,7 @@ func (g *GitlabInstance) createProjectFromSource(sourceProject *gitlab.Project, g.addProject(destinationProject) } - return destinationProject, nil + return destinationProject, err } // ============================================================ // diff --git a/internal/mirroring/post_test.go b/internal/mirroring/post_test.go index 0a854b4..903abca 100644 --- a/internal/mirroring/post_test.go +++ b/internal/mirroring/post_test.go @@ -211,7 +211,7 @@ func TestCreateProjects(t *testing.T) { }, } err := destinationGitlabInstance.createProjects(sourceGitlabInstance, mirrorMapping) - if err != nil { + if err != nil && len(err) > 0 { t.Errorf("Unexpected error when creating projects: %v", err) } if len(destinationGitlabInstance.Projects) == 0 { diff --git a/internal/mirroring/put.go b/internal/mirroring/put.go index a470af4..dde65ce 100644 --- a/internal/mirroring/put.go +++ b/internal/mirroring/put.go @@ -21,6 +21,13 @@ import ( // It also mirrors releases if the option is set. // The function uses goroutines to perform these tasks concurrently and waits for all of them to finish. func (destinationGitlabInstance *GitlabInstance) updateProjectFromSource(sourceGitlabInstance *GitlabInstance, sourceProject *gitlab.Project, destinationProject *gitlab.Project, copyOptions *utils.MirroringOptions) []error { + // Immediately capture pointers in local variables to avoid any late overrides + srcProj := sourceProject + dstProj := destinationProject + if srcProj == nil || dstProj == nil { + return []error{fmt.Errorf("source or destination project is nil")} + } + wg := sync.WaitGroup{} maxErrors := 3 if copyOptions.CI_CD_Catalog { @@ -29,41 +36,43 @@ func (destinationGitlabInstance *GitlabInstance) updateProjectFromSource(sourceG if copyOptions.MirrorReleases { maxErrors++ } + wg.Add(maxErrors) errorChan := make(chan error, maxErrors) - go func() { + go func(sp *gitlab.Project, dp *gitlab.Project) { defer wg.Done() - errorChan <- destinationGitlabInstance.syncProjectAttributes(sourceProject, destinationProject, copyOptions) - }() + errorChan <- destinationGitlabInstance.syncProjectAttributes(sp, dp, copyOptions) + }(srcProj, dstProj) - go func() { + go func(sp *gitlab.Project, dp *gitlab.Project) { defer wg.Done() - errorChan <- destinationGitlabInstance.enableProjectMirrorPull(sourceProject, destinationProject, copyOptions) - }() + errorChan <- destinationGitlabInstance.enableProjectMirrorPull(sp, dp, copyOptions) + }(srcProj, dstProj) - go func() { + go func(sp *gitlab.Project, dp *gitlab.Project) { defer wg.Done() - errorChan <- sourceGitlabInstance.copyProjectAvatar(destinationGitlabInstance, destinationProject, sourceProject) - }() + errorChan <- sourceGitlabInstance.copyProjectAvatar(destinationGitlabInstance, dp, sp) + }(srcProj, dstProj) if copyOptions.CI_CD_Catalog { - go func() { + go func(dp *gitlab.Project) { defer wg.Done() - errorChan <- destinationGitlabInstance.addProjectToCICDCatalog(destinationProject) - }() + errorChan <- destinationGitlabInstance.addProjectToCICDCatalog(dp) + }(dstProj) } allErrors := []error{} if copyOptions.MirrorReleases { - go func() { + go func(sp *gitlab.Project, dp *gitlab.Project) { defer wg.Done() - allErrors = destinationGitlabInstance.mirrorReleases(sourceGitlabInstance, sourceProject, destinationProject) - }() + allErrors = destinationGitlabInstance.mirrorReleases(sourceGitlabInstance, sp, dp) + }(srcProj, dstProj) } wg.Wait() close(errorChan) + for err := range errorChan { if err != nil { allErrors = append(allErrors, err) @@ -176,20 +185,29 @@ func (sourceGitlabInstance *GitlabInstance) copyProjectAvatar(destinationGitlabI // updateGroupFromSource updates the destination group with settings from the source group. // It copies the group avatar and updates the group attributes. func (destinationGitlabInstance *GitlabInstance) updateGroupFromSource(sourceGitlabInstance *GitlabInstance, sourceGroup *gitlab.Group, destinationGroup *gitlab.Group, copyOptions *utils.MirroringOptions) []error { + // Immediately capture pointers in local variables to avoid any late overrides + srcGroup := sourceGroup + dstGroup := destinationGroup + cpOpts := copyOptions + + if srcGroup == nil || dstGroup == nil { + return []error{fmt.Errorf("source or destination group is nil")} + } + wg := sync.WaitGroup{} maxErrors := 2 wg.Add(maxErrors) errorChan := make(chan error, maxErrors) - go func() { + go func(sg *gitlab.Group, dg *gitlab.Group, cp *utils.MirroringOptions) { defer wg.Done() - errorChan <- destinationGitlabInstance.syncGroupAttributes(sourceGroup, destinationGroup, copyOptions) - }() + errorChan <- destinationGitlabInstance.syncGroupAttributes(sg, dg, cp) + }(srcGroup, dstGroup, cpOpts) - go func() { + go func(sg *gitlab.Group, dg *gitlab.Group) { defer wg.Done() - errorChan <- sourceGitlabInstance.copyGroupAvatar(destinationGitlabInstance, destinationGroup, sourceGroup) - }() + errorChan <- sourceGitlabInstance.copyGroupAvatar(destinationGitlabInstance, dg, sg) + }(srcGroup, dstGroup) wg.Wait() close(errorChan)