diff --git a/github/resource_github_organization_ruleset.go b/github/resource_github_organization_ruleset.go index 014b28ef65..2443547b5d 100644 --- a/github/resource_github_organization_ruleset.go +++ b/github/resource_github_organization_ruleset.go @@ -52,14 +52,14 @@ func resourceGithubOrganizationRuleset() *schema.Resource { Schema: map[string]*schema.Schema{ "actor_id": { Type: schema.TypeInt, - Required: true, - Description: "The ID of the actor that can bypass a ruleset. When `actor_type` is `OrganizationAdmin`, this should be set to `1`.", + Optional: true, + Default: nil, + Description: "The ID of the actor that can bypass a ruleset. When `actor_type` is `OrganizationAdmin`, this should be set to `1`. Some resources such as DeployKey do not have an ID and this should be omitted.", }, "actor_type": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{"RepositoryRole", "Team", "Integration", "OrganizationAdmin"}, false), - Description: "The type of actor that can bypass a ruleset. Can be one of: `RepositoryRole`, `Team`, `Integration`, `OrganizationAdmin`.", + Type: schema.TypeString, + Required: true, + Description: "The type of actor that can bypass a ruleset. See https://docs.github.com/en/rest/orgs/rules for more information", }, "bypass_mode": { Type: schema.TypeString, diff --git a/github/resource_github_organization_ruleset_test.go b/github/resource_github_organization_ruleset_test.go index 9aae9f35b9..72b4d2208c 100644 --- a/github/resource_github_organization_ruleset_test.go +++ b/github/resource_github_organization_ruleset_test.go @@ -260,4 +260,87 @@ func TestGithubOrganizationRulesets(t *testing.T) { }) + t.Run("Creates and updates organization using bypasses", func(t *testing.T) { + + config := fmt.Sprintf(` + resource "github_organization_ruleset" "test" { + name = "test-%s" + target = "branch" + enforcement = "active" + + conditions { + ref_name { + include = ["~ALL"] + exclude = [] + } + } + + rules { + creation = true + update = true + deletion = true + required_linear_history = true + required_signatures = false + pull_request { + required_approving_review_count = 2 + required_review_thread_resolution = true + require_code_owner_review = true + dismiss_stale_reviews_on_push = true + require_last_push_approval = true + } + + bypass_actors { + actor_type = "DeployKey" + bypass_mode = "always" + } + + bypass_actors { + actor_id = 5 + actor_type = "RepositoryRole" + bypass_mode = "always" + } + + bypass_actors { + actor_id = 0 + actor_type = "OrganizationAdmin" + bypass_mode = "always" + } + } + } + `, randomID) + + check := resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "github_organization_ruleset.test", "bypass_actors.0.actor_type", + "0", + ), + resource.TestCheckResourceAttr( + "github_organization_ruleset.test", "bypass_actors.1.actor_type", + "5", + ), + resource.TestCheckResourceAttr( + "github_organization_ruleset.test", "bypass_actors.2.actor_type", + "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, + }, + }, + }) + } + + t.Run("with an enterprise account", func(t *testing.T) { + testCase(t, enterprise) + }) + + }) + } diff --git a/github/resource_github_repository_ruleset.go b/github/resource_github_repository_ruleset.go index cac6630249..0b71f6fe4e 100644 --- a/github/resource_github_repository_ruleset.go +++ b/github/resource_github_repository_ruleset.go @@ -57,14 +57,15 @@ func resourceGithubRepositoryRuleset() *schema.Resource { Schema: map[string]*schema.Schema{ "actor_id": { Type: schema.TypeInt, - Required: true, - Description: "The ID of the actor that can bypass a ruleset. When `actor_type` is `OrganizationAdmin`, this should be set to `1`.", + Optional: true, + Default: nil, + Description: "The ID of the actor that can bypass a ruleset. When `actor_type` is `OrganizationAdmin`, this should be set to `1`. Some resources such as DeployKey do not have an ID and this should be omitted.", }, "actor_type": { Type: schema.TypeString, Required: true, - ValidateFunc: validation.StringInSlice([]string{"RepositoryRole", "Team", "Integration", "OrganizationAdmin"}, false), - Description: "The type of actor that can bypass a ruleset. Can be one of: `RepositoryRole`, `Team`, `Integration`, `OrganizationAdmin`.", + ValidateFunc: validation.StringInSlice([]string{"RepositoryRole", "Team", "Integration", "OrganizationAdmin", "DeployKey"}, false), + Description: "The type of actor that can bypass a ruleset. See https://docs.github.com/en/rest/repos/rules for more information.", }, "bypass_mode": { Type: schema.TypeString, @@ -604,7 +605,7 @@ func resourceGithubRepositoryRulesetUpdate(d *schema.ResourceData, meta interfac ctx := context.WithValue(context.Background(), ctxId, rulesetID) - ruleset, _, err := client.Repositories.UpdateRuleset(ctx, owner, repoName, rulesetID, rulesetReq) + ruleset, _, err := client.Repositories.UpdateRulesetNoBypassActor(ctx, owner, repoName, rulesetID, rulesetReq) if err != nil { return err } diff --git a/github/respository_rules_utils.go b/github/respository_rules_utils.go index 44ccb27de1..cef8600576 100644 --- a/github/respository_rules_utils.go +++ b/github/respository_rules_utils.go @@ -44,7 +44,11 @@ func expandBypassActors(input []interface{}) []*github.BypassActor { inputMap := v.(map[string]interface{}) actor := &github.BypassActor{} if v, ok := inputMap["actor_id"].(int); ok { - actor.ActorID = github.Int64(int64(v)) + if v == 0 { + actor.ActorID = nil + } else { + actor.ActorID = github.Int64(int64(v)) + } } if v, ok := inputMap["actor_type"].(string); ok { diff --git a/website/docs/r/repository_ruleset.html.markdown b/website/docs/r/repository_ruleset.html.markdown index 173ffcf234..43306828d3 100644 --- a/website/docs/r/repository_ruleset.html.markdown +++ b/website/docs/r/repository_ruleset.html.markdown @@ -218,9 +218,9 @@ The `rules` block supports the following: #### bypass_actors #### -* `actor_id` - (Required) (Number) The ID of the actor that can bypass a ruleset. If `actor_type` is `Integration`, `actor_id` is a GitHub App ID. App ID can be obtained by following instructions from the [Get an App API docs](https://docs.github.com/en/rest/apps/apps?apiVersion=2022-11-28#get-an-app) +* `actor_id` - (Number) The ID of the actor that can bypass a ruleset. If `actor_type` is `Integration`, `actor_id` is a GitHub App ID. App ID can be obtained by following instructions from the [Get an App API docs](https://docs.github.com/en/rest/apps/apps?apiVersion=2022-11-28#get-an-app) -* `actor_type` (String) The type of actor that can bypass a ruleset. Can be one of: `RepositoryRole`, `Team`, `Integration`, `OrganizationAdmin`. +* `actor_type` (String) The type of actor that can bypass a ruleset. Can be one of: `RepositoryRole`, `Team`, `Integration`, `OrganizationAdmin`, `DeployKey`. * `bypass_mode` - (Optional) (String) When the specified actor can bypass the ruleset. pull_request means that an actor can only bypass rules on pull requests. Can be one of: `always`, `pull_request`.