Skip to content

Commit ab0e4e1

Browse files
committed
Add code_owner_approval_required argument to gitlab_branch_protection resource
1 parent 52ed810 commit ab0e4e1

File tree

4 files changed

+140
-10
lines changed

4 files changed

+140
-10
lines changed

gitlab/resource_gitlab_branch_protection.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ func resourceGitlabBranchProtection() *schema.Resource {
4040
Required: true,
4141
ForceNew: true,
4242
},
43+
"code_owner_approval_required": {
44+
Type: schema.TypeBool,
45+
Optional: true,
46+
},
4347
},
4448
}
4549
}
@@ -50,11 +54,13 @@ func resourceGitlabBranchProtectionCreate(d *schema.ResourceData, meta interface
5054
branch := gitlab.String(d.Get("branch").(string))
5155
mergeAccessLevel := accessLevelID[d.Get("merge_access_level").(string)]
5256
pushAccessLevel := accessLevelID[d.Get("push_access_level").(string)]
57+
codeOwnerApprovalRequired := getOptionalBool(d, "code_owner_approval_required")
5358

5459
options := &gitlab.ProtectRepositoryBranchesOptions{
55-
Name: branch,
56-
MergeAccessLevel: &mergeAccessLevel,
57-
PushAccessLevel: &pushAccessLevel,
60+
Name: branch,
61+
MergeAccessLevel: &mergeAccessLevel,
62+
PushAccessLevel: &pushAccessLevel,
63+
CodeOwnerApprovalRequired: codeOwnerApprovalRequired,
5864
}
5965

6066
log.Printf("[DEBUG] create gitlab branch protection on %v for project %s", options.Name, project)
@@ -98,6 +104,7 @@ func resourceGitlabBranchProtectionRead(d *schema.ResourceData, meta interface{}
98104
d.Set("branch", pb.Name)
99105
d.Set("merge_access_level", accessLevel[pb.MergeAccessLevels[0].AccessLevel])
100106
d.Set("push_access_level", accessLevel[pb.PushAccessLevels[0].AccessLevel])
107+
d.Set("code_owner_approval_required", pb.CodeOwnerApprovalRequired)
101108

102109
d.SetId(buildTwoPartID(&project, &pb.Name))
103110

gitlab/resource_gitlab_branch_protection_test.go

Lines changed: 115 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package gitlab
22

33
import (
44
"fmt"
5+
"strconv"
56
"testing"
67

78
"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
@@ -59,6 +60,66 @@ func TestAccGitlabBranchProtection_basic(t *testing.T) {
5960
}),
6061
),
6162
},
63+
// Update the the Branch Protection code owner approval setting
64+
{
65+
SkipFunc: isRunningInCE,
66+
Config: testAccGitlabBranchProtectionUpdateConfigCodeOwnerTrue(rInt),
67+
Check: resource.ComposeTestCheckFunc(
68+
testAccCheckGitlabBranchProtectionExists("gitlab_branch_protection.BranchProtect", &pb),
69+
testAccCheckGitlabBranchProtectionPersistsInStateCorrectly("gitlab_branch_protection.BranchProtect", &pb),
70+
testAccCheckGitlabBranchProtectionAttributes(&pb, &testAccGitlabBranchProtectionExpectedAttributes{
71+
Name: fmt.Sprintf("BranchProtect-%d", rInt),
72+
PushAccessLevel: accessLevel[gitlab.DeveloperPermissions],
73+
MergeAccessLevel: accessLevel[gitlab.DeveloperPermissions],
74+
CodeOwnerApprovalRequired: true,
75+
}),
76+
),
77+
},
78+
// Update the Branch Protection to get back to initial settings.
79+
// Since code_owner_approval_required is an optional setting, it does not revert to its original setting.
80+
// This test ensures that the addition of this optional value is backward compatible and does not overwrite existing settings in GitLab when it is unset.
81+
{
82+
SkipFunc: isRunningInCE,
83+
Config: testAccGitlabBranchProtectionConfig(rInt),
84+
Check: resource.ComposeTestCheckFunc(
85+
testAccCheckGitlabBranchProtectionExists("gitlab_branch_protection.BranchProtect", &pb),
86+
testAccCheckGitlabBranchProtectionPersistsInStateCorrectly("gitlab_branch_protection.BranchProtect", &pb),
87+
testAccCheckGitlabBranchProtectionAttributes(&pb, &testAccGitlabBranchProtectionExpectedAttributes{
88+
Name: fmt.Sprintf("BranchProtect-%d", rInt),
89+
PushAccessLevel: accessLevel[gitlab.DeveloperPermissions],
90+
MergeAccessLevel: accessLevel[gitlab.DeveloperPermissions],
91+
CodeOwnerApprovalRequired: true,
92+
}),
93+
),
94+
},
95+
// Update the the Branch Protection to explicitly disable code owner approval, to truly reset state back to initial settings.
96+
{
97+
SkipFunc: isRunningInCE,
98+
Config: testAccGitlabBranchProtectionUpdateConfigCodeOwnerFalse(rInt),
99+
Check: resource.ComposeTestCheckFunc(
100+
testAccCheckGitlabBranchProtectionExists("gitlab_branch_protection.BranchProtect", &pb),
101+
testAccCheckGitlabBranchProtectionPersistsInStateCorrectly("gitlab_branch_protection.BranchProtect", &pb),
102+
testAccCheckGitlabBranchProtectionAttributes(&pb, &testAccGitlabBranchProtectionExpectedAttributes{
103+
Name: fmt.Sprintf("BranchProtect-%d", rInt),
104+
PushAccessLevel: accessLevel[gitlab.DeveloperPermissions],
105+
MergeAccessLevel: accessLevel[gitlab.DeveloperPermissions],
106+
}),
107+
),
108+
},
109+
// Update the Branch Protection to get back to initial settings.
110+
{
111+
SkipFunc: isRunningInCE,
112+
Config: testAccGitlabBranchProtectionConfig(rInt),
113+
Check: resource.ComposeTestCheckFunc(
114+
testAccCheckGitlabBranchProtectionExists("gitlab_branch_protection.BranchProtect", &pb),
115+
testAccCheckGitlabBranchProtectionPersistsInStateCorrectly("gitlab_branch_protection.BranchProtect", &pb),
116+
testAccCheckGitlabBranchProtectionAttributes(&pb, &testAccGitlabBranchProtectionExpectedAttributes{
117+
Name: fmt.Sprintf("BranchProtect-%d", rInt),
118+
PushAccessLevel: accessLevel[gitlab.DeveloperPermissions],
119+
MergeAccessLevel: accessLevel[gitlab.DeveloperPermissions],
120+
}),
121+
),
122+
},
62123
},
63124
})
64125
}
@@ -78,6 +139,10 @@ func testAccCheckGitlabBranchProtectionPersistsInStateCorrectly(n string, pb *gi
78139
return fmt.Errorf("push access level not persisted in state correctly")
79140
}
80141

142+
if rs.Primary.Attributes["code_owner_approval_required"] != strconv.FormatBool(pb.CodeOwnerApprovalRequired) {
143+
return fmt.Errorf("code_owner_approval_required not persisted in state correctly")
144+
}
145+
81146
return nil
82147
}
83148
}
@@ -110,9 +175,10 @@ func testAccCheckGitlabBranchProtectionExists(n string, pb *gitlab.ProtectedBran
110175
}
111176

112177
type testAccGitlabBranchProtectionExpectedAttributes struct {
113-
Name string
114-
PushAccessLevel string
115-
MergeAccessLevel string
178+
Name string
179+
PushAccessLevel string
180+
MergeAccessLevel string
181+
CodeOwnerApprovalRequired bool
116182
}
117183

118184
func testAccCheckGitlabBranchProtectionAttributes(pb *gitlab.ProtectedBranch, want *testAccGitlabBranchProtectionExpectedAttributes) resource.TestCheckFunc {
@@ -129,6 +195,10 @@ func testAccCheckGitlabBranchProtectionAttributes(pb *gitlab.ProtectedBranch, wa
129195
return fmt.Errorf("got Merge access levels %q; want %q", pb.MergeAccessLevels[0].AccessLevel, accessLevelID[want.MergeAccessLevel])
130196
}
131197

198+
if pb.CodeOwnerApprovalRequired != want.CodeOwnerApprovalRequired {
199+
return fmt.Errorf("got code_owner_approval_required %v; want %v", pb.CodeOwnerApprovalRequired, want.CodeOwnerApprovalRequired)
200+
}
201+
132202
return nil
133203
}
134204
}
@@ -196,3 +266,45 @@ resource "gitlab_branch_protection" "BranchProtect" {
196266
}
197267
`, rInt, rInt)
198268
}
269+
270+
func testAccGitlabBranchProtectionUpdateConfigCodeOwnerTrue(rInt int) string {
271+
return fmt.Sprintf(`
272+
resource "gitlab_project" "foo" {
273+
name = "foo-%d"
274+
description = "Terraform acceptance tests"
275+
276+
# So that acceptance tests can be run in a gitlab organization
277+
# with no billing
278+
visibility_level = "public"
279+
}
280+
281+
resource "gitlab_branch_protection" "BranchProtect" {
282+
project = "${gitlab_project.foo.id}"
283+
branch = "BranchProtect-%d"
284+
push_access_level = "developer"
285+
merge_access_level = "developer"
286+
code_owner_approval_required = true
287+
}
288+
`, rInt, rInt)
289+
}
290+
291+
func testAccGitlabBranchProtectionUpdateConfigCodeOwnerFalse(rInt int) string {
292+
return fmt.Sprintf(`
293+
resource "gitlab_project" "foo" {
294+
name = "foo-%d"
295+
description = "Terraform acceptance tests"
296+
297+
# So that acceptance tests can be run in a gitlab organization
298+
# with no billing
299+
visibility_level = "public"
300+
}
301+
302+
resource "gitlab_branch_protection" "BranchProtect" {
303+
project = "${gitlab_project.foo.id}"
304+
branch = "BranchProtect-%d"
305+
push_access_level = "developer"
306+
merge_access_level = "developer"
307+
code_owner_approval_required = false
308+
}
309+
`, rInt, rInt)
310+
}

gitlab/util.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,12 @@ func stringSetToStringSlice(stringSet *schema.Set) *[]string {
190190
}
191191
return &ret
192192
}
193+
194+
func getOptionalBool(d *schema.ResourceData, key string) *bool {
195+
var result *bool
196+
if value, isSet := d.GetOk(key); isSet {
197+
valueBool := value.(bool)
198+
result = &valueBool
199+
}
200+
return result
201+
}

website/docs/r/branch_protection.html.markdown

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,12 @@ resource "gitlab_branch_protection" "BranchProtect" {
2525

2626
The following arguments are supported:
2727

28-
* `project` - (Required) The id of the project.
28+
* `project` - (Required, string) The id of the project.
2929

30-
* `branch` - (Required) Name of the branch.
30+
* `branch` - (Required, string) Name of the branch.
3131

32-
* `push_access_level` - (Required) One of five levels of access to the project.
32+
* `push_access_level` - (Required, string) One of five levels of access to the project.
3333

34-
* `merge_access_level` - (Required) One of five levels of access to the project.
34+
* `merge_access_level` - (Required, string) One of five levels of access to the project.
35+
36+
* `code_owner_approval_required` (Optional, bool) Can be set to true to enable code owner approval requirement. Requires GitLab Silver/Premium.

0 commit comments

Comments
 (0)