Skip to content

Commit 3225aaa

Browse files
authored
Merge pull request #877 from beekeep/feat_branch_protection_force_push
Add branch protection support for allow_force_push
2 parents e3a911c + a073f36 commit 3225aaa

File tree

4 files changed

+126
-0
lines changed

4 files changed

+126
-0
lines changed

docs/resources/branch_protection.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ resource "gitlab_branch_protection" "BranchProtect" {
2121
branch = "BranchProtected"
2222
push_access_level = "developer"
2323
merge_access_level = "developer"
24+
allow_force_push = true
2425
code_owner_approval_required = true
2526
allowed_to_push {
2627
user_id = 5
@@ -64,6 +65,7 @@ resource "gitlab_branch_protection" "main" {
6465

6566
### Optional
6667

68+
- **allow_force_push** (Boolean) Can be set to true to allow users with push access to force push.
6769
- **allowed_to_merge** (Block Set) Defines permissions for action. (see [below for nested schema](#nestedblock--allowed_to_merge))
6870
- **allowed_to_push** (Block Set) Defines permissions for action. (see [below for nested schema](#nestedblock--allowed_to_push))
6971
- **code_owner_approval_required** (Boolean) Can be set to true to require code owner approval before merging.

examples/resources/gitlab_branch_protection/resource.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ resource "gitlab_branch_protection" "BranchProtect" {
33
branch = "BranchProtected"
44
push_access_level = "developer"
55
merge_access_level = "developer"
6+
allow_force_push = true
67
code_owner_approval_required = true
78
allowed_to_push {
89
user_id = 5

internal/provider/resource_gitlab_branch_protection.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@ var _ = registerResource("gitlab_branch_protection", func() *schema.Resource {
7878
Required: true,
7979
ForceNew: true,
8080
},
81+
"allow_force_push": {
82+
Description: "Can be set to true to allow users with push access to force push.",
83+
Type: schema.TypeBool,
84+
Optional: true,
85+
Default: false,
86+
ForceNew: true,
87+
},
8188
"allowed_to_push": schemaAllowedTo(),
8289
"allowed_to_merge": schemaAllowedTo(),
8390
"code_owner_approval_required": {
@@ -114,6 +121,7 @@ func resourceGitlabBranchProtectionCreate(ctx context.Context, d *schema.Resourc
114121

115122
mergeAccessLevel := accessLevelNameToValue[d.Get("merge_access_level").(string)]
116123
pushAccessLevel := accessLevelNameToValue[d.Get("push_access_level").(string)]
124+
allowForcePush := d.Get("allow_force_push").(bool)
117125
codeOwnerApprovalRequired := d.Get("code_owner_approval_required").(bool)
118126

119127
allowedToPush := expandBranchPermissionOptions(d.Get("allowed_to_push").(*schema.Set).List())
@@ -123,6 +131,7 @@ func resourceGitlabBranchProtectionCreate(ctx context.Context, d *schema.Resourc
123131
Name: &branch,
124132
PushAccessLevel: &pushAccessLevel,
125133
MergeAccessLevel: &mergeAccessLevel,
134+
AllowForcePush: &allowForcePush,
126135
AllowedToPush: &allowedToPush,
127136
AllowedToMerge: &allowedToMerge,
128137
CodeOwnerApprovalRequired: &codeOwnerApprovalRequired,
@@ -174,6 +183,10 @@ func resourceGitlabBranchProtectionRead(ctx context.Context, d *schema.ResourceD
174183
}
175184
}
176185

186+
if err := d.Set("allow_force_push", pb.AllowForcePush); err != nil {
187+
return diag.Errorf("error setting allow_force_push: %v", err)
188+
}
189+
177190
// lintignore: R004 // TODO: Resolve this tfproviderlint issue
178191
if err := d.Set("allowed_to_push", convertAllowedToToBranchAccessDescriptions(pb.PushAccessLevels)); err != nil {
179192
return diag.Errorf("error setting allowed_to_push: %v", err)

internal/provider/resource_gitlab_branch_protection_test.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,33 @@ func TestAccGitlabBranchProtection_basic(t *testing.T) {
6262
}),
6363
),
6464
},
65+
// Update the Branch Protection with allow force push enabled
66+
{
67+
Config: testAccGitlabBranchProtectionUpdateConfigAllowForcePushTrue(rInt),
68+
Check: resource.ComposeTestCheckFunc(
69+
testAccCheckGitlabBranchProtectionExists("gitlab_branch_protection.branch_protect", &pb),
70+
testAccCheckGitlabBranchProtectionPersistsInStateCorrectly("gitlab_branch_protection.branch_protect", &pb),
71+
testAccCheckGitlabBranchProtectionAttributes(&pb, &testAccGitlabBranchProtectionExpectedAttributes{
72+
Name: fmt.Sprintf("BranchProtect-%d", rInt),
73+
PushAccessLevel: accessLevelValueToName[gitlab.DeveloperPermissions],
74+
MergeAccessLevel: accessLevelValueToName[gitlab.DeveloperPermissions],
75+
AllowForcePush: true,
76+
}),
77+
),
78+
},
79+
// Update the Branch Protection to get back to initial settings
80+
{
81+
Config: testAccGitlabBranchProtectionConfig(rInt),
82+
Check: resource.ComposeTestCheckFunc(
83+
testAccCheckGitlabBranchProtectionExists("gitlab_branch_protection.branch_protect", &pb),
84+
testAccCheckGitlabBranchProtectionPersistsInStateCorrectly("gitlab_branch_protection.branch_protect", &pb),
85+
testAccCheckGitlabBranchProtectionAttributes(&pb, &testAccGitlabBranchProtectionExpectedAttributes{
86+
Name: fmt.Sprintf("BranchProtect-%d", rInt),
87+
PushAccessLevel: accessLevelValueToName[gitlab.DeveloperPermissions],
88+
MergeAccessLevel: accessLevelValueToName[gitlab.DeveloperPermissions],
89+
}),
90+
),
91+
},
6592
// Update the the Branch Protection code owner approval setting
6693
{
6794
SkipFunc: isRunningInCE,
@@ -180,6 +207,59 @@ func TestAccGitlabBranchProtection_createWithCodeOwnerApproval(t *testing.T) {
180207
})
181208
}
182209

210+
func TestAccGitlabBranchProtection_createWithAllowForcePush(t *testing.T) {
211+
var pb gitlab.ProtectedBranch
212+
rInt := acctest.RandInt()
213+
214+
resource.Test(t, resource.TestCase{
215+
PreCheck: func() { testAccPreCheck(t) },
216+
ProviderFactories: providerFactories,
217+
CheckDestroy: testAccCheckGitlabBranchProtectionDestroy,
218+
Steps: []resource.TestStep{
219+
// Start with allow force push disabled
220+
{
221+
Config: testAccGitlabBranchProtectionConfig(rInt),
222+
Check: resource.ComposeTestCheckFunc(
223+
testAccCheckGitlabBranchProtectionExists("gitlab_branch_protection.branch_protect", &pb),
224+
testAccCheckGitlabBranchProtectionPersistsInStateCorrectly("gitlab_branch_protection.branch_protect", &pb),
225+
testAccCheckGitlabBranchProtectionAttributes(&pb, &testAccGitlabBranchProtectionExpectedAttributes{
226+
Name: fmt.Sprintf("BranchProtect-%d", rInt),
227+
PushAccessLevel: accessLevelValueToName[gitlab.DeveloperPermissions],
228+
MergeAccessLevel: accessLevelValueToName[gitlab.DeveloperPermissions],
229+
}),
230+
),
231+
},
232+
// Create a project and Branch Protection with allow force push enabled
233+
{
234+
Config: testAccGitlabBranchProtectionUpdateConfigAllowForcePushTrue(rInt),
235+
Check: resource.ComposeTestCheckFunc(
236+
testAccCheckGitlabBranchProtectionExists("gitlab_branch_protection.branch_protect", &pb),
237+
testAccCheckGitlabBranchProtectionPersistsInStateCorrectly("gitlab_branch_protection.branch_protect", &pb),
238+
testAccCheckGitlabBranchProtectionAttributes(&pb, &testAccGitlabBranchProtectionExpectedAttributes{
239+
Name: fmt.Sprintf("BranchProtect-%d", rInt),
240+
PushAccessLevel: accessLevelValueToName[gitlab.DeveloperPermissions],
241+
MergeAccessLevel: accessLevelValueToName[gitlab.DeveloperPermissions],
242+
AllowForcePush: true,
243+
}),
244+
),
245+
},
246+
// Update the Branch Protection to get back to initial settings
247+
{
248+
Config: testAccGitlabBranchProtectionConfig(rInt),
249+
Check: resource.ComposeTestCheckFunc(
250+
testAccCheckGitlabBranchProtectionExists("gitlab_branch_protection.branch_protect", &pb),
251+
testAccCheckGitlabBranchProtectionPersistsInStateCorrectly("gitlab_branch_protection.branch_protect", &pb),
252+
testAccCheckGitlabBranchProtectionAttributes(&pb, &testAccGitlabBranchProtectionExpectedAttributes{
253+
Name: fmt.Sprintf("BranchProtect-%d", rInt),
254+
PushAccessLevel: accessLevelValueToName[gitlab.DeveloperPermissions],
255+
MergeAccessLevel: accessLevelValueToName[gitlab.DeveloperPermissions],
256+
}),
257+
),
258+
},
259+
},
260+
})
261+
}
262+
183263
func TestAccGitlabBranchProtection_createWithMultipleAccessLevels(t *testing.T) {
184264
var pb gitlab.ProtectedBranch
185265
rInt := acctest.RandInt()
@@ -258,6 +338,10 @@ func testAccCheckGitlabBranchProtectionPersistsInStateCorrectly(n string, pb *gi
258338
return fmt.Errorf("push access level not persisted in state correctly")
259339
}
260340

341+
if rs.Primary.Attributes["allow_force_push"] != strconv.FormatBool(pb.AllowForcePush) {
342+
return fmt.Errorf("allow_force_push not persisted in state correctly")
343+
}
344+
261345
if rs.Primary.Attributes["code_owner_approval_required"] != strconv.FormatBool(pb.CodeOwnerApprovalRequired) {
262346
return fmt.Errorf("code_owner_approval_required not persisted in state correctly")
263347
}
@@ -301,6 +385,7 @@ type testAccGitlabBranchProtectionExpectedAttributes struct {
301385
Name string
302386
PushAccessLevel string
303387
MergeAccessLevel string
388+
AllowForcePush bool
304389
UsersAllowedToPush []string
305390
UsersAllowedToMerge []string
306391
GroupsAllowedToPush []string
@@ -336,6 +421,10 @@ func testAccCheckGitlabBranchProtectionAttributes(pb *gitlab.ProtectedBranch, wa
336421
return fmt.Errorf("got Merge access level %v; want %v", mergeAccessLevel, accessLevelNameToValue[want.MergeAccessLevel])
337422
}
338423

424+
if pb.AllowForcePush != want.AllowForcePush {
425+
return fmt.Errorf("got allow_force_push %v; want %v", pb.AllowForcePush, want.AllowForcePush)
426+
}
427+
339428
remainingWantedUserIDsAllowedToPush := map[int]struct{}{}
340429
for _, v := range want.UsersAllowedToPush {
341430
users, _, err := testGitlabClient.Users.ListUsers(&gitlab.ListUsersOptions{
@@ -448,6 +537,27 @@ resource "gitlab_branch_protection" "branch_protect" {
448537
`, rInt)
449538
}
450539

540+
func testAccGitlabBranchProtectionUpdateConfigAllowForcePushTrue(rInt int) string {
541+
return fmt.Sprintf(`
542+
resource "gitlab_project" "foo" {
543+
name = "foo-%[1]d"
544+
description = "Terraform acceptance tests"
545+
546+
# So that acceptance tests can be run in a gitlab organization
547+
# with no billing
548+
visibility_level = "public"
549+
}
550+
551+
resource "gitlab_branch_protection" "branch_protect" {
552+
project = gitlab_project.foo.id
553+
branch = "BranchProtect-%[1]d"
554+
push_access_level = "developer"
555+
merge_access_level = "developer"
556+
allow_force_push = true
557+
}
558+
`, rInt)
559+
}
560+
451561
func testAccGitlabBranchProtectionUpdateConfigCodeOwnerTrue(rInt int) string {
452562
return fmt.Sprintf(`
453563
resource "gitlab_project" "foo" {

0 commit comments

Comments
 (0)