@@ -69,6 +69,7 @@ func createGroups(sourceGitlab *GitlabInstance, destinationGitlab *GitlabInstanc
6969
7070func createProjects (sourceGitlab * GitlabInstance , destinationGitlab * GitlabInstance , mirrorMapping * utils.MirrorMapping ) error {
7171 utils .LogVerbose ("Creating projects in destination GitLab instance" )
72+
7273 // Reverse the mirror mapping to get the source project path for each destination project
7374 reversedMirrorMap := make (map [string ]string , len (mirrorMapping .Projects ))
7475 for sourceProjectPath , projectOptions := range mirrorMapping .Projects {
@@ -81,10 +82,6 @@ func createProjects(sourceGitlab *GitlabInstance, destinationGitlab *GitlabInsta
8182 // Create a channel to collect errors
8283 errorChan := make (chan error , len (reversedMirrorMap ))
8384
84- // Create a channel to limit the number of concurrent goroutines
85- concurrencyLimit := 10
86- sem := make (chan struct {}, concurrencyLimit )
87-
8885 for destinationProjectPath , sourceProjectPath := range reversedMirrorMap {
8986 utils .LogVerbosef ("Mirroring project from source %s to destination %s" , sourceProjectPath , destinationProjectPath )
9087 sourceProject := sourceGitlab .Projects [sourceProjectPath ]
@@ -93,13 +90,9 @@ func createProjects(sourceGitlab *GitlabInstance, destinationGitlab *GitlabInsta
9390 continue
9491 }
9592 wg .Add (1 )
96- // Acquire a token from the semaphore
97- sem <- struct {}{}
9893
9994 go func (sourcePath string , destinationPath string ) {
10095 defer wg .Done ()
101- // Release the token back to the semaphore
102- defer func () { <- sem }()
10396
10497 // Retrieve the corresponding project creation options from the mirror mapping
10598 projectCreationOptions , ok := mirrorMapping .Projects [sourcePath ]
@@ -136,42 +129,64 @@ func createProjects(sourceGitlab *GitlabInstance, destinationGitlab *GitlabInsta
136129 }(sourceProjectPath , destinationProjectPath )
137130 }
138131
139- // Wait for all goroutines to finish
140132 wg .Wait ()
141133 close (errorChan )
142134
143135 return utils .MergeErrors (errorChan , 2 )
144136}
145137
146138func (g * GitlabInstance ) createProjectFromSource (sourceProject * gitlab.Project , copyOptions * utils.MirroringOptions ) (* gitlab.Project , error ) {
147- projectCreationArgs := & gitlab.CreateProjectOptions {
148- Name : & sourceProject .Name ,
149- Path : & sourceProject .Path ,
150- DefaultBranch : & sourceProject .DefaultBranch ,
151- Description : & sourceProject .Description ,
152- MirrorTriggerBuilds : gitlab .Ptr (copyOptions .MirrorTriggerBuilds ),
153- Mirror : gitlab .Ptr (true ),
154- Topics : & sourceProject .Topics ,
155- Visibility : gitlab .Ptr (gitlab .VisibilityValue (copyOptions .Visibility )),
156- }
139+ // Create a wait group and error channel for error handling
140+ var wg sync.WaitGroup
141+ errorChan := make (chan error , 1 )
142+
143+ // Define the API call logic
144+ apiFunc := func () error {
145+ projectCreationArgs := & gitlab.CreateProjectOptions {
146+ Name : & sourceProject .Name ,
147+ Path : & sourceProject .Path ,
148+ DefaultBranch : & sourceProject .DefaultBranch ,
149+ Description : & sourceProject .Description ,
150+ MirrorTriggerBuilds : & copyOptions .MirrorTriggerBuilds ,
151+ Mirror : gitlab .Ptr (true ),
152+ Topics : & sourceProject .Topics ,
153+ Visibility : gitlab .Ptr (gitlab .VisibilityValue (copyOptions .Visibility )),
154+ }
157155
158- utils .LogVerbosef ("Retrieving project namespace ID for %s" , copyOptions .DestinationPath )
159- parentNamespaceId , err := g .getParentNamespaceID (copyOptions .DestinationPath )
160- if err != nil {
161- return nil , err
162- } else if parentNamespaceId >= 0 {
163- projectCreationArgs .NamespaceID = & parentNamespaceId
156+ utils .LogVerbosef ("Retrieving project namespace ID for %s" , copyOptions .DestinationPath )
157+ parentNamespaceId , err := g .getParentNamespaceID (copyOptions .DestinationPath )
158+ if err != nil {
159+ return err
160+ } else if parentNamespaceId >= 0 {
161+ projectCreationArgs .NamespaceID = & parentNamespaceId
162+ }
163+
164+ utils .LogVerbosef ("Creating project %s in destination GitLab instance" , copyOptions .DestinationPath )
165+ destinationProject , _ , err := g .Gitlab .Projects .CreateProject (projectCreationArgs )
166+ if err != nil {
167+ return err
168+ }
169+ utils .LogVerbosef ("Project %s created successfully" , destinationProject .PathWithNamespace )
170+ g .addProject (copyOptions .DestinationPath , destinationProject )
171+
172+ return nil
164173 }
165174
166- utils .LogVerbosef ("Creating project %s in destination GitLab instance" , copyOptions .DestinationPath )
167- destinationProject , _ , err := g .Gitlab .Projects .CreateProject (projectCreationArgs )
168- if err != nil {
175+ // Increment the wait group counter and execute the API call
176+ wg .Add (1 )
177+ go utils .ExecuteWithConcurrency (apiFunc , & wg , errorChan )
178+
179+ // Wait for the API call to complete
180+ wg .Wait ()
181+ close (errorChan )
182+
183+ // Check for errors
184+ select {
185+ case err := <- errorChan :
169186 return nil , err
187+ default :
188+ return nil , nil
170189 }
171- utils .LogVerbosef ("Project %s created successfully" , destinationProject .PathWithNamespace )
172- g .addProject (copyOptions .DestinationPath , destinationProject )
173-
174- return destinationProject , nil
175190}
176191
177192func (g * GitlabInstance ) createGroupFromSource (sourceGroup * gitlab.Group , copyOptions * utils.MirroringOptions ) (* gitlab.Group , error ) {
@@ -219,6 +234,10 @@ func (g *GitlabInstance) mirrorReleases(sourceProject *gitlab.Project, destinati
219234 return fmt .Errorf ("failed to fetch releases for source project %s: %s" , sourceProject .PathWithNamespace , err )
220235 }
221236
237+ // Create a wait group and an error channel for handling API calls concurrently
238+ var wg sync.WaitGroup
239+ errorChan := make (chan error , len (sourceReleases ))
240+
222241 // Iterate over each source release
223242 for _ , release := range sourceReleases {
224243 // Check if the release already exists in the destination project
@@ -227,20 +246,48 @@ func (g *GitlabInstance) mirrorReleases(sourceProject *gitlab.Project, destinati
227246 continue
228247 }
229248
230- utils .LogVerbosef ("Mirroring release %s to project %s" , release .TagName , destinationProject .PathWithNamespace )
249+ // Increment the wait group counter
250+ wg .Add (1 )
231251
232- // Create the release in the destination project
233- _ , _ , err := g .Gitlab .Releases .CreateRelease (destinationProject .ID , & gitlab.CreateReleaseOptions {
234- Name : gitlab .Ptr (release .Name ),
235- TagName : gitlab .Ptr (release .TagName ),
236- Description : gitlab .Ptr (release .Description ),
237- ReleasedAt : release .ReleasedAt ,
238- })
239- if err != nil {
240- utils .LogVerbosef ("Failed to create release %s in project %s: %s" , release .TagName , destinationProject .PathWithNamespace , err )
252+ // Define the API call logic for creating a release
253+ releaseToMirror := release // Capture the current release in the loop
254+ go utils .ExecuteWithConcurrency (func () error {
255+ utils .LogVerbosef ("Mirroring release %s to project %s" , releaseToMirror .TagName , destinationProject .PathWithNamespace )
256+
257+ // Create the release in the destination project
258+ _ , _ , err := g .Gitlab .Releases .CreateRelease (destinationProject .ID , & gitlab.CreateReleaseOptions {
259+ Name : & releaseToMirror .Name ,
260+ TagName : & releaseToMirror .TagName ,
261+ Description : & releaseToMirror .Description ,
262+ ReleasedAt : releaseToMirror .ReleasedAt ,
263+ })
264+ if err != nil {
265+ utils .LogVerbosef ("Failed to create release %s in project %s: %s" , releaseToMirror .TagName , destinationProject .PathWithNamespace , err )
266+ return fmt .Errorf ("Failed to create release %s in project %s: %s" , releaseToMirror .TagName , destinationProject .PathWithNamespace , err )
267+ }
268+
269+ return nil
270+ }, & wg , errorChan )
271+ }
272+
273+ // Wait for all goroutines to finish
274+ wg .Wait ()
275+ close (errorChan )
276+
277+ // Check the error channel for any errors
278+ var combinedError error
279+ for err := range errorChan {
280+ if combinedError == nil {
281+ combinedError = err
282+ } else {
283+ combinedError = fmt .Errorf ("%s; %s" , combinedError , err )
241284 }
242285 }
243286
287+ if combinedError != nil {
288+ return combinedError
289+ }
290+
244291 utils .LogVerbosef ("Releases mirroring completed for project %s" , destinationProject .HTTPURLToRepo )
245292 return nil
246293}
0 commit comments