Skip to content

Commit 30ae70c

Browse files
committed
resource/gitlab_project_protected_environment: Allow multiple deploy_access_levels
1 parent 2b3d413 commit 30ae70c

File tree

4 files changed

+150
-379
lines changed

4 files changed

+150
-379
lines changed

docs/resources/project_protected_environment.md

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,50 +16,58 @@ The `gitlab_project_protected_environment` resource allows to manage the lifecyc
1616
## Example Usage
1717

1818
```terraform
19-
resource "gitlab_group" "this" {
20-
name = "example"
21-
path = "example"
22-
description = "An example group"
23-
}
24-
25-
resource "gitlab_project" "this" {
26-
name = "example"
27-
namespace_id = gitlab_group.this.id
28-
initialize_with_readme = true
29-
}
30-
3119
resource "gitlab_project_environment" "this" {
32-
project = gitlab_project.this.id
20+
project = 123
3321
name = "example"
3422
external_url = "www.example.com"
3523
}
3624
37-
resource "gitlab_project_protected_environment" "this" {
38-
project = gitlab_project.this.id
25+
# Example with access level
26+
resource "gitlab_project_protected_environment" "example_with_access_level" {
27+
project = gitlab_project_environment.this.project
3928
environment = gitlab_project_environment.this.name
4029
4130
deploy_access_levels {
4231
access_level = "developer"
4332
}
4433
}
4534
46-
resource "gitlab_project_protected_environment" "this" {
47-
project = gitlab_project.this.id
35+
# Example with group
36+
resource "gitlab_project_protected_environment" "example_with_group" {
37+
project = gitlab_project_environment.this.project
38+
environment = gitlab_project_environment.this.name
39+
40+
deploy_access_levels {
41+
group_id = 456
42+
}
43+
}
44+
45+
# Example with user
46+
resource "gitlab_project_protected_environment" "example_with_user" {
47+
project = gitlab_project_environment.this.project
4848
environment = gitlab_project_environment.this.name
4949
5050
deploy_access_levels {
51-
group_id = gitlab_group.test.id
51+
user_id = 789
5252
}
5353
}
5454
55-
resource "gitlab_project_protected_environment" "this" {
56-
project = gitlab_project.this.id
55+
# Example with multiple access levels
56+
resource "gitlab_project_protected_environment" "example_with_multiple" {
57+
project = gitlab_project_environment.this.project
5758
environment = gitlab_project_environment.this.name
5859
5960
deploy_access_levels {
60-
user_id = gitlab_user.test.id
61+
access_level = "developer"
62+
}
63+
64+
deploy_access_levels {
65+
group_id = 456
6166
}
6267
68+
deploy_access_levels {
69+
user_id = 789
70+
}
6371
}
6472
```
6573

@@ -68,7 +76,7 @@ resource "gitlab_project_protected_environment" "this" {
6876

6977
### Required
7078

71-
- `deploy_access_levels` (Block List, Min: 1, Max: 1) Array of access levels allowed to deploy, with each described by a hash. (see [below for nested schema](#nestedblock--deploy_access_levels))
79+
- `deploy_access_levels` (Block List, Min: 1) Array of access levels allowed to deploy, with each described by a hash. (see [below for nested schema](#nestedblock--deploy_access_levels))
7280
- `environment` (String) The name of the environment.
7381
- `project` (String) The ID or full path of the project which the protected environment is created against.
7482

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,53 @@
1-
resource "gitlab_group" "this" {
2-
name = "example"
3-
path = "example"
4-
description = "An example group"
5-
}
6-
7-
resource "gitlab_project" "this" {
8-
name = "example"
9-
namespace_id = gitlab_group.this.id
10-
initialize_with_readme = true
11-
}
12-
131
resource "gitlab_project_environment" "this" {
14-
project = gitlab_project.this.id
2+
project = 123
153
name = "example"
164
external_url = "www.example.com"
175
}
186

19-
resource "gitlab_project_protected_environment" "this" {
20-
project = gitlab_project.this.id
7+
# Example with access level
8+
resource "gitlab_project_protected_environment" "example_with_access_level" {
9+
project = gitlab_project_environment.this.project
2110
environment = gitlab_project_environment.this.name
2211

2312
deploy_access_levels {
2413
access_level = "developer"
2514
}
2615
}
2716

28-
resource "gitlab_project_protected_environment" "this" {
29-
project = gitlab_project.this.id
17+
# Example with group
18+
resource "gitlab_project_protected_environment" "example_with_group" {
19+
project = gitlab_project_environment.this.project
20+
environment = gitlab_project_environment.this.name
21+
22+
deploy_access_levels {
23+
group_id = 456
24+
}
25+
}
26+
27+
# Example with user
28+
resource "gitlab_project_protected_environment" "example_with_user" {
29+
project = gitlab_project_environment.this.project
3030
environment = gitlab_project_environment.this.name
3131

3232
deploy_access_levels {
33-
group_id = gitlab_group.test.id
33+
user_id = 789
3434
}
3535
}
3636

37-
resource "gitlab_project_protected_environment" "this" {
38-
project = gitlab_project.this.id
37+
# Example with multiple access levels
38+
resource "gitlab_project_protected_environment" "example_with_multiple" {
39+
project = gitlab_project_environment.this.project
3940
environment = gitlab_project_environment.this.name
4041

4142
deploy_access_levels {
42-
user_id = gitlab_user.test.id
43+
access_level = "developer"
44+
}
45+
46+
deploy_access_levels {
47+
group_id = 456
4348
}
4449

50+
deploy_access_levels {
51+
user_id = 789
52+
}
4553
}

internal/provider/resource_gitlab_project_protected_environment.go

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,13 @@ var _ = registerResource("gitlab_project_protected_environment", func() *schema.
4040
},
4141
// Uncomment and validate after 14.9 is released, update acceptance tests
4242
// "required_approval_count": {
43-
// Description: "The number of approvals required to deploy to this environment. This is part of Deployment Approvals, which isn't yet available for use.",
44-
// Type: schema.TypeString,
43+
// Description: "The number of approvals required to deploy to this environment.",
44+
// Type: schema.TypeInt,
4545
// ForceNew: true,
46-
// Required: false,
47-
// ValidateFunc: validation.StringIsNotEmpty,
4846
// },
4947
"deploy_access_levels": {
5048
Description: "Array of access levels allowed to deploy, with each described by a hash.",
5149
Type: schema.TypeList,
52-
MaxItems: 1,
5350
ForceNew: true,
5451
Required: true,
5552
Elem: &schema.Resource{
@@ -59,7 +56,7 @@ var _ = registerResource("gitlab_project_protected_environment", func() *schema.
5956
Type: schema.TypeString,
6057
ForceNew: true,
6158
Optional: true,
62-
Computed: true,
59+
Computed: true, // When user_id or group_id is specified, the GitLab API still returns an access_level in the response.
6360
ValidateFunc: validation.StringInSlice(validProtectedEnvironmentDeploymentLevelNames, false),
6461
},
6562
"access_level_description": {
@@ -89,7 +86,11 @@ var _ = registerResource("gitlab_project_protected_environment", func() *schema.
8986
})
9087

9188
func resourceGitlabProjectProtectedEnvironmentCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
92-
deployAccessLevels := expandDeployAccessLevels(d.Get("deploy_access_levels").([]interface{}))
89+
deployAccessLevels, err := expandDeployAccessLevels(d.Get("deploy_access_levels").([]interface{}))
90+
if err != nil {
91+
return diag.FromErr(err)
92+
}
93+
9394
options := &gitlab.ProtectRepositoryEnvironmentsOptions{
9495
Name: gitlab.String(d.Get("environment").(string)),
9596
DeployAccessLevels: &deployAccessLevels,
@@ -162,41 +163,58 @@ func resourceGitlabProjectProtectedEnvironmentDelete(ctx context.Context, d *sch
162163
return nil
163164
}
164165

165-
func expandDeployAccessLevels(vs []interface{}) []*gitlab.EnvironmentAccessOptions {
166-
result := make([]*gitlab.EnvironmentAccessOptions, 0)
166+
func expandDeployAccessLevels(vs []interface{}) ([]*gitlab.EnvironmentAccessOptions, error) {
167+
result := make([]*gitlab.EnvironmentAccessOptions, len(vs))
167168

168-
for _, v := range vs {
169+
for i, v := range vs {
169170
opts := v.(map[string]interface{})
170171
option := &gitlab.EnvironmentAccessOptions{}
172+
count := 0
173+
171174
if accessLevel, ok := opts["access_level"]; ok && accessLevel != "" {
172175
option.AccessLevel = gitlab.AccessLevel(accessLevelNameToValue[accessLevel.(string)])
173-
} else if userID, ok := opts["user_id"]; ok && userID != 0 {
176+
count++
177+
}
178+
179+
if userID, ok := opts["user_id"]; ok && userID != 0 {
174180
option.UserID = gitlab.Int(userID.(int))
175-
} else if groupID, ok := opts["group_id"]; ok && groupID != 0 {
181+
count++
182+
}
183+
184+
if groupID, ok := opts["group_id"]; ok && groupID != 0 {
176185
option.GroupID = gitlab.Int(groupID.(int))
186+
count++
187+
}
188+
189+
// This is a manual "ExactlyOneOf" schema check, since this cannot be validated at the
190+
// schema-level inside of a list.
191+
// See: https://github.com/hashicorp/terraform-plugin-sdk/blob/0f834ffb1619ce1ef8d3f5255911108ede086ef9/helper/schema/schema.go#L278
192+
if count != 1 {
193+
return nil, fmt.Errorf(`illegal deploy_access_levels.%d: exactly one of "access_level", "user_id", or "group_id" must be specified (got %d)`, i, count)
177194
}
178-
result = append(result, option)
195+
196+
result[i] = option
179197
}
180198

181-
return result
199+
return result, nil
182200
}
183201

184202
func flattenDeployAccessLevels(accessDescriptions []*gitlab.EnvironmentAccessDescription) []map[string]interface{} {
185-
result := make([]map[string]interface{}, 0)
203+
result := make([]map[string]interface{}, len(accessDescriptions))
186204

187-
for _, accessDescription := range accessDescriptions {
205+
for i, accessDescription := range accessDescriptions {
188206
v := make(map[string]interface{})
207+
v["access_level_description"] = accessDescription.AccessLevelDescription
189208
if accessDescription.AccessLevel != 0 {
190209
v["access_level"] = accessLevelValueToName[accessDescription.AccessLevel]
191-
v["access_level_description"] = accessDescription.AccessLevelDescription
192210
}
193211
if accessDescription.UserID != 0 {
194212
v["user_id"] = accessDescription.UserID
195213
}
196214
if accessDescription.GroupID != 0 {
197215
v["group_id"] = accessDescription.GroupID
198216
}
199-
result = append(result, v)
217+
result[i] = v
200218
}
201219

202220
return result

0 commit comments

Comments
 (0)