diff --git a/modules/private_repository/README.md b/modules/private_repository/README.md index 283b942..0ff1289 100644 --- a/modules/private_repository/README.md +++ b/modules/private_repository/README.md @@ -38,6 +38,7 @@ No resources. | [name](#input\_name) | The name of the repository to create/import. | `string` | n/a | yes | | [protected\_branches](#input\_protected\_branches) | A list of ref names or patterns that should be protected. Defaults `["main"]` | `list(string)` |
[
"main"
]
| no | | [repository\_team\_permissions](#input\_repository\_team\_permissions) | A map where the keys are github team slugs and the value is the permissions the team should have in the repository | `map(string)` | n/a | yes | +| [repository\_user\_permissions](#input\_repository\_user\_permissions) | A map where the keys are github usernames and the value is the permissions the user should have in the repository | `map(string)` | n/a | yes | | [requires\_web\_commit\_signing](#input\_requires\_web\_commit\_signing) | If set commit signatures are required for commits to the organization. Defaults to `false`. | `bool` | `false` | no | | [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
}))
| `{}` | no | | [template\_repository](#input\_template\_repository) | A (Optional) list of template repositories to use for the repository |
object({
owner = string
repository = string
include_all_branches = bool
})
| `null` | no | diff --git a/modules/private_repository/repository.tf b/modules/private_repository/repository.tf index bab5cdf..a872ce4 100644 --- a/modules/private_repository/repository.tf +++ b/modules/private_repository/repository.tf @@ -13,6 +13,7 @@ module "repository_base" { has_discussions = false repository_team_permissions = var.repository_team_permissions + repository_user_permissions = var.repository_user_permissions default_branch = var.default_branch protected_branches = var.protected_branches diff --git a/modules/private_repository/variables.tf b/modules/private_repository/variables.tf index f6c6fff..b347472 100644 --- a/modules/private_repository/variables.tf +++ b/modules/private_repository/variables.tf @@ -20,6 +20,11 @@ variable "repository_team_permissions" { description = "A map where the keys are github team slugs and the value is the permissions the team should have in the repository" } +variable "repository_user_permissions" { + type = map(string) + description = "A map where the keys are github usernames and the value is the permissions the user should have in the repository" +} + variable "protected_branches" { type = list(string) description = "A list of ref names or patterns that should be protected. Defaults `[\"main\"]`" diff --git a/modules/public_repository/README.md b/modules/public_repository/README.md index 125a701..b47dc90 100644 --- a/modules/public_repository/README.md +++ b/modules/public_repository/README.md @@ -38,6 +38,7 @@ No resources. | [name](#input\_name) | The name of the repository to create/import. | `string` | n/a | yes | | [protected\_branches](#input\_protected\_branches) | A list of ref names or patterns that should be protected. Defaults `["main"]` | `list(string)` |
[
"main"
]
| no | | [repository\_team\_permissions](#input\_repository\_team\_permissions) | A map where the keys are github team slugs and the value is the permissions the team should have in the repository | `map(string)` | n/a | yes | +| [repository\_user\_permissions](#input\_repository\_user\_permissions) | A map where the keys are github usernames and the value is the permissions the user should have in the repository | `map(string)` | n/a | yes | | [requires\_web\_commit\_signing](#input\_requires\_web\_commit\_signing) | If set commit signatures are required for commits to the organization. Defaults to `false`. | `bool` | `false` | no | | [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
}))
| `{}` | no | | [template\_repository](#input\_template\_repository) | A (Optional) list of template repositories to use for the repository |
object({
owner = string
repository = string
include_all_branches = bool
})
| `null` | no | diff --git a/modules/public_repository/repository.tf b/modules/public_repository/repository.tf index 64a8699..811be5c 100644 --- a/modules/public_repository/repository.tf +++ b/modules/public_repository/repository.tf @@ -13,6 +13,7 @@ module "repository_base" { has_discussions = true repository_team_permissions = var.repository_team_permissions + repository_user_permissions = var.repository_user_permissions default_branch = var.default_branch protected_branches = var.protected_branches diff --git a/modules/public_repository/variables.tf b/modules/public_repository/variables.tf index 87360d0..4c6195f 100644 --- a/modules/public_repository/variables.tf +++ b/modules/public_repository/variables.tf @@ -20,6 +20,11 @@ variable "repository_team_permissions" { description = "A map where the keys are github team slugs and the value is the permissions the team should have in the repository" } +variable "repository_user_permissions" { + type = map(string) + description = "A map where the keys are github usernames and the value is the permissions the user should have in the repository" +} + variable "protected_branches" { type = list(string) description = "A list of ref names or patterns that should be protected. Defaults `[\"main\"]`" diff --git a/modules/repository_base/README.md b/modules/repository_base/README.md index 1fa224e..94c955e 100644 --- a/modules/repository_base/README.md +++ b/modules/repository_base/README.md @@ -60,6 +60,7 @@ | [name](#input\_name) | The name of the repository to create/import. | `string` | n/a | yes | | [protected\_branches](#input\_protected\_branches) | A list of ref names or patterns that should be protected. Setting to `[]` means no protection. Defaults `["~DEFAULT_BRANCH"]` | `list(string)` |
[
"~DEFAULT_BRANCH"
]
| no | | [repository\_team\_permissions](#input\_repository\_team\_permissions) | A map where the keys are github team slugs and the value is the permissions the team should have in the repository | `map(string)` | n/a | yes | +| [repository\_user\_permissions](#input\_repository\_user\_permissions) | A map where the keys are github usernames and the value is the permissions the user should have in the repository | `map(string)` | n/a | yes | | [requires\_web\_commit\_signing](#input\_requires\_web\_commit\_signing) | If set commit signatures are required for commits to the organization. Defaults to `false`. | `bool` | `false` | no | | [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
}))
| `{}` | no | | [secret\_scanning](#input\_secret\_scanning) | Enables secret scanning for the repository. If repository is private `advance_security` must also be enabled. | `bool` | `true` | no | diff --git a/modules/repository_base/teams.tf b/modules/repository_base/collaborators.tf similarity index 63% rename from modules/repository_base/teams.tf rename to modules/repository_base/collaborators.tf index 8532470..b30f3f9 100644 --- a/modules/repository_base/teams.tf +++ b/modules/repository_base/collaborators.tf @@ -8,4 +8,12 @@ resource "github_repository_collaborators" "collaborators" { team_id = team.key } } + + dynamic "user" { + for_each = var.repository_user_permissions + content { + permission = user.value + username = user.key + } + } } diff --git a/modules/repository_base/variables.tf b/modules/repository_base/variables.tf index 88d8146..7bd1356 100644 --- a/modules/repository_base/variables.tf +++ b/modules/repository_base/variables.tf @@ -20,6 +20,11 @@ variable "repository_team_permissions" { description = "A map where the keys are github team slugs and the value is the permissions the team should have in the repository" } +variable "repository_user_permissions" { + type = map(string) + description = "A map where the keys are github usernames and the value is the permissions the user should have in the repository" +} + variable "protected_branches" { type = list(string) description = "A list of ref names or patterns that should be protected. Setting to `[]` means no protection. Defaults `[\"~DEFAULT_BRANCH\"]`" diff --git a/modules/repository_set/README.md b/modules/repository_set/README.md index c1b7a70..6e325f0 100644 --- a/modules/repository_set/README.md +++ b/modules/repository_set/README.md @@ -30,9 +30,9 @@ | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [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. | `map(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
repository_team_permissions_override = map(string)
protected_branches = list(string)
advance_security = bool
has_vulnerability_alerts = bool
topics = list(string)
homepage = string
delete_head_on_merge = bool
allow_auto_merge = bool
requires_web_commit_signing = bool
dependabot_security_updates = bool
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)
}))
| 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
repository_team_permissions_override = map(string)
protected_branches = list(string)
advance_security = bool
topics = list(string)
homepage = string
delete_head_on_merge = bool
allow_auto_merge = bool
dependabot_security_updates = bool
requires_web_commit_signing = bool
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)
}))
| n/a | yes | +| [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 | +| [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
allow_auto_merge = bool
requires_web_commit_signing = bool
dependabot_security_updates = bool
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)
}))
| 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
allow_auto_merge = bool
dependabot_security_updates = bool
requires_web_commit_signing = bool
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)
}))
| 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/repositories.tf b/modules/repository_set/repositories.tf index 46b3929..e475415 100644 --- a/modules/repository_set/repositories.tf +++ b/modules/repository_set/repositories.tf @@ -17,7 +17,8 @@ module "public_repositories" { for_each = var.public_repositories name = each.key - repository_team_permissions = merge(var.default_repository_team_permissions, each.value.repository_team_permissions_override) + repository_team_permissions = merge(var.default_repository_team_permissions, coalesce(each.value.repository_team_permissions_override, {})) + repository_user_permissions = coalesce(each.value.user_permissions, {}) description = each.value.description default_branch = each.value.default_branch protected_branches = each.value.protected_branches @@ -43,7 +44,8 @@ module "private_repositories" { for_each = var.private_repositories name = each.key - repository_team_permissions = merge(var.default_repository_team_permissions, each.value.repository_team_permissions_override) + repository_team_permissions = merge(var.default_repository_team_permissions, coalesce(each.value.repository_team_permissions_override, {})) + repository_user_permissions = coalesce(each.value.user_permissions, {}) description = each.value.description default_branch = each.value.default_branch protected_branches = each.value.protected_branches diff --git a/modules/repository_set/variables.tf b/modules/repository_set/variables.tf index 2edb044..df03511 100644 --- a/modules/repository_set/variables.tf +++ b/modules/repository_set/variables.tf @@ -2,7 +2,6 @@ variable "private_repositories" { type = map(object({ description = string default_branch = string - repository_team_permissions_override = map(string) protected_branches = list(string) advance_security = bool has_vulnerability_alerts = bool @@ -12,6 +11,8 @@ variable "private_repositories" { allow_auto_merge = bool requires_web_commit_signing = bool dependabot_security_updates = bool + 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)) @@ -35,7 +36,6 @@ variable "public_repositories" { type = map(object({ description = string default_branch = string - repository_team_permissions_override = map(string) protected_branches = list(string) advance_security = bool topics = list(string) @@ -44,6 +44,8 @@ variable "public_repositories" { allow_auto_merge = bool dependabot_security_updates = bool requires_web_commit_signing = bool + 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)) @@ -65,7 +67,8 @@ variable "public_repositories" { variable "default_repository_team_permissions" { type = map(string) - description = "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." + description = "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." + default = {} } variable "rulesets" {