@@ -93,6 +93,28 @@ func resourceGitlabProject() *schema.Resource {
93
93
Type : schema .TypeString ,
94
94
Computed : true ,
95
95
},
96
+ "shared_with_groups" : {
97
+ Type : schema .TypeList ,
98
+ Optional : true ,
99
+ Elem : & schema.Resource {
100
+ Schema : map [string ]* schema.Schema {
101
+ "group_id" : {
102
+ Type : schema .TypeInt ,
103
+ Required : true ,
104
+ },
105
+ "group_access_level" : {
106
+ Type : schema .TypeString ,
107
+ Required : true ,
108
+ ValidateFunc : validation .StringInSlice ([]string {
109
+ "guest" , "reporter" , "developer" , "master" }, false ),
110
+ },
111
+ "group_name" : {
112
+ Type : schema .TypeString ,
113
+ Computed : true ,
114
+ },
115
+ },
116
+ },
117
+ },
96
118
},
97
119
}
98
120
}
@@ -114,6 +136,7 @@ func resourceGitlabProjectSetToState(d *schema.ResourceData, project *gitlab.Pro
114
136
d .Set ("http_url_to_repo" , project .HTTPURLToRepo )
115
137
d .Set ("web_url" , project .WebURL )
116
138
d .Set ("runners_token" , project .RunnersToken )
139
+ d .Set ("shared_with_groups" , flattenSharedWithGroupsOptions (project ))
117
140
}
118
141
119
142
func resourceGitlabProjectCreate (d * schema.ResourceData , meta interface {}) error {
@@ -146,6 +169,17 @@ func resourceGitlabProjectCreate(d *schema.ResourceData, meta interface{}) error
146
169
return err
147
170
}
148
171
172
+ if v , ok := d .GetOk ("shared_with_groups" ); ok {
173
+ options := expandSharedWithGroupsOptions (v .([]interface {}))
174
+
175
+ for _ , option := range options {
176
+ _ , err := client .Projects .ShareProjectWithGroup (project .ID , option )
177
+ if err != nil {
178
+ return err
179
+ }
180
+ }
181
+ }
182
+
149
183
d .SetId (fmt .Sprintf ("%d" , project .ID ))
150
184
151
185
return resourceGitlabProjectRead (d , meta )
@@ -211,11 +245,16 @@ func resourceGitlabProjectUpdate(d *schema.ResourceData, meta interface{}) error
211
245
options .SnippetsEnabled = gitlab .Bool (d .Get ("snippets_enabled" ).(bool ))
212
246
}
213
247
214
- log .Printf ("[DEBUG] update gitlab project %s" , d .Id ())
248
+ if * options != (gitlab.EditProjectOptions {}) {
249
+ log .Printf ("[DEBUG] update gitlab project %s" , d .Id ())
250
+ _ , _ , err := client .Projects .EditProject (d .Id (), options )
251
+ if err != nil {
252
+ return err
253
+ }
254
+ }
215
255
216
- _ , _ , err := client .Projects .EditProject (d .Id (), options )
217
- if err != nil {
218
- return err
256
+ if d .HasChange ("shared_with_groups" ) {
257
+ updateSharedWithGroups (d , meta )
219
258
}
220
259
221
260
return resourceGitlabProjectRead (d , meta )
@@ -258,3 +297,122 @@ func resourceGitlabProjectDelete(d *schema.ResourceData, meta interface{}) error
258
297
}
259
298
return nil
260
299
}
300
+
301
+ func expandSharedWithGroupsOptions (d []interface {}) []* gitlab.ShareWithGroupOptions {
302
+ shareWithGroupOptionsList := []* gitlab.ShareWithGroupOptions {}
303
+
304
+ for _ , config := range d {
305
+ data := config .(map [string ]interface {})
306
+
307
+ groupAccess := accessLevelNameToValue [data ["group_access_level" ].(string )]
308
+
309
+ shareWithGroupOptions := & gitlab.ShareWithGroupOptions {
310
+ GroupID : gitlab .Int (data ["group_id" ].(int )),
311
+ GroupAccess : & groupAccess ,
312
+ }
313
+
314
+ shareWithGroupOptionsList = append (shareWithGroupOptionsList ,
315
+ shareWithGroupOptions )
316
+ }
317
+
318
+ return shareWithGroupOptionsList
319
+ }
320
+
321
+ func flattenSharedWithGroupsOptions (project * gitlab.Project ) []interface {} {
322
+ sharedWithGroups := project .SharedWithGroups
323
+ sharedWithGroupsList := []interface {}{}
324
+
325
+ for _ , option := range sharedWithGroups {
326
+ values := map [string ]interface {}{
327
+ "group_id" : option .GroupID ,
328
+ "group_access_level" : accessLevelValueToName [gitlab .AccessLevelValue (
329
+ option .GroupAccessLevel )],
330
+ "group_name" : option .GroupName ,
331
+ }
332
+
333
+ sharedWithGroupsList = append (sharedWithGroupsList , values )
334
+ }
335
+
336
+ return sharedWithGroupsList
337
+ }
338
+
339
+ func findGroupProjectSharedWith (target * gitlab.ShareWithGroupOptions ,
340
+ groups []* gitlab.ShareWithGroupOptions ) (* gitlab.ShareWithGroupOptions , int , error ) {
341
+ for i , group := range groups {
342
+ if * group .GroupID == * target .GroupID {
343
+ return group , i , nil
344
+ }
345
+ }
346
+
347
+ return nil , 0 , fmt .Errorf ("group not found" )
348
+ }
349
+
350
+ func getGroupsProjectSharedWith (project * gitlab.Project ) []* gitlab.ShareWithGroupOptions {
351
+ sharedGroups := []* gitlab.ShareWithGroupOptions {}
352
+
353
+ for _ , group := range project .SharedWithGroups {
354
+ sharedGroups = append (sharedGroups , & gitlab.ShareWithGroupOptions {
355
+ GroupID : gitlab .Int (group .GroupID ),
356
+ GroupAccess : gitlab .AccessLevel (gitlab .AccessLevelValue (
357
+ group .GroupAccessLevel )),
358
+ })
359
+ }
360
+
361
+ return sharedGroups
362
+ }
363
+
364
+ func updateSharedWithGroups (d * schema.ResourceData , meta interface {}) error {
365
+ client := meta .(* gitlab.Client )
366
+
367
+ var groupsToUnshare []* gitlab.ShareWithGroupOptions
368
+ var groupsToShare []* gitlab.ShareWithGroupOptions
369
+
370
+ // Get target groups from the TF config and current groups from Gitlab server
371
+ targetGroups := expandSharedWithGroupsOptions (
372
+ d .Get ("shared_with_groups" ).([]interface {}))
373
+ project , _ , err := client .Projects .GetProject (d .Id ())
374
+ if err != nil {
375
+ return err
376
+ }
377
+ currentGroups := getGroupsProjectSharedWith (project )
378
+
379
+ for _ , targetGroup := range targetGroups {
380
+ currentGroup , index , err := findGroupProjectSharedWith (targetGroup , currentGroups )
381
+
382
+ // If no corresponding group is found, it must be added
383
+ if err != nil {
384
+ groupsToShare = append (groupsToShare , targetGroup )
385
+ continue
386
+ }
387
+
388
+ // If group is different it must be deleted and added again
389
+ if * targetGroup .GroupAccess != * currentGroup .GroupAccess {
390
+ groupsToShare = append (groupsToShare , targetGroup )
391
+ groupsToUnshare = append (groupsToUnshare , targetGroup )
392
+ }
393
+
394
+ // Remove currentGroup from from list
395
+ currentGroups = append (currentGroups [:index ], currentGroups [index + 1 :]... )
396
+ }
397
+
398
+ // All groups still present in currentGroup must be deleted
399
+ groupsToUnshare = append (groupsToUnshare , currentGroups ... )
400
+
401
+ // Unshare groups to delete and update
402
+ for _ , group := range groupsToUnshare {
403
+ _ , err := client .Projects .DeleteSharedProjectFromGroup (d .Id (), * group .GroupID )
404
+ if err != nil {
405
+ return err
406
+ }
407
+ }
408
+
409
+ // Share groups to add and update
410
+ for _ , group := range groupsToShare {
411
+ _ , err := client .Projects .ShareProjectWithGroup (d .Id (), group )
412
+ if err != nil {
413
+ return err
414
+ }
415
+ }
416
+
417
+ return nil
418
+ }
0 commit comments