Skip to content

Commit

Permalink
feat: add conversation resolution variable on branch protection
Browse files Browse the repository at this point in the history
  • Loading branch information
josh-barker committed Sep 14, 2021
1 parent 011b3ff commit 93e41a0
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 82 deletions.
80 changes: 46 additions & 34 deletions github/resource_github_branch_protection.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ func resourceGithubBranchProtection() *schema.Resource {
Optional: true,
Default: false,
},
PROTECTION_REQUIRES_CONVERSATION_RESOLUTION: {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
PROTECTION_REQUIRES_APPROVING_REVIEWS: {
Type: schema.TypeList,
Optional: true,
Expand Down Expand Up @@ -136,23 +141,24 @@ func resourceGithubBranchProtectionCreate(d *schema.ResourceData, meta interface
return err
}
input := githubv4.CreateBranchProtectionRuleInput{
AllowsDeletions: githubv4.NewBoolean(githubv4.Boolean(data.AllowsDeletions)),
AllowsForcePushes: githubv4.NewBoolean(githubv4.Boolean(data.AllowsForcePushes)),
DismissesStaleReviews: githubv4.NewBoolean(githubv4.Boolean(data.DismissesStaleReviews)),
IsAdminEnforced: githubv4.NewBoolean(githubv4.Boolean(data.IsAdminEnforced)),
Pattern: githubv4.String(data.Pattern),
PushActorIDs: githubv4NewIDSlice(githubv4IDSlice(data.PushActorIDs)),
RepositoryID: githubv4.NewID(githubv4.ID(data.RepositoryID)),
RequiredApprovingReviewCount: githubv4.NewInt(githubv4.Int(data.RequiredApprovingReviewCount)),
RequiredStatusCheckContexts: githubv4NewStringSlice(githubv4StringSlice(data.RequiredStatusCheckContexts)),
RequiresApprovingReviews: githubv4.NewBoolean(githubv4.Boolean(data.RequiresApprovingReviews)),
RequiresCodeOwnerReviews: githubv4.NewBoolean(githubv4.Boolean(data.RequiresCodeOwnerReviews)),
RequiresCommitSignatures: githubv4.NewBoolean(githubv4.Boolean(data.RequiresCommitSignatures)),
RequiresStatusChecks: githubv4.NewBoolean(githubv4.Boolean(data.RequiresStatusChecks)),
RequiresStrictStatusChecks: githubv4.NewBoolean(githubv4.Boolean(data.RequiresStrictStatusChecks)),
RestrictsPushes: githubv4.NewBoolean(githubv4.Boolean(data.RestrictsPushes)),
RestrictsReviewDismissals: githubv4.NewBoolean(githubv4.Boolean(data.RestrictsReviewDismissals)),
ReviewDismissalActorIDs: githubv4NewIDSlice(githubv4IDSlice(data.ReviewDismissalActorIDs)),
AllowsDeletions: githubv4.NewBoolean(githubv4.Boolean(data.AllowsDeletions)),
AllowsForcePushes: githubv4.NewBoolean(githubv4.Boolean(data.AllowsForcePushes)),
DismissesStaleReviews: githubv4.NewBoolean(githubv4.Boolean(data.DismissesStaleReviews)),
IsAdminEnforced: githubv4.NewBoolean(githubv4.Boolean(data.IsAdminEnforced)),
Pattern: githubv4.String(data.Pattern),
PushActorIDs: githubv4NewIDSlice(githubv4IDSlice(data.PushActorIDs)),
RepositoryID: githubv4.NewID(githubv4.ID(data.RepositoryID)),
RequiredApprovingReviewCount: githubv4.NewInt(githubv4.Int(data.RequiredApprovingReviewCount)),
RequiredStatusCheckContexts: githubv4NewStringSlice(githubv4StringSlice(data.RequiredStatusCheckContexts)),
RequiresApprovingReviews: githubv4.NewBoolean(githubv4.Boolean(data.RequiresApprovingReviews)),
RequiresCodeOwnerReviews: githubv4.NewBoolean(githubv4.Boolean(data.RequiresCodeOwnerReviews)),
RequiresCommitSignatures: githubv4.NewBoolean(githubv4.Boolean(data.RequiresCommitSignatures)),
RequiresConversationResolution: githubv4.NewBoolean(githubv4.Boolean(data.RequiresConversationResolution)),
RequiresStatusChecks: githubv4.NewBoolean(githubv4.Boolean(data.RequiresStatusChecks)),
RequiresStrictStatusChecks: githubv4.NewBoolean(githubv4.Boolean(data.RequiresStrictStatusChecks)),
RestrictsPushes: githubv4.NewBoolean(githubv4.Boolean(data.RestrictsPushes)),
RestrictsReviewDismissals: githubv4.NewBoolean(githubv4.Boolean(data.RestrictsReviewDismissals)),
ReviewDismissalActorIDs: githubv4NewIDSlice(githubv4IDSlice(data.ReviewDismissalActorIDs)),
}

ctx := context.Background()
Expand Down Expand Up @@ -217,6 +223,11 @@ func resourceGithubBranchProtectionRead(d *schema.ResourceData, meta interface{}
log.Printf("[WARN] Problem setting '%s' in %s %s branch protection (%s)", PROTECTION_REQUIRES_COMMIT_SIGNATURES, protection.Repository.Name, protection.Pattern, d.Id())
}

err = d.Set(PROTECTION_REQUIRES_CONVERSATION_RESOLUTION, protection.RequiresConversationResolution)
if err != nil {
log.Printf("[WARN] Problem setting '%s' in %s %s branch protection (%s)", PROTECTION_REQUIRES_CONVERSATION_RESOLUTION, protection.Repository.Name, protection.Pattern, d.Id())
}

approvingReviews := setApprovingReviews(protection)
err = d.Set(PROTECTION_REQUIRES_APPROVING_REVIEWS, approvingReviews)
if err != nil {
Expand Down Expand Up @@ -251,23 +262,24 @@ func resourceGithubBranchProtectionUpdate(d *schema.ResourceData, meta interface
return err
}
input := githubv4.UpdateBranchProtectionRuleInput{
BranchProtectionRuleID: d.Id(),
AllowsDeletions: githubv4.NewBoolean(githubv4.Boolean(data.AllowsDeletions)),
AllowsForcePushes: githubv4.NewBoolean(githubv4.Boolean(data.AllowsForcePushes)),
DismissesStaleReviews: githubv4.NewBoolean(githubv4.Boolean(data.DismissesStaleReviews)),
IsAdminEnforced: githubv4.NewBoolean(githubv4.Boolean(data.IsAdminEnforced)),
Pattern: githubv4.NewString(githubv4.String(data.Pattern)),
PushActorIDs: githubv4NewIDSlice(githubv4IDSlice(data.PushActorIDs)),
RequiredApprovingReviewCount: githubv4.NewInt(githubv4.Int(data.RequiredApprovingReviewCount)),
RequiredStatusCheckContexts: githubv4NewStringSlice(githubv4StringSlice(data.RequiredStatusCheckContexts)),
RequiresApprovingReviews: githubv4.NewBoolean(githubv4.Boolean(data.RequiresApprovingReviews)),
RequiresCodeOwnerReviews: githubv4.NewBoolean(githubv4.Boolean(data.RequiresCodeOwnerReviews)),
RequiresCommitSignatures: githubv4.NewBoolean(githubv4.Boolean(data.RequiresCommitSignatures)),
RequiresStatusChecks: githubv4.NewBoolean(githubv4.Boolean(data.RequiresStatusChecks)),
RequiresStrictStatusChecks: githubv4.NewBoolean(githubv4.Boolean(data.RequiresStrictStatusChecks)),
RestrictsPushes: githubv4.NewBoolean(githubv4.Boolean(data.RestrictsPushes)),
RestrictsReviewDismissals: githubv4.NewBoolean(githubv4.Boolean(data.RestrictsReviewDismissals)),
ReviewDismissalActorIDs: githubv4NewIDSlice(githubv4IDSlice(data.ReviewDismissalActorIDs)),
BranchProtectionRuleID: d.Id(),
AllowsDeletions: githubv4.NewBoolean(githubv4.Boolean(data.AllowsDeletions)),
AllowsForcePushes: githubv4.NewBoolean(githubv4.Boolean(data.AllowsForcePushes)),
DismissesStaleReviews: githubv4.NewBoolean(githubv4.Boolean(data.DismissesStaleReviews)),
IsAdminEnforced: githubv4.NewBoolean(githubv4.Boolean(data.IsAdminEnforced)),
Pattern: githubv4.NewString(githubv4.String(data.Pattern)),
PushActorIDs: githubv4NewIDSlice(githubv4IDSlice(data.PushActorIDs)),
RequiredApprovingReviewCount: githubv4.NewInt(githubv4.Int(data.RequiredApprovingReviewCount)),
RequiredStatusCheckContexts: githubv4NewStringSlice(githubv4StringSlice(data.RequiredStatusCheckContexts)),
RequiresApprovingReviews: githubv4.NewBoolean(githubv4.Boolean(data.RequiresApprovingReviews)),
RequiresCodeOwnerReviews: githubv4.NewBoolean(githubv4.Boolean(data.RequiresCodeOwnerReviews)),
RequiresCommitSignatures: githubv4.NewBoolean(githubv4.Boolean(data.RequiresCommitSignatures)),
RequiresConversationResolution: githubv4.NewBoolean(githubv4.Boolean(data.RequiresConversationResolution)),
RequiresStatusChecks: githubv4.NewBoolean(githubv4.Boolean(data.RequiresStatusChecks)),
RequiresStrictStatusChecks: githubv4.NewBoolean(githubv4.Boolean(data.RequiresStrictStatusChecks)),
RestrictsPushes: githubv4.NewBoolean(githubv4.Boolean(data.RestrictsPushes)),
RestrictsReviewDismissals: githubv4.NewBoolean(githubv4.Boolean(data.RestrictsReviewDismissals)),
ReviewDismissalActorIDs: githubv4NewIDSlice(githubv4IDSlice(data.ReviewDismissalActorIDs)),
}

ctx := context.WithValue(context.Background(), ctxId, d.Id())
Expand Down
88 changes: 88 additions & 0 deletions github/resource_github_branch_protection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,94 @@ func TestAccGithubBranchProtection(t *testing.T) {
resource.TestCheckResourceAttr(
"github_branch_protection.test", "require_signed_commits", "false",
),
resource.TestCheckResourceAttr(
"github_branch_protection.test", "require_conversation_resolution", "false",
),
resource.TestCheckResourceAttr(
"github_branch_protection.test", "required_status_checks.#", "0",
),
resource.TestCheckResourceAttr(
"github_branch_protection.test", "required_pull_request_reviews.#", "0",
),
resource.TestCheckResourceAttr(
"github_branch_protection.test", "push_restrictions.#", "0",
),
)

testCase := func(t *testing.T, mode string) {
resource.Test(t, resource.TestCase{
PreCheck: func() { skipUnlessMode(t, mode) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: config,
Check: check,
},
{
ResourceName: "github_branch_protection.test",
ImportState: true,
ImportStateVerify: true,
ImportStateIdFunc: importBranchProtectionByRepoName(
fmt.Sprintf("tf-acc-test-%s", randomID), "main",
),
},
{
ResourceName: "github_branch_protection.test",
ImportState: true,
ExpectError: regexp.MustCompile(
`Could not find a branch protection rule with the pattern 'no-such-pattern'\.`,
),
ImportStateIdFunc: importBranchProtectionByRepoName(
fmt.Sprintf("tf-acc-test-%s", randomID), "no-such-pattern",
),
},
},
})
}

t.Run("with an anonymous account", func(t *testing.T) {
t.Skip("anonymous account not supported for this operation")
})

t.Run("with an individual account", func(t *testing.T) {
testCase(t, individual)
})

t.Run("with an organization account", func(t *testing.T) {
testCase(t, organization)
})

})

t.Run("configures default settings when conversation resolution is true", func(t *testing.T) {

config := fmt.Sprintf(`
resource "github_repository" "test" {
name = "tf-acc-test-%s"
auto_init = true
}
resource "github_branch_protection" "test" {
repository_id = github_repository.test.node_id
pattern = "main"
require_conversation_resolution = true
}
`, randomID)

check := resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(
"github_branch_protection.test", "pattern", "main",
),
resource.TestCheckResourceAttr(
"github_branch_protection.test", "require_signed_commits", "false",
),
resource.TestCheckResourceAttr(
"github_branch_protection.test", "require_conversation_resolution", "true",
),
resource.TestCheckResourceAttr(
"github_branch_protection.test", "required_status_checks.#", "0",
),
Expand Down
72 changes: 39 additions & 33 deletions github/util_v4_branch_protection.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,42 +39,44 @@ type BranchProtectionRule struct {
ReviewDismissalAllowances struct {
Nodes []DismissalActorTypes
} `graphql:"reviewDismissalAllowances(first: 100)"`
AllowsDeletions githubv4.Boolean
AllowsForcePushes githubv4.Boolean
DismissesStaleReviews githubv4.Boolean
ID githubv4.ID
IsAdminEnforced githubv4.Boolean
Pattern githubv4.String
RequiredApprovingReviewCount githubv4.Int
RequiredStatusCheckContexts []githubv4.String
RequiresApprovingReviews githubv4.Boolean
RequiresCodeOwnerReviews githubv4.Boolean
RequiresCommitSignatures githubv4.Boolean
RequiresStatusChecks githubv4.Boolean
RequiresStrictStatusChecks githubv4.Boolean
RestrictsPushes githubv4.Boolean
RestrictsReviewDismissals githubv4.Boolean
AllowsDeletions githubv4.Boolean
AllowsForcePushes githubv4.Boolean
DismissesStaleReviews githubv4.Boolean
ID githubv4.ID
IsAdminEnforced githubv4.Boolean
Pattern githubv4.String
RequiredApprovingReviewCount githubv4.Int
RequiredStatusCheckContexts []githubv4.String
RequiresApprovingReviews githubv4.Boolean
RequiresCodeOwnerReviews githubv4.Boolean
RequiresCommitSignatures githubv4.Boolean
RequiresConversationResolution githubv4.Boolean
RequiresStatusChecks githubv4.Boolean
RequiresStrictStatusChecks githubv4.Boolean
RestrictsPushes githubv4.Boolean
RestrictsReviewDismissals githubv4.Boolean
}

type BranchProtectionResourceData struct {
AllowsDeletions bool
AllowsForcePushes bool
BranchProtectionRuleID string
DismissesStaleReviews bool
IsAdminEnforced bool
Pattern string
PushActorIDs []string
RepositoryID string
RequiredApprovingReviewCount int
RequiredStatusCheckContexts []string
RequiresApprovingReviews bool
RequiresCodeOwnerReviews bool
RequiresCommitSignatures bool
RequiresStatusChecks bool
RequiresStrictStatusChecks bool
RestrictsPushes bool
RestrictsReviewDismissals bool
ReviewDismissalActorIDs []string
AllowsDeletions bool
AllowsForcePushes bool
BranchProtectionRuleID string
DismissesStaleReviews bool
IsAdminEnforced bool
Pattern string
PushActorIDs []string
RepositoryID string
RequiredApprovingReviewCount int
RequiredStatusCheckContexts []string
RequiresApprovingReviews bool
RequiresCodeOwnerReviews bool
RequiresCommitSignatures bool
RequiresConversationResolution bool
RequiresStatusChecks bool
RequiresStrictStatusChecks bool
RestrictsPushes bool
RestrictsReviewDismissals bool
ReviewDismissalActorIDs []string
}

func branchProtectionResourceData(d *schema.ResourceData, meta interface{}) (BranchProtectionResourceData, error) {
Expand Down Expand Up @@ -108,6 +110,10 @@ func branchProtectionResourceData(d *schema.ResourceData, meta interface{}) (Bra
data.RequiresCommitSignatures = v.(bool)
}

if v, ok := d.GetOk(PROTECTION_REQUIRES_CONVERSATION_RESOLUTION); ok {
data.RequiresConversationResolution = v.(bool)
}

if v, ok := d.GetOk(PROTECTION_REQUIRES_APPROVING_REVIEWS); ok {
vL := v.([]interface{})
if len(vL) > 1 {
Expand Down
31 changes: 16 additions & 15 deletions github/util_v4_consts.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
package github

const (
PROTECTION_ALLOWS_DELETIONS = "allows_deletions"
PROTECTION_ALLOWS_FORCE_PUSHES = "allows_force_pushes"
PROTECTION_DISMISSES_STALE_REVIEWS = "dismiss_stale_reviews"
PROTECTION_IS_ADMIN_ENFORCED = "enforce_admins"
PROTECTION_PATTERN = "pattern"
PROTECTION_REQUIRED_APPROVING_REVIEW_COUNT = "required_approving_review_count"
PROTECTION_REQUIRED_STATUS_CHECK_CONTEXTS = "contexts"
PROTECTION_REQUIRES_APPROVING_REVIEWS = "required_pull_request_reviews"
PROTECTION_REQUIRES_CODE_OWNER_REVIEWS = "require_code_owner_reviews"
PROTECTION_REQUIRES_COMMIT_SIGNATURES = "require_signed_commits"
PROTECTION_REQUIRES_STATUS_CHECKS = "required_status_checks"
PROTECTION_REQUIRES_STRICT_STATUS_CHECKS = "strict"
PROTECTION_RESTRICTS_PUSHES = "push_restrictions"
PROTECTION_RESTRICTS_REVIEW_DISMISSALS = "restrict_dismissals"
PROTECTION_RESTRICTS_REVIEW_DISMISSERS = "dismissal_restrictions"
PROTECTION_ALLOWS_DELETIONS = "allows_deletions"
PROTECTION_ALLOWS_FORCE_PUSHES = "allows_force_pushes"
PROTECTION_DISMISSES_STALE_REVIEWS = "dismiss_stale_reviews"
PROTECTION_IS_ADMIN_ENFORCED = "enforce_admins"
PROTECTION_PATTERN = "pattern"
PROTECTION_REQUIRED_APPROVING_REVIEW_COUNT = "required_approving_review_count"
PROTECTION_REQUIRED_STATUS_CHECK_CONTEXTS = "contexts"
PROTECTION_REQUIRES_APPROVING_REVIEWS = "required_pull_request_reviews"
PROTECTION_REQUIRES_CODE_OWNER_REVIEWS = "require_code_owner_reviews"
PROTECTION_REQUIRES_COMMIT_SIGNATURES = "require_signed_commits"
PROTECTION_REQUIRES_CONVERSATION_RESOLUTION = "require_conversation_resolution"
PROTECTION_REQUIRES_STATUS_CHECKS = "required_status_checks"
PROTECTION_REQUIRES_STRICT_STATUS_CHECKS = "strict"
PROTECTION_RESTRICTS_PUSHES = "push_restrictions"
PROTECTION_RESTRICTS_REVIEW_DISMISSALS = "restrict_dismissals"
PROTECTION_RESTRICTS_REVIEW_DISMISSERS = "dismissal_restrictions"

REPOSITORY_ID = "repository_id"
)
1 change: 1 addition & 0 deletions website/docs/r/branch_protection.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ The following arguments are supported:
* `pattern` - (Required) Identifies the protection rule pattern.
* `enforce_admins` - (Optional) Boolean, setting this to `true` enforces status checks for repository administrators.
* `require_signed_commits` - (Optional) Boolean, setting this to `true` requires all commits to be signed with GPG.
* `require_conversation_resolution` - (Optional) Boolean, setting this to `true` requires all conversations on code must be resolved before a pull request can be merged.
* `required_status_checks` - (Optional) Enforce restrictions for required status checks. See [Required Status Checks](#required-status-checks) below for details.
* `required_pull_request_reviews` - (Optional) Enforce restrictions for pull request reviews. See [Required Pull Request Reviews](#required-pull-request-reviews) below for details.
* `push_restrictions` - (Optional) The list of actor IDs that may push to the branch.
Expand Down

0 comments on commit 93e41a0

Please sign in to comment.