Skip to content

Commit f292fdf

Browse files
authored
Merge pull request #1216 from timofurrer/feature/resource/gitlab_branch_protection-default-branch-overwrite
resource/gitlab_branch_protection: Allow to manage branch protection for default branch
2 parents f61f8c1 + 906e721 commit f292fdf

File tree

3 files changed

+79
-6
lines changed

3 files changed

+79
-6
lines changed

docs/resources/branch_protection.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ page_title: "gitlab_branch_protection Resource - terraform-provider-gitlab"
44
subcategory: ""
55
description: |-
66
The gitlab_branch_protection resource allows to manage the lifecycle of a protected branch of a repository.
7+
~> Branch Protection Behavior for the default branch
8+
Depending on the GitLab instance, group or project setting the default branch of a project is created automatically by GitLab behind the scenes.
9+
Due to some https://github.com/gitlabhq/terraform-provider-gitlab/issues/792 limitations https://discuss.hashicorp.com/t/ignore-the-order-of-a-complex-typed-list/42242 in the Terraform Provider SDK and the GitLab API,
10+
when creating a new project and trying to manage the branch protection setting for its default branch the gitlab_branch_protection resource will
11+
automatically take ownership of the default branch without an explicit import by unprotecting and properly protecting it again.
12+
Having multiple gitlab_branch_protection resources for the same project and default branch will result in them overriding each other - make sure to only have a single one.
13+
This behavior might change in the future.
714
~> The allowed_to_push, allowed_to_merge, allowed_to_unprotect, unprotect_access_level and code_owner_approval_required attributes require a GitLab Enterprise instance.
815
Upstream API: GitLab REST API docs https://docs.gitlab.com/ee/api/protected_branches.html
916
---
@@ -12,6 +19,14 @@ description: |-
1219

1320
The `gitlab_branch_protection` resource allows to manage the lifecycle of a protected branch of a repository.
1421

22+
~> **Branch Protection Behavior for the default branch**
23+
Depending on the GitLab instance, group or project setting the default branch of a project is created automatically by GitLab behind the scenes.
24+
Due to [some](https://github.com/gitlabhq/terraform-provider-gitlab/issues/792) [limitations](https://discuss.hashicorp.com/t/ignore-the-order-of-a-complex-typed-list/42242) in the Terraform Provider SDK and the GitLab API,
25+
when creating a new project and trying to manage the branch protection setting for its default branch the `gitlab_branch_protection` resource will
26+
automatically take ownership of the default branch without an explicit import by unprotecting and properly protecting it again.
27+
Having multiple `gitlab_branch_protection` resources for the same project and default branch will result in them overriding each other - make sure to only have a single one.
28+
This behavior might change in the future.
29+
1530
~> The `allowed_to_push`, `allowed_to_merge`, `allowed_to_unprotect`, `unprotect_access_level` and `code_owner_approval_required` attributes require a GitLab Enterprise instance.
1631

1732
**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/protected_branches.html)

internal/provider/resource_gitlab_branch_protection.go

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"fmt"
66
"log"
7-
"net/http"
87

98
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
109
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -43,6 +42,14 @@ var _ = registerResource("gitlab_branch_protection", func() *schema.Resource {
4342
return &schema.Resource{
4443
Description: `The ` + "`gitlab_branch_protection`" + ` resource allows to manage the lifecycle of a protected branch of a repository.
4544
45+
~> **Branch Protection Behavior for the default branch**
46+
Depending on the GitLab instance, group or project setting the default branch of a project is created automatically by GitLab behind the scenes.
47+
Due to [some](https://github.com/gitlabhq/terraform-provider-gitlab/issues/792) [limitations](https://discuss.hashicorp.com/t/ignore-the-order-of-a-complex-typed-list/42242) in the Terraform Provider SDK and the GitLab API,
48+
when creating a new project and trying to manage the branch protection setting for its default branch the ` + "`gitlab_branch_protection`" + ` resource will
49+
automatically take ownership of the default branch without an explicit import by unprotecting and properly protecting it again.
50+
Having multiple ` + "`gitlab_branch_protection`" + ` resources for the same project and default branch will result in them overriding each other - make sure to only have a single one.
51+
This behavior might change in the future.
52+
4653
~> The ` + "`allowed_to_push`" + `, ` + "`allowed_to_merge`" + `, ` + "`allowed_to_unprotect`" + `, ` + "`unprotect_access_level`" + ` and ` + "`code_owner_approval_required`" + ` attributes require a GitLab Enterprise instance.
4754
4855
**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/ee/api/protected_branches.html)`,
@@ -124,12 +131,25 @@ func resourceGitlabBranchProtectionCreate(ctx context.Context, d *schema.Resourc
124131
log.Printf("[DEBUG] create gitlab branch protection on branch %q for project %s", branch, project)
125132

126133
if d.IsNewResource() {
127-
existing, resp, err := client.ProtectedBranches.GetProtectedBranch(project, branch, gitlab.WithContext(ctx))
128-
if err != nil && resp.StatusCode != http.StatusNotFound {
129-
return diag.Errorf("error looking up protected branch %q on project %q: %v", branch, project, err)
134+
existing, _, err := client.ProtectedBranches.GetProtectedBranch(project, branch, gitlab.WithContext(ctx))
135+
if err == nil {
136+
projectDetails, _, err := client.Projects.GetProject(project, nil, gitlab.WithContext(ctx))
137+
if err != nil {
138+
return diag.Errorf("Failed to get project details for %q to get the name of the default branch: %v", project, err)
139+
}
140+
141+
if projectDetails.DefaultBranch == branch {
142+
log.Printf("[DEBUG] this branch protection is for the default branch %q in project %q, thus we allow configuring it even though this is a new resource! We do this by quickly unprotect it, because it's not editable ...!", branch, project)
143+
_, err := client.ProtectedBranches.UnprotectRepositoryBranches(project, branch, gitlab.WithContext(ctx))
144+
if err != nil {
145+
return diag.Errorf("Failed to unprotect default branch %q in project %q while trying to 'import' it: %v", branch, project, err)
146+
}
147+
} else {
148+
return diag.Errorf("protected branch %q on project %q already exists: %+v", branch, project, *existing)
149+
}
130150
}
131-
if resp.StatusCode != http.StatusNotFound {
132-
return diag.Errorf("protected branch %q on project %q already exists: %+v", branch, project, *existing)
151+
if err != nil && !is404(err) {
152+
return diag.Errorf("error looking up protected branch %q on project %q: %v", branch, project, err)
133153
}
134154
}
135155

internal/provider/resource_gitlab_branch_protection_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,44 @@ func TestAccGitlabBranchProtection_createWithMultipleAccessLevels(t *testing.T)
383383
})
384384
}
385385

386+
func TestAccGitlabBranchProtection_createForProjectDefaultBranch(t *testing.T) {
387+
testProjectName := acctest.RandomWithPrefix("tf-acc-test")
388+
var protectedBranch gitlab.ProtectedBranch
389+
390+
resource.ParallelTest(t, resource.TestCase{
391+
ProviderFactories: providerFactories,
392+
CheckDestroy: testAccCheckGitlabBranchProtectionDestroy,
393+
Steps: []resource.TestStep{
394+
// Create a project and protect its default branch with custom settings
395+
{
396+
Config: fmt.Sprintf(`
397+
resource "gitlab_project" "this" {
398+
name = "%s"
399+
initialize_with_readme = true
400+
}
401+
402+
resource "gitlab_branch_protection" "default_branch" {
403+
project = gitlab_project.this.id
404+
branch = gitlab_project.this.default_branch
405+
406+
// non-default setting
407+
allow_force_push = true
408+
}
409+
`, testProjectName),
410+
Check: resource.ComposeTestCheckFunc(
411+
testAccCheckGitlabBranchProtectionExists("gitlab_branch_protection.default_branch", &protectedBranch),
412+
func(_ *terraform.State) error {
413+
if protectedBranch.AllowForcePush != true {
414+
return fmt.Errorf("allow_force_push is not set to true")
415+
}
416+
return nil
417+
},
418+
),
419+
},
420+
},
421+
})
422+
}
423+
386424
func testAccCheckGitlabBranchProtectionPersistsInStateCorrectly(n string, pb *gitlab.ProtectedBranch) resource.TestCheckFunc {
387425
return func(s *terraform.State) error {
388426
rs, ok := s.RootModule().Resources[n]

0 commit comments

Comments
 (0)