Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for merge queues in repository rulesets #2380

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions github/resource_github_repository_ruleset.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,65 @@ func resourceGithubRepositoryRuleset() *schema.Resource {
},
},
},
"merge_queue": {
MXfive marked this conversation as resolved.
Show resolved Hide resolved
Type: schema.TypeList,
MaxItems: 1,
Optional: true,
Description: "Merges must be performed via a merge queue.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"check_response_timeout_minutes": {
Type: schema.TypeInt,
Optional: true,
Default: 60,
ValidateDiagFunc: toDiagFunc(validation.IntBetween(0, 360), "check_response_timeout_minutes"),
Description: "Maximum time for a required status check to report a conclusion. After this much time has elapsed, checks that have not reported a conclusion will be assumed to have failed. Defaults to `60`.",
},
"grouping_strategy": {
Type: schema.TypeString,
Optional: true,
Default: "ALLGREEN",
ValidateDiagFunc: toDiagFunc(validation.StringInSlice([]string{"ALLGREEN", "HEADGREEN"}, false), "grouping_strategy"),
Description: "When set to ALLGREEN, the merge commit created by merge queue for each PR in the group must pass all required checks to merge. When set to HEADGREEN, only the commit at the head of the merge group, i.e. the commit containing changes from all of the PRs in the group, must pass its required checks to merge. Can be one of: ALLGREEN, HEADGREEN. Defaults to `ALLGREEN`.",
},
"max_entries_to_build": {
Type: schema.TypeInt,
Optional: true,
Default: 5,
ValidateDiagFunc: toDiagFunc(validation.IntBetween(0, 100), "max_entries_to_merge"),
Description: "Limit the number of queued pull requests requesting checks and workflow runs at the same time. Defaults to `5`.",
},
"max_entries_to_merge": {
Type: schema.TypeInt,
Optional: true,
Default: 5,
ValidateDiagFunc: toDiagFunc(validation.IntBetween(0, 100), "max_entries_to_merge"),
Description: "The maximum number of PRs that will be merged together in a group. Defaults to `5`.",
},
"merge_method": {
Type: schema.TypeString,
Optional: true,
Default: "MERGE",
ValidateDiagFunc: toDiagFunc(validation.StringInSlice([]string{"MERGE", "SQUASH", "REBASE"}, false), "merge_method"),
Description: "Method to use when merging changes from queued pull requests. Can be one of: MERGE, SQUASH, REBASE. Defaults to `MERGE`.",
},
"min_entries_to_merge": {
Type: schema.TypeInt,
Optional: true,
Default: 1,
ValidateDiagFunc: toDiagFunc(validation.IntBetween(0, 100), "min_entries_to_merge"),
Description: "The minimum number of PRs that will be merged together in a group. Defaults to `1`.",
},
"min_entries_to_merge_wait_minutes": {
Type: schema.TypeInt,
Optional: true,
Default: 5,
ValidateDiagFunc: toDiagFunc(validation.IntBetween(0, 360), "min_entries_to_merge_wait_minutes"),
Description: "The time merge queue should wait after the first PR is added to the queue for the minimum group size to be met. After this time has elapsed, the minimum group size will be ignored and a smaller group will be merged. Defaults to `5`.",
},
},
},
},
"non_fast_forward": {
Type: schema.TypeBool,
Optional: true,
Expand Down
30 changes: 30 additions & 0 deletions github/resource_github_repository_ruleset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,16 @@ func TestGithubRepositoryRulesets(t *testing.T) {

required_signatures = false

merge_queue {
check_response_timeout_minutes = 10
grouping_strategy = "ALLGREEN"
max_entries_to_build = 5
max_entries_to_merge = 5
merge_method = "MERGE"
min_entries_to_merge = 1
min_entries_to_merge_wait_minutes = 60
}

pull_request {
required_approving_review_count = 2
required_review_thread_resolution = true
Expand All @@ -63,6 +73,16 @@ func TestGithubRepositoryRulesets(t *testing.T) {
require_last_push_approval = true
}

merge_queue {
check_response_timeout_minutes = 30
grouping_strategy = "HEADGREEN"
max_entries_to_build = 4
max_entries_to_merge = 4
merge_method = SQUASH
min_entries_to_merge = 2
min_entries_to_merge_wait_minutes = 10
}

required_status_checks {

required_check {
Expand Down Expand Up @@ -312,6 +332,16 @@ func TestGithubRepositoryRulesets(t *testing.T) {
require_last_push_approval = true
}

aerge_queue {
check_response_timeout_minutes = 30
grouping_strategy = "HEADGREEN"
max_entries_to_build = 4
max_entries_to_merge = 4
merge_method = SQUASH
min_entries_to_merge = 2
min_entries_to_merge_wait_minutes = 10
}

required_status_checks {

required_check {
Expand Down
16 changes: 16 additions & 0 deletions github/respository_rules_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,22 @@ func expandRules(input []interface{}, org bool) []*github.RepositoryRule {
rulesSlice = append(rulesSlice, github.NewPullRequestRule(params))
}

// Merge queue rule
if v, ok := rulesMap["merge_queue"].([]interface{}); ok && len(v) != 0 {
mergeQueueMap := v[0].(map[string]interface{})
params := &github.MergeQueueRuleParameters{
CheckResponseTimeoutMinutes: mergeQueueMap["check_response_timeout_minutes"].(int),
GroupingStrategy: mergeQueueMap["grouping_strategy"].(string),
MaxEntriesToBuild: mergeQueueMap["max_entries_to_build"].(int),
MaxEntriesToMerge: mergeQueueMap["max_entries_to_merge"].(int),
MergeMethod: mergeQueueMap["merge_method"].(string),
MinEntriesToMerge: mergeQueueMap["min_entries_to_merge"].(int),
MinEntriesToMergeWaitMinutes: mergeQueueMap["min_entries_to_merge_wait_minutes"].(int),
}

rulesSlice = append(rulesSlice, github.NewMergeQueueRule(params))
}

// Required status checks rule
if v, ok := rulesMap["required_status_checks"].([]interface{}); ok && len(v) != 0 {
requiredStatusMap := v[0].(map[string]interface{})
Expand Down
34 changes: 20 additions & 14 deletions website/docs/r/repository_ruleset.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ resource "github_repository_ruleset" "example" {
required_deployment_environments = ["test"]
}


}
}
```
Expand All @@ -74,7 +74,6 @@ resource "github_repository_ruleset" "example" {

The `rules` block supports the following:


* `branch_name_pattern` - (Optional) (Block List, Max: 1) Parameters to be used for the branch_name_pattern rule. This rule only applies to repositories within an enterprise, it cannot be applied to repositories owned by individuals or regular organizations. Conflicts with `tag_name_pattern` as it only applied to rulesets with target `branch`. (see [below for nested schema](#rules.branch_name_pattern))

* `commit_author_email_pattern` - (Optional) (Block List, Max: 1) Parameters to be used for the commit_author_email_pattern rule. This rule only applies to repositories within an enterprise, it cannot be applied to repositories owned by individuals or regular organizations. (see [below for nested schema](#rules.commit_author_email_pattern))
Expand All @@ -89,6 +88,8 @@ The `rules` block supports the following:

* `non_fast_forward` - (Optional) (Boolean) Prevent users with push access from force pushing to branches.

* `merge_queue` - (Optional) (Block List, Max: 1) Merges must be performed via a merge queue.

* `pull_request` - (Optional) (Block List, Max: 1) Require all commits be made to a non-target branch and submitted via a pull request before they can be merged. (see [below for nested schema](#rules.pull_request))

* `required_deployments` - (Optional) (Block List, Max: 1) Choose which environments must be successfully deployed to before branches can be merged into a branch that matches this rule. (see [below for nested schema](#rules.required_deployments))
Expand All @@ -102,7 +103,7 @@ The `rules` block supports the following:
* `tag_name_pattern` - (Optional) (Block List, Max: 1) Parameters to be used for the tag_name_pattern rule. This rule only applies to repositories within an enterprise, it cannot be applied to repositories owned by individuals or regular organizations. Conflicts with `branch_name_pattern` as it only applied to rulesets with target `tag`. (see [below for nested schema](#rules.tag_name_pattern))

* `update` - (Optional) (Boolean) Only allow users with bypass permission to update matching refs.

* `update_allows_fetch_and_merge` - (Optional) (Boolean) Branch can pull changes from its upstream repository. This is only applicable to forked repositories. Requires `update` to be set to `true`. Note: behaviour is affected by a known bug on the GitHub side which may cause issues when using this parameter.

#### rules.branch_name_pattern ####
Expand All @@ -115,7 +116,6 @@ The `rules` block supports the following:

* `negate` - (Optional) (Boolean) If true, the rule will fail if the pattern matches.


#### rules.commit_author_email_pattern ####

* `operator` - (Required) (String) The operator to use for matching. Can be one of: `starts_with`, `ends_with`, `contains`, `regex`.
Expand All @@ -126,7 +126,6 @@ The `rules` block supports the following:

* `negate` - (Optional) (Boolean) If true, the rule will fail if the pattern matches.


#### rules.commit_message_pattern ####

* `operator` - (Required) (String) The operator to use for matching. Can be one of: `starts_with`, `ends_with`, `contains`, `regex`.
Expand All @@ -137,7 +136,6 @@ The `rules` block supports the following:

* `negate` - (Optional) (Boolean) If true, the rule will fail if the pattern matches.


#### rules.committer_email_pattern ####

* `operator` - (Required) (String) The operator to use for matching. Can be one of: `starts_with`, `ends_with`, `contains`, `regex`.
Expand All @@ -148,6 +146,21 @@ The `rules` block supports the following:

* `negate` - (Optional) (Boolean) If true, the rule will fail if the pattern matches.

#### rules.merge_queue ####

* `check_response_timeout_minutes` - (Required) (Number)Maximum time for a required status check to report a conclusion. After this much time has elapsed, checks that have not reported a conclusion will be assumed to have failed. Defaults to `60`.

* `grouping_strategy` - (Required) (String)When set to ALLGREEN, the merge commit created by merge queue for each PR in the group must pass all required checks to merge. When set to HEADGREEN, only the commit at the head of the merge group, i.e. the commit containing changes from all of the PRs in the group, must pass its required checks to merge. Can be one of: ALLGREEN, HEADGREEN. Defaults to `ALLGREEN`.

* `max_entries_to_build` - (Required) (Number) Limit the number of queued pull requests requesting checks and workflow runs at the same time. Defaults to `5`.

* `max_entries_to_merge` - (Required) (Number) Limit the number of queued pull requests requesting checks and workflow runs at the same time. Defaults to `5`.

* `merge_method` - (Required) (String) Method to use when merging changes from queued pull requests. Can be one of: MERGE, SQUASH, REBASE. Defaults to `MERGE`.

* `min_entries_to_merge` - (Required) (Number) The minimum number of PRs that will be merged together in a group. Defaults to `1`.

* `min_entries_to_merge_wait_minutes` - (Required) (Number) The time merge queue should wait after the first PR is added to the queue for the minimum group size to be met. After this time has elapsed, the minimum group size will be ignored and a smaller group will be merged. Defaults to `5`.

#### rules.pull_request ####

Expand All @@ -161,12 +174,10 @@ The `rules` block supports the following:

* `required_review_thread_resolution` - (Optional) (Boolean) All conversations on code must be resolved before a pull request can be merged. Defaults to `false`.


#### rules.required_deployments ####

* `required_deployment_environments` - (Required) (List of String) The environments that must be successfully deployed to before branches can be merged.


#### rules.required_status_checks ####

* `required_check` - (Required) (Block Set, Min: 1) Status checks that are required. Several can be defined. (see [below for nested schema](#rules.required_status_checks.required_check))
Expand All @@ -179,8 +190,6 @@ The `rules` block supports the following:

* `integration_id` - (Optional) (Number) The optional integration ID that this status check must originate from.



#### rules.tag_name_pattern ####

* `operator` - (Required) (String) The operator to use for matching. Can be one of: `starts_with`, `ends_with`, `contains`, `regex`.
Expand All @@ -192,7 +201,6 @@ The `rules` block supports the following:
* `negate` - (Optional) (Boolean) If true, the rule will fail if the pattern matches.



#### bypass_actors ####

* `actor_id` - (Required) (Number) The ID of the actor that can bypass a ruleset.
Expand All @@ -202,13 +210,13 @@ The `rules` block supports the following:
* `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`.

~> Note: at the time of writing this, the following actor types correspond to the following actor IDs:

* `OrganizationAdmin` -> `1`
* `RepositoryRole` (This is the actor type, the following are the base repository roles and their associated IDs.)
* `maintain` -> `2`
* `write` -> `4`
* `admin` -> `5`


#### conditions ####

* `ref_name` - (Required) (Block List, Min: 1, Max: 1) (see [below for nested schema](#conditions.ref_name))
Expand All @@ -223,14 +231,12 @@ The `rules` block supports the following:

The following additional attributes are exported:


* `etag` (String)

* `node_id` (String) GraphQL global node id for use with v4 API.

* `ruleset_id` (Number) GitHub ID for the ruleset.


## Import

GitHub Repository Rulesets can be imported using the GitHub repository name and ruleset ID e.g.
Expand Down