diff --git a/modules/private_repository/README.md b/modules/private_repository/README.md index 9559002..bec2428 100644 --- a/modules/private_repository/README.md +++ b/modules/private_repository/README.md @@ -35,7 +35,7 @@ No resources. | [dependabot\_secrets](#input\_dependabot\_secrets) | An (Optional) map of Dependabot secrets to create for this repository. The key is the name of the secret and the value is the encrypted value. | `map(string)` | `{}` | no | | [dependabot\_security\_updates](#input\_dependabot\_security\_updates) | Enables dependabot security updates. Only works when `has_vulnerability_alerts` is set because that is required to enable dependabot for the repository. | `bool` | `true` | no | | [description](#input\_description) | The description to give to the repository. Defaults to `""` | `string` | `""` | no | -| [environments](#input\_environments) | Environments to create for the repository. |
map(object({
action_secrets = optional(map(string))
})) | `{}` | no |
+| [environments](#input\_environments) | Environments to create for the repository. | map(object({
wait_timer = optional(number)
can_admins_bypass = optional(bool)
prevent_self_review = optional(bool)
action_secrets = optional(map(string))
reviewers = optional(object({
teams = optional(list(string))
users = optional(list(string))
}))
deployment_branch_policy = optional(object({
protected_branches = bool
custom_branch_policies = bool
branch_patterns = list(string)
}))
})) | `{}` | no |
| [has\_ghas\_license](#input\_has\_ghas\_license) | If the organization owning the repository has a GitHub Advanced Security license or not. Defaults to false. | `bool` | `false` | no |
| [homepage](#input\_homepage) | The homepage for the repository | `string` | `""` | no |
| [license\_template](#input\_license\_template) | The (Optional) license template to use for the repository | `string` | `null` | no |
diff --git a/modules/private_repository/variables.tf b/modules/private_repository/variables.tf
index 186329a..3db58e2 100644
--- a/modules/private_repository/variables.tf
+++ b/modules/private_repository/variables.tf
@@ -100,7 +100,19 @@ variable "dependabot_secrets" {
variable "environments" {
description = "Environments to create for the repository."
type = map(object({
- action_secrets = optional(map(string))
+ wait_timer = optional(number)
+ can_admins_bypass = optional(bool)
+ prevent_self_review = optional(bool)
+ action_secrets = optional(map(string))
+ reviewers = optional(object({
+ teams = optional(list(string))
+ users = optional(list(string))
+ }))
+ deployment_branch_policy = optional(object({
+ protected_branches = bool
+ custom_branch_policies = bool
+ branch_patterns = list(string)
+ }))
}))
default = {}
}
diff --git a/modules/public_repository/README.md b/modules/public_repository/README.md
index 7a41231..1c4157a 100644
--- a/modules/public_repository/README.md
+++ b/modules/public_repository/README.md
@@ -35,7 +35,7 @@ No resources.
| [dependabot\_secrets](#input\_dependabot\_secrets) | An (Optional) map of Dependabot secrets to create for this repository. The key is the name of the secret and the value is the encrypted value. | `map(string)` | `{}` | no |
| [dependabot\_security\_updates](#input\_dependabot\_security\_updates) | Enables dependabot security updates. Only works when `has_vulnerability_alerts` is set because that is required to enable dependabot for the repository. | `bool` | `true` | no |
| [description](#input\_description) | The description to give to the repository. Defaults to `""` | `string` | `""` | no |
-| [environments](#input\_environments) | Environments to create for the repository. | map(object({
action_secrets = optional(map(string))
})) | `{}` | no |
+| [environments](#input\_environments) | Environments to create for the repository. | map(object({
wait_timer = optional(number)
can_admins_bypass = optional(bool)
prevent_self_review = optional(bool)
action_secrets = optional(map(string))
reviewers = optional(object({
teams = optional(list(string))
users = optional(list(string))
}))
deployment_branch_policy = optional(object({
protected_branches = bool
custom_branch_policies = bool
branch_patterns = list(string)
}))
})) | `{}` | no |
| [homepage](#input\_homepage) | The homepage for the repository | `string` | `""` | no |
| [license\_template](#input\_license\_template) | The (Optional) license template to apply to the repository | `string` | `null` | no |
| [merge\_commit\_message](#input\_merge\_commit\_message) | (Optional) Can be `PR_BODY`, `PR_TITLE`, or `BLANK` for a default merge commit message. Applicable only if allow\_merge\_commit is `true`. | `string` | `"PR_TITLE"` | no |
diff --git a/modules/public_repository/variables.tf b/modules/public_repository/variables.tf
index 99b5ee7..7d5cf79 100644
--- a/modules/public_repository/variables.tf
+++ b/modules/public_repository/variables.tf
@@ -94,7 +94,19 @@ variable "dependabot_secrets" {
variable "environments" {
description = "Environments to create for the repository."
type = map(object({
- action_secrets = optional(map(string))
+ wait_timer = optional(number)
+ can_admins_bypass = optional(bool)
+ prevent_self_review = optional(bool)
+ action_secrets = optional(map(string))
+ reviewers = optional(object({
+ teams = optional(list(string))
+ users = optional(list(string))
+ }))
+ deployment_branch_policy = optional(object({
+ protected_branches = bool
+ custom_branch_policies = bool
+ branch_patterns = list(string)
+ }))
}))
default = {}
}
diff --git a/modules/repository_base/README.md b/modules/repository_base/README.md
index f7a186e..3f039aa 100644
--- a/modules/repository_base/README.md
+++ b/modules/repository_base/README.md
@@ -30,6 +30,7 @@
| [github_repository_collaborators.collaborators](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/repository_collaborators) | resource |
| [github_repository_dependabot_security_updates.automated_security_fixes](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/repository_dependabot_security_updates) | resource |
| [github_repository_environment.environment](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/repository_environment) | resource |
+| [github_repository_environment_deployment_policy.deployment_policy](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/repository_environment_deployment_policy) | resource |
| [github_repository_ruleset.protected_branch_base_rules](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/repository_ruleset) | resource |
| [github_organization_custom_role.branch_ruleset_bypasser](https://registry.terraform.io/providers/integrations/github/latest/docs/data-sources/organization_custom_role) | data source |
| [github_team.branch_ruleset_bypasser](https://registry.terraform.io/providers/integrations/github/latest/docs/data-sources/team) | data source |
@@ -51,7 +52,7 @@
| [dependabot\_secrets](#input\_dependabot\_secrets) | An (Optional) map of Dependabot secrets to create for this repository. The key is the name of the secret and the value is the encrypted value. | `map(string)` | `{}` | no |
| [dependabot\_security\_updates](#input\_dependabot\_security\_updates) | Enables dependabot security updates. Only works when `has_vulnerability_alerts` is set because that is required to enable dependabot for the repository. | `bool` | `true` | no |
| [description](#input\_description) | The description to give to the repository. Defaults to `""` | `string` | `""` | no |
-| [environments](#input\_environments) | An (Optional) map of environments to create for the repository. The key is the name of the environment and the value is the environment configuration. | map(object({
action_secrets = optional(map(string))
})) | `{}` | no |
+| [environments](#input\_environments) | An (Optional) map of environments to create for the repository. The key is the name of the environment and the value is the environment configuration. | map(object({
wait_timer = optional(number)
can_admins_bypass = optional(bool)
prevent_self_review = optional(bool)
action_secrets = optional(map(string))
reviewers = optional(object({
teams = optional(list(string))
users = optional(list(string))
}))
deployment_branch_policy = optional(object({
protected_branches = bool
custom_branch_policies = bool
branch_patterns = list(string)
}))
})) | `{}` | no |
| [has\_discussions](#input\_has\_discussions) | Enables Github Discussions. | `bool` | `true` | no |
| [has\_downloads](#input\_has\_downloads) | Enables downloads for the repository | `bool` | `false` | no |
| [has\_issues](#input\_has\_issues) | Enables Github Issues for the repository | `bool` | `true` | no |
diff --git a/modules/repository_base/environments.tf b/modules/repository_base/environments.tf
index 08c3f60..07f01ec 100644
--- a/modules/repository_base/environments.tf
+++ b/modules/repository_base/environments.tf
@@ -1,5 +1,47 @@
+locals {
+ coalesced_environments = coalesce(var.environments, {})
+ env_deployment_branch_patterns = {
+ for env_name, env in local.coalesced_environments : env_name => env.deployment_branch_policy.branch_patterns if env.deployment_branch_policy != null
+ }
+
+ deployment_policy_configurations = merge([
+ for env_name, branch_patterns in local.env_deployment_branch_patterns : {
+ for pattern in branch_patterns : "${env_name}:${pattern}" => {
+ pattern = pattern,
+ environment = env_name
+ }
+ }
+ ]...)
+}
+
resource "github_repository_environment" "environment" {
- for_each = toset(keys(coalesce(var.environments, {})))
- repository = github_repository.repository.name
- environment = each.value
+ for_each = local.coalesced_environments
+ repository = github_repository.repository.name
+ environment = each.key
+ wait_timer = each.value.wait_timer
+ can_admins_bypass = each.value.can_admins_bypass
+ prevent_self_review = each.value.prevent_self_review
+
+ dynamic "reviewers" {
+ for_each = each.value.reviewers != null ? toset([each.value.reviewers]) : []
+ content {
+ teams = reviewers.value.teams
+ users = reviewers.value.users
+ }
+ }
+
+ dynamic "deployment_branch_policy" {
+ for_each = each.value.deployment_branch_policy != null ? toset([each.value.deployment_branch_policy]) : []
+ content {
+ protected_branches = deployment_branch_policy.value.protected_branches
+ custom_branch_policies = deployment_branch_policy.value.custom_branch_policies
+ }
+ }
+}
+
+resource "github_repository_environment_deployment_policy" "deployment_policy" {
+ for_each = local.deployment_policy_configurations
+ repository = github_repository.repository.name
+ environment = github_repository_environment.environment["${each.value.environment}"].environment
+ branch_pattern = each.value.pattern
}
diff --git a/modules/repository_base/variables.tf b/modules/repository_base/variables.tf
index 0aa1291..a8808e5 100644
--- a/modules/repository_base/variables.tf
+++ b/modules/repository_base/variables.tf
@@ -148,7 +148,19 @@ variable "dependabot_secrets" {
variable "environments" {
description = "An (Optional) map of environments to create for the repository. The key is the name of the environment and the value is the environment configuration."
type = map(object({
- action_secrets = optional(map(string))
+ wait_timer = optional(number)
+ can_admins_bypass = optional(bool)
+ prevent_self_review = optional(bool)
+ action_secrets = optional(map(string))
+ reviewers = optional(object({
+ teams = optional(list(string))
+ users = optional(list(string))
+ }))
+ deployment_branch_policy = optional(object({
+ protected_branches = bool
+ custom_branch_policies = bool
+ branch_patterns = list(string)
+ }))
}))
default = {}
}
diff --git a/modules/repository_set/README.md b/modules/repository_set/README.md
index 6477b43..5a74929 100644
--- a/modules/repository_set/README.md
+++ b/modules/repository_set/README.md
@@ -32,8 +32,8 @@
|------|-------------|------|---------|:--------:|
| [default\_repository\_team\_permissions](#input\_default\_repository\_team\_permissions) | A map where the keys are github team slugs and the value is the permissions the team should have by default for every repository. If an entry exists in `repository_team_permissions_override` for a repository then that will take precedence over this default. Defaults to `{}` giving no team access to the repositories. | `map(string)` | `{}` | no |
| [has\_ghas\_license](#input\_has\_ghas\_license) | If the organization owning the repositories has a GitHub Advanced Security license or not. Defaults to false. | `bool` | `false` | no |
-| [private\_repositories](#input\_private\_repositories) | A map of private repositories where the key is the repository name and the value is the configuration | map(object({
description = string
default_branch = string
protected_branches = list(string)
advance_security = bool
has_vulnerability_alerts = bool
topics = list(string)
homepage = string
delete_head_on_merge = bool
requires_web_commit_signing = bool
dependabot_security_updates = bool
allow_auto_merge = optional(bool)
allow_squash_merge = optional(bool)
allow_rebase_merge = optional(bool)
allow_merge_commit = optional(bool)
squash_merge_commit_title = optional(string)
squash_merge_commit_message = optional(string)
merge_commit_title = optional(string)
merge_commit_message = optional(string)
repository_team_permissions_override = optional(map(string))
user_permissions = optional(map(string))
organization_action_secrets = optional(list(string))
organization_codespace_secrets = optional(list(string))
organization_dependabot_secrets = optional(list(string))
action_secrets = optional(map(string))
codespace_secrets = optional(map(string))
dependabot_secrets = optional(map(string))
environments = optional(map(object({
action_secrets = optional(map(string))
})))
template_repository = optional(object({
owner = string
repository = string
include_all_branches = bool
}))
license_template = optional(string)
pages = optional(object({
source = optional(object({
branch = string
path = optional(string)
}))
build_type = optional(string)
cname = optional(string)
}))
})) | n/a | yes |
-| [public\_repositories](#input\_public\_repositories) | A map of public repositories where the key is the repository name and the value is the configuration | map(object({
description = string
default_branch = string
protected_branches = list(string)
advance_security = bool
topics = list(string)
homepage = string
delete_head_on_merge = bool
dependabot_security_updates = bool
requires_web_commit_signing = bool
allow_auto_merge = optional(bool)
allow_squash_merge = optional(bool)
allow_rebase_merge = optional(bool)
allow_merge_commit = optional(bool)
squash_merge_commit_title = optional(string)
squash_merge_commit_message = optional(string)
merge_commit_title = optional(string)
merge_commit_message = optional(string)
repository_team_permissions_override = optional(map(string))
user_permissions = optional(map(string))
organization_action_secrets = optional(list(string))
organization_codespace_secrets = optional(list(string))
organization_dependabot_secrets = optional(list(string))
action_secrets = optional(map(string))
codespace_secrets = optional(map(string))
dependabot_secrets = optional(map(string))
environments = optional(map(object({
action_secrets = optional(map(string))
})))
template_repository = optional(object({
owner = string
repository = string
include_all_branches = bool
}))
license_template = optional(string)
pages = optional(object({
source = optional(object({
branch = string
path = optional(string)
}))
build_type = optional(string)
cname = optional(string)
}))
})) | n/a | yes |
+| [private\_repositories](#input\_private\_repositories) | A map of private repositories where the key is the repository name and the value is the configuration | map(object({
description = string
default_branch = string
protected_branches = list(string)
advance_security = bool
has_vulnerability_alerts = bool
topics = list(string)
homepage = string
delete_head_on_merge = bool
requires_web_commit_signing = bool
dependabot_security_updates = bool
allow_auto_merge = optional(bool)
allow_squash_merge = optional(bool)
allow_rebase_merge = optional(bool)
allow_merge_commit = optional(bool)
squash_merge_commit_title = optional(string)
squash_merge_commit_message = optional(string)
merge_commit_title = optional(string)
merge_commit_message = optional(string)
repository_team_permissions_override = optional(map(string))
user_permissions = optional(map(string))
organization_action_secrets = optional(list(string))
organization_codespace_secrets = optional(list(string))
organization_dependabot_secrets = optional(list(string))
action_secrets = optional(map(string))
codespace_secrets = optional(map(string))
dependabot_secrets = optional(map(string))
environments = optional(map(object({
wait_timer = optional(number)
can_admins_bypass = optional(bool)
prevent_self_review = optional(bool)
action_secrets = optional(map(string))
reviewers = optional(object({
teams = optional(list(string))
users = optional(list(string))
}))
deployment_branch_policy = optional(object({
protected_branches = bool
custom_branch_policies = bool
branch_patterns = list(string)
}))
})))
template_repository = optional(object({
owner = string
repository = string
include_all_branches = bool
}))
license_template = optional(string)
pages = optional(object({
source = optional(object({
branch = string
path = optional(string)
}))
build_type = optional(string)
cname = optional(string)
}))
})) | n/a | yes |
+| [public\_repositories](#input\_public\_repositories) | A map of public repositories where the key is the repository name and the value is the configuration | map(object({
description = string
default_branch = string
protected_branches = list(string)
advance_security = bool
topics = list(string)
homepage = string
delete_head_on_merge = bool
dependabot_security_updates = bool
requires_web_commit_signing = bool
allow_auto_merge = optional(bool)
allow_squash_merge = optional(bool)
allow_rebase_merge = optional(bool)
allow_merge_commit = optional(bool)
squash_merge_commit_title = optional(string)
squash_merge_commit_message = optional(string)
merge_commit_title = optional(string)
merge_commit_message = optional(string)
repository_team_permissions_override = optional(map(string))
user_permissions = optional(map(string))
organization_action_secrets = optional(list(string))
organization_codespace_secrets = optional(list(string))
organization_dependabot_secrets = optional(list(string))
action_secrets = optional(map(string))
codespace_secrets = optional(map(string))
dependabot_secrets = optional(map(string))
environments = optional(map(object({
wait_timer = optional(number)
can_admins_bypass = optional(bool)
prevent_self_review = optional(bool)
action_secrets = optional(map(string))
reviewers = optional(object({
teams = optional(list(string))
users = optional(list(string))
}))
deployment_branch_policy = optional(object({
protected_branches = bool
custom_branch_policies = bool
branch_patterns = list(string)
}))
})))
template_repository = optional(object({
owner = string
repository = string
include_all_branches = bool
}))
license_template = optional(string)
pages = optional(object({
source = optional(object({
branch = string
path = optional(string)
}))
build_type = optional(string)
cname = optional(string)
}))
})) | n/a | yes |
| [rulesets](#input\_rulesets) | n/a | map(object({
bypass_actors = optional(object({
repository_roles = optional(list(object({
role = string
always_bypass = optional(bool)
})))
teams = optional(list(object({
team = string
always_bypass = optional(bool)
})))
integrations = optional(list(object({
installation_id = number
always_bypass = optional(bool)
})))
organization_admins = optional(list(object({
user = string
always_bypass = optional(bool)
})))
}))
conditions = optional(object({
ref_name = object({
include = list(string)
exclude = list(string)
})
}))
rules = object({
branch_name_pattern = optional(object({
operator = string
pattern = string
name = optional(string)
negate = optional(bool)
}))
tag_name_pattern = optional(object({
operator = string
pattern = string
name = optional(string)
negate = optional(bool)
}))
commit_author_email_pattern = optional(object({
operator = string
pattern = string
name = optional(string)
negate = optional(bool)
}))
commit_message_pattern = optional(object({
operator = string
pattern = string
name = optional(string)
negate = optional(bool)
}))
committer_email_pattern = optional(object({
operator = string
pattern = string
name = optional(string)
negate = optional(bool)
}))
creation = optional(bool)
deletion = optional(bool)
update = optional(bool)
non_fast_forward = optional(bool)
required_linear_history = optional(bool)
required_signatures = optional(bool)
update_allows_fetch_and_merge = optional(bool)
pull_request = optional(object({
dismiss_stale_reviews_on_push = optional(bool)
require_code_owner_review = optional(bool)
require_last_push_approval = optional(bool)
required_approving_review_count = optional(number)
required_review_thread_resolution = optional(bool)
}))
required_status_checks = optional(object({
required_check = list(object({
context = string
integration_id = optional(number)
}))
strict_required_status_check_policy = optional(bool)
}))
required_deployment_environments = optional(list(string))
})
target = string
enforcement = string
repositories = list(string)
})) | `{}` | no |
## Outputs
diff --git a/modules/repository_set/variables.tf b/modules/repository_set/variables.tf
index a9ddee6..9288cb9 100644
--- a/modules/repository_set/variables.tf
+++ b/modules/repository_set/variables.tf
@@ -27,7 +27,19 @@ variable "private_repositories" {
codespace_secrets = optional(map(string))
dependabot_secrets = optional(map(string))
environments = optional(map(object({
- action_secrets = optional(map(string))
+ wait_timer = optional(number)
+ can_admins_bypass = optional(bool)
+ prevent_self_review = optional(bool)
+ action_secrets = optional(map(string))
+ reviewers = optional(object({
+ teams = optional(list(string))
+ users = optional(list(string))
+ }))
+ deployment_branch_policy = optional(object({
+ protected_branches = bool
+ custom_branch_policies = bool
+ branch_patterns = list(string)
+ }))
})))
template_repository = optional(object({
owner = string
@@ -75,7 +87,19 @@ variable "public_repositories" {
codespace_secrets = optional(map(string))
dependabot_secrets = optional(map(string))
environments = optional(map(object({
- action_secrets = optional(map(string))
+ wait_timer = optional(number)
+ can_admins_bypass = optional(bool)
+ prevent_self_review = optional(bool)
+ action_secrets = optional(map(string))
+ reviewers = optional(object({
+ teams = optional(list(string))
+ users = optional(list(string))
+ }))
+ deployment_branch_policy = optional(object({
+ protected_branches = bool
+ custom_branch_policies = bool
+ branch_patterns = list(string)
+ }))
})))
template_repository = optional(object({
owner = string