@@ -12,89 +12,96 @@ import (
1212 "go.uber.org/zap"
1313)
1414
15+ // fetchProjects retrieves all projects that match the filters from the GitLab instance and stores them in the instance cache.
16+ // It also updates the mirror mapping with the corresponding group creation options.
17+ //
18+ // The function is run in a goroutine for each project, and a wait group is used to wait for all goroutines to finish.
1519func (g * GitlabInstance ) fetchProjects (projectFilters * map [string ]bool , groupFilters * map [string ]bool , mirrorMapping * utils.MirrorMapping , isSource bool ) error {
1620 sourceString := "source"
1721 if ! isSource {
1822 sourceString = "destination"
1923 }
20- zap .L ().Sugar (). Debugf ( "Fetching all projects from %s GitLab instance" , sourceString )
24+ zap .L ().Debug ( "Fetching all projects from GitLab instance" , zap . String ( "role" , sourceString ) )
2125 projects , _ , err := g .Gitlab .Projects .ListProjects (nil )
2226 if err != nil {
2327 return err
2428 }
2529
26- zap .L ().Sugar (). Debugf ( "Processing %d projects from %s GitLab instance" , len ( projects ) , sourceString )
30+ zap .L ().Debug ( "Processing projects from GitLab instance" , zap . String ( "role" , sourceString ), zap . Int ( "projects" , len ( projects )) )
2731
2832 // Create a wait group to wait for all goroutines to finish
2933 var wg sync.WaitGroup
3034
3135 for _ , project := range projects {
3236 wg .Add (1 )
33- // Acquire a token from the semaphore
3437
3538 go func (project * gitlab.Project ) {
3639 defer wg .Done ()
3740
38- // Check if the project matches the filters:
39- // - either is in the projects map
40- // - or path starts with any of the groups in the groups map
41- if _ , ok := (* projectFilters )[project .PathWithNamespace ]; ok {
42- g .addProject (project .PathWithNamespace , project )
43- } else {
44- for group := range * groupFilters {
45- if strings .HasPrefix (project .PathWithNamespace , group ) {
46- // Add the project to the gitlab instance projects cache
47- g .addProject (project .PathWithNamespace , project )
48-
49- if isSource {
50- // Retrieve the corresponding group creation options from the mirror mapping
51- groupCreationOptions , ok := mirrorMapping .Groups [group ]
52- if ! ok {
53- zap .L ().Sugar ().Errorf ("Group %s not found in mirror mapping (internal error, please review script)" , group )
54- }
55-
56- // Calculate the relative path between the project and the group
57- relativePath , err := filepath .Rel (group , project .PathWithNamespace )
58- if err != nil {
59- zap .L ().Sugar ().Errorf ("Failed to calculate relative path for project %s: %s" , project .PathWithNamespace , err )
60- }
61-
62- // Add the project to the mirror mapping
63- mirrorMapping .AddProject (project .PathWithNamespace , & utils.MirroringOptions {
64- DestinationPath : filepath .Join (groupCreationOptions .DestinationPath , relativePath ),
65- CI_CD_Catalog : groupCreationOptions .CI_CD_Catalog ,
66- Issues : groupCreationOptions .Issues ,
67- MirrorTriggerBuilds : groupCreationOptions .MirrorTriggerBuilds ,
68- Visibility : groupCreationOptions .Visibility ,
69- MirrorReleases : groupCreationOptions .MirrorReleases ,
70- })
71- }
72- break
73- }
74- }
41+ group , matches := g .checkPathMatchesFilters (project .PathWithNamespace , projectFilters , groupFilters )
42+ if matches {
43+ g .storeProject (project , group , mirrorMapping , isSource )
7544 }
45+
7646 }(project )
7747 }
7848
7949 wg .Wait ()
8050
81- zap .L ().Sugar ().Debugf ("Found %d projects to mirror in the %s GitLab instance" , len (g .Projects ), sourceString )
82-
51+ zap .L ().Debug ("Found matching projects in the GitLab instance" , zap .String ("role" , sourceString ), zap .Int ("projects" , len (g .Projects )))
8352 return nil
8453}
8554
55+ // storeProject stores the project in the Gitlab instance projects cache
56+ // and updates the mirror mapping with the corresponding group creation options.
57+ func (g * GitlabInstance ) storeProject (project * gitlab.Project , parentGroupPath string , mirrorMapping * utils.MirrorMapping , isSource bool ) {
58+ // Add the project to the gitlab instance projects cache
59+ g .addProject (project .PathWithNamespace , project )
60+
61+ if isSource {
62+ zap .L ().Debug ("Storing project in mirror mapping" , zap .String ("project" , project .HTTPURLToRepo ), zap .String ("group" , parentGroupPath ))
63+ // Retrieve the corresponding group creation options from the mirror mapping
64+ groupCreationOptions , ok := mirrorMapping .GetGroup (parentGroupPath )
65+ if ! ok {
66+ zap .L ().Error ("Group not found in mirror mapping" , zap .String ("group" , parentGroupPath ))
67+ return
68+ }
69+
70+ // Calculate the relative path between the project and the group
71+ relativePath , err := filepath .Rel (parentGroupPath , project .PathWithNamespace )
72+ if err != nil {
73+ zap .L ().Error ("Failed to calculate relative path for project" , zap .String ("project" , project .HTTPURLToRepo ), zap .String ("group" , parentGroupPath ), zap .Error (err ))
74+ return
75+ }
76+
77+ // Add the project to the mirror mapping with the corresponding group creation options
78+ mirrorMapping .AddProject (project .PathWithNamespace , & utils.MirroringOptions {
79+ DestinationPath : filepath .Join (groupCreationOptions .DestinationPath , relativePath ),
80+ CI_CD_Catalog : groupCreationOptions .CI_CD_Catalog ,
81+ Issues : groupCreationOptions .Issues ,
82+ MirrorTriggerBuilds : groupCreationOptions .MirrorTriggerBuilds ,
83+ Visibility : groupCreationOptions .Visibility ,
84+ MirrorReleases : groupCreationOptions .MirrorReleases ,
85+ })
86+ }
87+ }
88+
89+ // fetchGroups retrieves all groups that match the filters from the GitLab instance and stores them in the instance cache.
90+ // It also updates the mirror mapping with the corresponding group creation options.
91+ //
92+ // The function is run in a goroutine for each group, and a wait group is used to wait for all goroutines to finish.
8693func (g * GitlabInstance ) fetchGroups (groupFilters * map [string ]bool , mirrorMapping * utils.MirrorMapping , isSource bool ) error {
8794 sourceString := "source"
8895 if ! isSource {
8996 sourceString = "destination"
9097 }
91- zap .L ().Sugar (). Debugf ( "Fetching all groups from %s GitLab instance" , sourceString )
98+ zap .L ().Debug ( "Fetching all groups from GitLab instance" , zap . String ( "role" , sourceString ) )
9299 groups , _ , err := g .Gitlab .Groups .ListGroups (nil )
93100 if err != nil {
94101 return err
95102 }
96103
97- zap .L ().Sugar (). Debugf ( "Processing %d groups from %s GitLab instance" , len ( groups ) , sourceString )
104+ zap .L ().Debug ( "Processing groups from GitLab instance" , zap . String ( "role" , sourceString ), zap . Int ( "groups" , len ( groups )) )
98105
99106 // Create a wait group to wait for all goroutines to finish
100107 var wg sync.WaitGroup
@@ -105,55 +112,84 @@ func (g *GitlabInstance) fetchGroups(groupFilters *map[string]bool, mirrorMappin
105112 go func (group * gitlab.Group ) {
106113 defer wg .Done ()
107114
108- // Check if the group matches the filters:
109- // - either is in the groups map
110- // - or path starts with any of the groups in the groups map
111- // - or is a subgroup of any of the groups in the groups map
112- if _ , ok := (* groupFilters )[group .FullPath ]; ok {
113- g .addGroup (group .FullPath , group )
114- } else {
115- for groupPath := range * groupFilters {
116- if strings .HasPrefix (group .FullPath , groupPath ) {
117- // Add the group to the gitlab instance groups cache
118- g .addGroup (group .FullPath , group )
119-
120- if isSource {
121- // Retrieve the corresponding group creation options from the mirror mapping
122- groupCreationOptions , ok := mirrorMapping .Groups [groupPath ]
123- if ! ok {
124- zap .L ().Sugar ().Fatalf ("Group %s not found in mirror mapping (internal error, please review script)" , groupPath )
125- }
126-
127- // Calculate the relative path between the group and the groupPath
128- relativePath , err := filepath .Rel (groupPath , group .FullPath )
129- if err != nil {
130- zap .L ().Sugar ().Fatalf ("Failed to calculate relative path for group %s: %s" , group .FullPath , err )
131- }
132-
133- // Add the group to the mirror mapping
134- mirrorMapping .AddGroup (group .FullPath , & utils.MirroringOptions {
135- DestinationPath : filepath .Join (groupCreationOptions .DestinationPath , relativePath ),
136- CI_CD_Catalog : groupCreationOptions .CI_CD_Catalog ,
137- Issues : groupCreationOptions .Issues ,
138- MirrorTriggerBuilds : groupCreationOptions .MirrorTriggerBuilds ,
139- Visibility : groupCreationOptions .Visibility ,
140- MirrorReleases : groupCreationOptions .MirrorReleases ,
141- })
142- }
143- break
144- }
145- }
115+ groupPath , matches := g .checkPathMatchesFilters (group .FullPath , nil , groupFilters )
116+ if matches {
117+ g .storeGroup (group , groupPath , mirrorMapping , isSource )
146118 }
147119 }(group )
148120 }
149121
150122 wg .Wait ()
151123
152- zap .L ().Sugar (). Debugf ( "Found %d matching groups in %s GitLab instance" , len (g .Groups ), sourceString )
124+ zap .L ().Debug ( "Found matching groups in the GitLab instance" , zap . String ( "role" , sourceString ), zap . Int ( "groups" , len (g .Groups )) )
153125
154126 return nil
155127}
156128
129+ // storeGroup stores the group in the Gitlab instance groups cache
130+ // and updates the mirror mapping with the corresponding group creation options.
131+ func (g * GitlabInstance ) storeGroup (group * gitlab.Group , parentGroupPath string , mirrorMapping * utils.MirrorMapping , isSource bool ) {
132+ if group != nil {
133+ // Add the group to the gitlab instance groups cache
134+ g .addGroup (group .FullPath , group )
135+
136+ if isSource {
137+ zap .L ().Debug ("Storing group in mirror mapping" , zap .String ("group" , group .FullPath ), zap .String ("parentGroup" , parentGroupPath ))
138+ // Retrieve the corresponding group creation options from the mirror mapping
139+ groupCreationOptions , ok := mirrorMapping .Groups [parentGroupPath ]
140+ if ! ok {
141+ zap .L ().Error ("Group not found in mirror mapping" , zap .String ("group" , parentGroupPath ))
142+ return
143+ }
144+
145+ // Calculate the relative path between the group and the parent group
146+ relativePath , err := filepath .Rel (parentGroupPath , group .FullPath )
147+ if err != nil {
148+ zap .L ().Error ("Failed to calculate relative path for group" , zap .String ("group" , group .FullPath ), zap .String ("parentGroup" , parentGroupPath ), zap .Error (err ))
149+ return
150+ }
151+
152+ // Add the group to the mirror mapping
153+ mirrorMapping .AddGroup (group .FullPath , & utils.MirroringOptions {
154+ DestinationPath : filepath .Join (groupCreationOptions .DestinationPath , relativePath ),
155+ CI_CD_Catalog : groupCreationOptions .CI_CD_Catalog ,
156+ Issues : groupCreationOptions .Issues ,
157+ MirrorTriggerBuilds : groupCreationOptions .MirrorTriggerBuilds ,
158+ Visibility : groupCreationOptions .Visibility ,
159+ MirrorReleases : groupCreationOptions .MirrorReleases ,
160+ })
161+ }
162+ } else {
163+ zap .L ().Error ("Failed to store group in mirror mapping: nil group" )
164+ }
165+ }
166+
167+ // checkPathMatchesFilters checks if the resources matches the filters
168+ // - either is in the projects map
169+ // - or path starts with any of the groups in the groups map
170+ //
171+ // In the case of a match with a group, it returns the group path
172+ func (g * GitlabInstance ) checkPathMatchesFilters (resourcePath string , projectFilters * map [string ]bool , groupFilters * map [string ]bool ) (string , bool ) {
173+ zap .L ().Debug ("Checking if path matches filters" , zap .String ("path" , resourcePath ))
174+ if projectFilters != nil {
175+ if _ , ok := (* projectFilters )[resourcePath ]; ok {
176+ zap .L ().Debug ("Resource path matches project filter" , zap .String ("project" , resourcePath ))
177+ return "" , true
178+ }
179+ }
180+ if groupFilters != nil {
181+ for groupPath := range * groupFilters {
182+ if strings .HasPrefix (resourcePath , groupPath ) {
183+ zap .L ().Debug ("Resource path matches group filter" , zap .String ("resource" , resourcePath ), zap .String ("group" , groupPath ))
184+ return groupPath , true
185+ }
186+ }
187+ }
188+ return "" , false
189+ }
190+
191+ // fetchAll retrieves all projects and groups from the GitLab instance
192+ // that match the filters and stores them in the instance cache.
157193func fetchAll (gitlabInstance * GitlabInstance , projectFilters map [string ]bool , groupFilters map [string ]bool , mirrorMapping * utils.MirrorMapping , isSource bool ) error {
158194 wg := sync.WaitGroup {}
159195 errCh := make (chan error , 2 )
@@ -176,6 +212,10 @@ func fetchAll(gitlabInstance *GitlabInstance, projectFilters map[string]bool, gr
176212 return utils .MergeErrors (errCh , 2 )
177213}
178214
215+ // getParentNamespaceID retrieves the parent namespace ID for a given project or group path.
216+ // It checks if the parent path is already in the instance groups cache.
217+ //
218+ // If not, it returns an error indicating that the parent group was not found.
179219func (g * GitlabInstance ) getParentNamespaceID (projectOrGroupPath string ) (int , error ) {
180220 parentGroupID := - 1
181221 parentPath := filepath .Dir (projectOrGroupPath )
0 commit comments