Skip to content

Commit

Permalink
first_attempt_at_requires
Browse files Browse the repository at this point in the history
  • Loading branch information
mark.johnson committed Nov 5, 2024
1 parent 6e5ef36 commit adc37f2
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 6 deletions.
25 changes: 25 additions & 0 deletions github/resource_github_branch_protection.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,21 @@ func resourceGithubBranchProtection() *schema.Resource {
},
},
},
PROTECTION_REQUIRES_DEPLOYMENTS: {
Type: schema.TypeList,
Optional: true,
Description: "Are successful deployments required before merging.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
PROTECTION_REQUIRES_DEPLOYMENT_ENVIRONMENTS: {
Type: schema.TypeSet,
Optional: true,
Description: "The list of required deployment environments.",
Elem: &schema.Schema{Type: schema.TypeString},
},
},
},
},
PROTECTION_REQUIRES_STATUS_CHECKS: {
Type: schema.TypeList,
Optional: true,
Expand Down Expand Up @@ -256,6 +271,8 @@ func resourceGithubBranchProtectionCreate(d *schema.ResourceData, meta interface
ReviewDismissalActorIDs: githubv4NewIDSlice(githubv4IDSlice(data.ReviewDismissalActorIDs)),
LockBranch: githubv4.NewBoolean(githubv4.Boolean(data.LockBranch)),
RequireLastPushApproval: githubv4.NewBoolean(githubv4.Boolean(data.RequireLastPushApproval)),
RequiresDeployments: githubv4.NewBoolean(githubv4.Boolean(data.RequiresDeployments)),
RequiredDeploymentEnvironments: githubv4NewIDSlice(githubv4IDSliceEmpty(data.RequiredDeploymentEnvironments)),
}

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

rquiredDeployments := setRequiredDeployments(protection)
err = d.Set(PROTECTION_REQUIRES_DEPLOYMENTS, rquiredDeployments)
if err != nil {
log.Printf("[DEBUG] Problem setting '%s' in %s %s branch protection (%s)", PROTECTION_REQUIRES_DEPLOYMENTS, protection.Repository.Name, protection.Pattern, d.Id())
}

statusChecks := setStatusChecks(protection)
err = d.Set(PROTECTION_REQUIRES_STATUS_CHECKS, statusChecks)
if err != nil {
Expand Down Expand Up @@ -429,6 +452,8 @@ func resourceGithubBranchProtectionUpdate(d *schema.ResourceData, meta interface
ReviewDismissalActorIDs: githubv4NewIDSlice(githubv4IDSlice(data.ReviewDismissalActorIDs)),
LockBranch: githubv4.NewBoolean(githubv4.Boolean(data.LockBranch)),
RequireLastPushApproval: githubv4.NewBoolean(githubv4.Boolean(data.RequireLastPushApproval)),
RequiresDeployments: githubv4.NewBoolean(githubv4.Boolean(data.RequiresDeployments)),
RequiredDeploymentEnvironments: githubv4NewIDSlice(githubv4IDSliceEmpty(data.RequiredDeploymentEnvironments)),
}

ctx := context.WithValue(context.Background(), ctxId, d.Id())
Expand Down
51 changes: 51 additions & 0 deletions github/resource_github_branch_protection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,58 @@ func TestAccGithubBranchProtectionV4(t *testing.T) {
})

})
t.Run("configures branch push restrictions with deployment environments", func(t *testing.T) {
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)

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_deployments {
environments = ["dev","test]
}
}
`, randomID)

check := resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(
"github_branch_protection.test", "require_deployments.environments.#", "2",
),
)

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,
},
},
})
}

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) {
t.Skip("individual account not supported for this operation")
})

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

})
t.Run("configures branch push restrictions with blocksCreations false", func(t *testing.T) {
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)

Expand Down
36 changes: 36 additions & 0 deletions github/util_v4_branch_protection.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ type BranchProtectionRule struct {
RestrictsReviewDismissals githubv4.Boolean
RequireLastPushApproval githubv4.Boolean
LockBranch githubv4.Boolean
RequiresDeployments githubv4.Boolean
RequiredDeploymentEnvironments []githubv4.String
}

type BranchProtectionResourceData struct {
Expand Down Expand Up @@ -119,6 +121,8 @@ type BranchProtectionResourceData struct {
ReviewDismissalActorIDs []string
RequireLastPushApproval bool
LockBranch bool
RequiresDeployments bool
RequiredDeploymentEnvironments []string
}

func branchProtectionResourceData(d *schema.ResourceData, meta interface{}) (BranchProtectionResourceData, error) {
Expand Down Expand Up @@ -213,6 +217,23 @@ func branchProtectionResourceData(d *schema.ResourceData, meta interface{}) (Bra
}
}

if v, ok := d.GetOk(PROTECTION_REQUIRES_DEPLOYMENTS); ok {
data.RequiresDeployments = true
vL := v.([]interface{})
if len(vL) > 1 {
return BranchProtectionResourceData{},
fmt.Errorf("error multiple %s declarations", PROTECTION_REQUIRES_DEPLOYMENT_ENVIRONMENTS)
}
for _, v := range vL {
if v == nil {
break
}

m := v.(map[string]interface{})
data.RequiredDeploymentEnvironments = expandNestedSet(m, PROTECTION_REQUIRES_DEPLOYMENT_ENVIRONMENTS)
}
}

if v, ok := d.GetOk(PROTECTION_REQUIRES_STATUS_CHECKS); ok {
data.RequiresStatusChecks = true
vL := v.([]interface{})
Expand Down Expand Up @@ -515,6 +536,21 @@ func setApprovingReviews(protection BranchProtectionRule, data BranchProtectionR
return approvalReviews
}

func setRequiredDeployments(protection BranchProtectionRule) interface{} {
if !protection.RequiresDeployments {
return nil
}

requiredDeployments := []interface{}{
map[string]interface{}{
PROTECTION_REQUIRES_DEPLOYMENTS: protection.RequiresDeployments,
PROTECTION_REQUIRES_DEPLOYMENT_ENVIRONMENTS: protection.RequiredDeploymentEnvironments,
},
}

return requiredDeployments
}

func setStatusChecks(protection BranchProtectionRule) interface{} {
if !protection.RequiresStatusChecks {
return nil
Expand Down
2 changes: 2 additions & 0 deletions github/util_v4_consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ const (
PROTECTION_RESTRICTS_PUSHES = "restrict_pushes"
PROTECTION_RESTRICTS_REVIEW_DISMISSALS = "restrict_dismissals"
PROTECTION_REVIEW_DISMISSAL_ALLOWANCES = "dismissal_restrictions"
PROTECTION_REQUIRES_DEPLOYMENTS = "required_deployments"
PROTECTION_REQUIRES_DEPLOYMENT_ENVIRONMENTS = "environments"

REPOSITORY_ID = "repository_id"
)
12 changes: 6 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ require (
github.com/google/uuid v1.6.0
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0
github.com/shurcooL/githubv4 v0.0.0-20221126192849-0b5c4c7994eb
github.com/shurcooL/githubv4 v0.0.0-20240727222349-48295856cce7
github.com/stretchr/testify v1.9.0
golang.org/x/crypto v0.26.0
golang.org/x/crypto v0.28.0
golang.org/x/oauth2 v0.22.0
)

Expand Down Expand Up @@ -176,7 +176,7 @@ require (
github.com/sashamelentyev/usestdlibvars v1.26.0 // indirect
github.com/securego/gosec/v2 v2.20.1-0.20240525090044-5f0084eb01a9 // indirect
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect
github.com/shurcooL/graphql v0.0.0-20220606043923-3cf50f8a0a29 // indirect
github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/sivchari/containedctx v1.0.3 // indirect
github.com/sivchari/tenv v1.7.1 // indirect
Expand Down Expand Up @@ -220,10 +220,10 @@ require (
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect
golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f // indirect
golang.org/x/mod v0.18.0 // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/net v0.30.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.23.0 // indirect
golang.org/x/text v0.17.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/text v0.19.0 // indirect
golang.org/x/tools v0.22.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
Expand Down
13 changes: 13 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -580,10 +580,14 @@ github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqP
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs=
github.com/shurcooL/githubv4 v0.0.0-20221126192849-0b5c4c7994eb h1:foJysa74+t41fG7adnt+TkfcNxQUWid8R/HlXe+Mmbw=
github.com/shurcooL/githubv4 v0.0.0-20221126192849-0b5c4c7994eb/go.mod h1:hAF0iLZy4td2EX+/8Tw+4nodhlMrwN3HupfaXj3zkGo=
github.com/shurcooL/githubv4 v0.0.0-20240727222349-48295856cce7 h1:cYCy18SHPKRkvclm+pWm1Lk4YrREb4IOIb/YdFO0p2M=
github.com/shurcooL/githubv4 v0.0.0-20240727222349-48295856cce7/go.mod h1:zqMwyHmnN/eDOZOdiTohqIUKUrTFX62PNlu7IJdu0q8=
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
github.com/shurcooL/graphql v0.0.0-20220606043923-3cf50f8a0a29 h1:B1PEwpArrNp4dkQrfxh/abbBAOZBVp0ds+fBEOUOqOc=
github.com/shurcooL/graphql v0.0.0-20220606043923-3cf50f8a0a29/go.mod h1:AuYgA5Kyo4c7HfUmvRGs/6rGlMMV/6B1bVnB9JxJEEg=
github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466 h1:17JxqqJY66GmZVHkmAsGEkcIu0oCe3AM420QDgGwZx0=
github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466/go.mod h1:9dIRpgIY7hVhoqfe0/FcYp0bpInZaT7dc3BYOprrIUE=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
Expand Down Expand Up @@ -720,6 +724,8 @@ golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
Expand Down Expand Up @@ -807,6 +813,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
Expand Down Expand Up @@ -892,6 +900,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
Expand All @@ -902,6 +912,7 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand All @@ -917,6 +928,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
Expand Down
6 changes: 6 additions & 0 deletions website/docs/r/branch_protection.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ If specified, usual value is the [job name](https://docs.github.com/en/actions/u
For workflows that use matrixes, append the matrix name to the value using the following pattern `(<matrix_value>[, <matrix_value>])`. Matrixes should be specified based on the order of matrix properties in the workflow file. See [GitHub Documentation]("https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#using-a-matrix-strategy") for more information.
For workflows that use reusable workflows, the pattern is `<initial_workflow.jobs.job.[name/id]> / <reused-workflow.jobs.job.[name/id]>`. This can extend multiple levels.

### Required Deployments

`required_deployments` supports the following arguments:

* `environments`: (Optional) The list of required Environments that require deployment.

### Required Pull Request Reviews

`required_pull_request_reviews` supports the following arguments:
Expand Down

0 comments on commit adc37f2

Please sign in to comment.