Skip to content

Commit 7fa7807

Browse files
committed
resource/gitlab_project: fix waiting for default branch protection during creation
This patch fixes waiting for the protection on the default branch in a scenario where the project is in a group namespace which has the default branch protection disabled. NOTE: I've made some assumption that this can only happen for the projects in group namespaces (e.g. project in a user namespace can't turn the default branch protection off) and that this information about the disabled default branch protection can always be read from the group the project is directly assigned to. Closes #906
1 parent 5b699f8 commit 7fa7807

File tree

3 files changed

+80
-24
lines changed

3 files changed

+80
-24
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 3.11.1 (2022-03-02)
2+
3+
BUG FIXES:
4+
5+
* resource/gitlab_project: fix waiting for default branch protection during creation ([#908](https://github.com/gitlabhq/terraform-provider-gitlab/pull/908))
6+
17
## 3.11.0 (2022-03-01)
28

39
FEATURES:

internal/provider/resource_gitlab_project.go

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -667,33 +667,42 @@ func resourceGitlabProjectCreate(ctx context.Context, d *schema.ResourceData, me
667667
}
668668
}
669669

670-
// Branch protection for a newly created branch is an async action, so use WaitForState to ensure it's protected
671-
// before we continue. Note this check should only be required when there is a custom default branch set
672-
// See issue 800: https://github.com/gitlabhq/terraform-provider-gitlab/issues/800
673-
stateConf := &resource.StateChangeConf{
674-
Pending: []string{"false"},
675-
Target: []string{"true"},
676-
Timeout: 2 * time.Minute, //The async action usually completes very quickly, within seconds. Don't wait too long.
677-
Refresh: func() (interface{}, string, error) {
678-
branch, _, err := client.Branches.GetBranch(project.ID, project.DefaultBranch, gitlab.WithContext(ctx))
679-
if err != nil {
680-
if is404(err) {
681-
// When we hit a 404 here, it means the default branch wasn't created at all as part of the project
682-
// this will happen when "default_branch" isn't set, or "initialize_with_readme" is set to false.
683-
// We don't need to wait anymore, so return "true" to exist the wait loop.
684-
return branch, "true", nil
685-
}
670+
// If the project is assigned to a group namespace and the group has *default branch protection*
671+
// disabled (`default_branch_protection = 0`) then we don't have to wait for one.
672+
waitForDefaultBranchProtection, err := expectDefaultBranchProtection(ctx, client, project)
673+
if err != nil {
674+
return diag.Errorf("Failed to fetch group the project %d is owned by: %+v", project.ID, err)
675+
}
686676

687-
//This is legit error, return the error.
688-
return nil, "", err
689-
}
677+
if waitForDefaultBranchProtection {
678+
// Branch protection for a newly created branch is an async action, so use WaitForState to ensure it's protected
679+
// before we continue. Note this check should only be required when there is a custom default branch set
680+
// See issue 800: https://github.com/gitlabhq/terraform-provider-gitlab/issues/800
681+
stateConf := &resource.StateChangeConf{
682+
Pending: []string{"false"},
683+
Target: []string{"true"},
684+
Timeout: 2 * time.Minute, //The async action usually completes very quickly, within seconds. Don't wait too long.
685+
Refresh: func() (interface{}, string, error) {
686+
branch, _, err := client.Branches.GetBranch(project.ID, project.DefaultBranch, gitlab.WithContext(ctx))
687+
if err != nil {
688+
if is404(err) {
689+
// When we hit a 404 here, it means the default branch wasn't created at all as part of the project
690+
// this will happen when "default_branch" isn't set, or "initialize_with_readme" is set to false.
691+
// We don't need to wait anymore, so return "true" to exist the wait loop.
692+
return branch, "true", nil
693+
}
690694

691-
return branch, strconv.FormatBool(branch.Protected), nil
692-
},
693-
}
695+
//This is legit error, return the error.
696+
return nil, "", err
697+
}
698+
699+
return branch, strconv.FormatBool(branch.Protected), nil
700+
},
701+
}
694702

695-
if _, err := stateConf.WaitForStateContext(ctx); err != nil {
696-
return diag.Errorf("error while waiting for branch %s to reach 'protected' status, %s", project.DefaultBranch, err)
703+
if _, err := stateConf.WaitForStateContext(ctx); err != nil {
704+
return diag.Errorf("error while waiting for branch %s to reach 'protected' status, %s", project.DefaultBranch, err)
705+
}
697706
}
698707

699708
var editProjectOptions gitlab.EditProjectOptions
@@ -1178,3 +1187,18 @@ func flattenProjectPushRules(pushRules *gitlab.ProjectPushRules) (values []map[s
11781187
func namespaceOrPathChanged(ctx context.Context, d *schema.ResourceDiff, meta interface{}) bool {
11791188
return d.HasChange("namespace_id") || d.HasChange("path")
11801189
}
1190+
1191+
func expectDefaultBranchProtection(ctx context.Context, client *gitlab.Client, project *gitlab.Project) (bool, error) {
1192+
if project.Namespace.Kind == "group" {
1193+
group, _, err := client.Groups.GetGroup(project.Namespace.ID, nil, gitlab.WithContext(ctx))
1194+
if err != nil {
1195+
return false, err
1196+
}
1197+
1198+
return group.DefaultBranchProtection != 0, nil
1199+
}
1200+
1201+
// projects which are not assigned to a group can't have a "no branch protection" default,
1202+
// thus, we always expect a default branch protection.
1203+
return true, nil
1204+
}

internal/provider/resource_gitlab_project_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,14 @@ func TestAccGitlabProject_groupWithoutDefaultBranchProtection(t *testing.T) {
428428
Config: testAccGitlabProjectConfigWithoutDefaultBranchProtection(rInt),
429429
Check: testAccCheckGitlabProjectExists("gitlab_project.foo", &project),
430430
},
431+
{
432+
Config: testAccGitlabProjectConfigWithoutDefaultBranchProtection(rInt),
433+
Destroy: true,
434+
},
435+
{
436+
Config: testAccGitlabProjectConfigWithoutDefaultBranchProtectionInitializeReadme(rInt),
437+
Check: testAccCheckGitlabProjectExists("gitlab_project.foo", &project),
438+
},
431439
},
432440
})
433441
}
@@ -1176,6 +1184,24 @@ resource "gitlab_project" "foo" {
11761184
`, rInt, rInt, rInt)
11771185
}
11781186

1187+
func testAccGitlabProjectConfigWithoutDefaultBranchProtectionInitializeReadme(rInt int) string {
1188+
return fmt.Sprintf(`
1189+
resource "gitlab_group" "foo" {
1190+
name = "foogroup2-%d"
1191+
path = "foogroup2-%d"
1192+
default_branch_protection = 0
1193+
visibility_level = "public"
1194+
}
1195+
1196+
resource "gitlab_project" "foo" {
1197+
name = "foo-%d"
1198+
description = "Terraform acceptance tests"
1199+
namespace_id = "${gitlab_group.foo.id}"
1200+
initialize_with_readme = true
1201+
}
1202+
`, rInt, rInt, rInt)
1203+
}
1204+
11791205
func testAccGitlabProjectTransferBetweenGroupsBefore(rInt int) string {
11801206
return fmt.Sprintf(`
11811207
resource "gitlab_group" "foo" {

0 commit comments

Comments
 (0)