diff --git a/README.md b/README.md index d63ad95..f88ec63 100644 --- a/README.md +++ b/README.md @@ -152,22 +152,44 @@ The GitHub organization YAML configuration post a Terraform plan as a pull reque ### GitHub Organization YAML +The example below demonstrates the full range of capabilities available in the organization YAML configuration. + ```yaml --- -default-properties: # OPTIONAL - # Global properties - visibility: public # OPTIONAL, DEFAULT public - # Global features - has_issues: true # OPTIONAL, DEFAULT false - has_discussions: true # OPTIONAL, DEFAULT false - has_projects: true # OPTIONAL, DEFAULT false - has_wiki: true # OPTIONAL, DEFAULT false - # Global settings - allow_merge_commit: false # OPTIONAL, DEFAULT true - allow_squash_merge: true # OPTIONAL, DEFAULT true - allow_rebase_merge: true # OPTIONAL, DEFAULT true - allow_auto_merge: true # OPTIONAL, DEFAULT false - delete_branch_on_merge: true # OPTIONAL, DEFAULT false +organization: + all-repositories: # OPTIONAL + # All-repository default properties + visibility: public # OPTIONAL, DEFAULT public + # All-repository default features + has_issues: true # OPTIONAL, DEFAULT false + has_discussions: true # OPTIONAL, DEFAULT false + has_projects: true # OPTIONAL, DEFAULT false + has_wiki: true # OPTIONAL, DEFAULT false + # All-repository default settings + allow_merge_commit: false # OPTIONAL, DEFAULT true + allow_squash_merge: true # OPTIONAL, DEFAULT true + allow_rebase_merge: true # OPTIONAL, DEFAULT true + allow_auto_merge: true # OPTIONAL, DEFAULT false + delete_branch_on_merge: true # OPTIONAL, DEFAULT false + # All-repository default rulesets + rulesets: + - name: "Main Branch" + target: branch # REQUIRED, VALUES branch or tag + enforcement: active # REQUIRED, VALUES disabled or active + conditions: # OPTIONAL, DEFAULT empty + ref_name: + include: # OPTIONAL, DEFAULT empty, VALUE array of ref names or patterns to include, special values ~ALL and ~DEFAULT_BRANCH also accepted + - ~DEFAULT_BRANCH + exclude: # OPTIONAL, DEFAULT empty + rules: + creation: false # OPTIONAL, DEFAULT true + update: false # OPTIONAL, DEFAULT true + update_allows_fetch_and_merge: false # OPTIONAL, DEFAULT false + deletion: false # OPTIONAL, DEFAULT true + required_linear_history: true # OPTIONAL, DEFAULT false + required_signatures: true # OPTIONAL, DEFAULT false + pull_request: # OPTIONAL, DEFAULT empty MEANING does not require a pull request before merging + required_approving_review_count: 0 # OPTIONAL, DEFAULT 0 repositories: - name: repo-slug # Repository metadata @@ -191,7 +213,7 @@ repositories: delete_branch_on_merge: true # OPTIONAL, DEFAULT false ``` -Defaults are the same as in the Terraform provider `github` resource `github_repository`, see [Terraform Registry / Providers / integrations / github / resources / github_repository](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/repository#argument-reference). +Defaults are usually the same as in the Terraform provider `github` resource `github_repository`, see [Terraform Registry / Providers / integrations / github / resources / github_repository](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/repository#argument-reference). ### Local Usage diff --git a/terraform/main.tf b/terraform/main.tf index 6c83c7d..35f3cbb 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -1,7 +1,13 @@ locals { - config = yamldecode(file(var.path)) - default_properties = try(local.config.default-properties, null) - repositories = local.config.repositories + config = yamldecode(file(var.path)) + all_repositories = try(local.config.organization.all-repositories, null) + repositories = local.config.repositories + all_repositories_rulesets = [ + for pair in setproduct(local.repositories, local.all_repositories.rulesets) : { + repository = pair[0] + ruleset = pair[1] + } + ] } resource "github_repository" "repo" { @@ -14,19 +20,64 @@ resource "github_repository" "repo" { topics = try(each.value.topics, null) # Properties - visibility = try(each.value.visibility, local.default_properties.visibility, null) + visibility = try(each.value.visibility, local.all_repositories.visibility, null) is_template = try(each.value.is_template, null) # Features - has_issues = try(each.value.has_issues, local.default_properties.has_issues, null) - has_discussions = try(each.value.has_discussions, local.default_properties.has_discussions, null) - has_projects = try(each.value.has_projects, local.default_properties.has_projects, null) - has_wiki = try(each.value.has_wiki, local.default_properties.has_wiki, null) + has_issues = try(each.value.has_issues, local.all_repositories.has_issues, null) + has_discussions = try(each.value.has_discussions, local.all_repositories.has_discussions, null) + has_projects = try(each.value.has_projects, local.all_repositories.has_projects, null) + has_wiki = try(each.value.has_wiki, local.all_repositories.has_wiki, null) # Settings - allow_merge_commit = try(each.value.allow_merge_commit, local.default_properties.allow_merge_commit, null) - allow_squash_merge = try(each.value.allow_squash_merge, local.default_properties.allow_squash_merge, null) - allow_rebase_merge = try(each.value.allow_rebase_merge, local.default_properties.allow_rebase_merge, null) - allow_auto_merge = try(each.value.allow_auto_merge, local.default_properties.allow_auto_merge, null) - delete_branch_on_merge = try(each.value.delete_branch_on_merge, local.default_properties.delete_branch_on_merge, null) + allow_merge_commit = try(each.value.allow_merge_commit, local.all_repositories.allow_merge_commit, null) + allow_squash_merge = try(each.value.allow_squash_merge, local.all_repositories.allow_squash_merge, null) + allow_rebase_merge = try(each.value.allow_rebase_merge, local.all_repositories.allow_rebase_merge, null) + allow_auto_merge = try(each.value.allow_auto_merge, local.all_repositories.allow_auto_merge, null) + delete_branch_on_merge = try(each.value.delete_branch_on_merge, local.all_repositories.delete_branch_on_merge, null) +} + +resource "github_repository_ruleset" "all_repositories" { + for_each = { + for repository_ruleset in local.all_repositories_rulesets : + format("%s/%s", "${repository_ruleset.repository.name}", replace(lower("${repository_ruleset.ruleset.name}"), " ", "_")) => repository_ruleset + } + + # Metadata + name = each.value.ruleset.name + repository = each.value.repository.name + target = try(each.value.ruleset.target, null) + enforcement = try(each.value.ruleset.enforcement, null) + + # Conditions + dynamic "conditions" { + for_each = try(length(each.value.ruleset.conditions) > 0 ? [each.value.ruleset.conditions] : [], []) + content { + ref_name { + include = try(each.value.ruleset.conditions.ref_name.include, []) + exclude = try(each.value.ruleset.conditions.ref_name.exclude, []) + } + } + } + + # Rules + rules { + # Lifecycle rules + creation = try(each.value.ruleset.rules.creation, null) + update = try(each.value.ruleset.rules.update, null) + update_allows_fetch_and_merge = try(each.value.ruleset.rules.update_allows_fetch_and_merge, null) + deletion = try(each.value.ruleset.rules.deletion, null) + + # Commit and history rules + required_linear_history = try(each.value.ruleset.rules.required_linear_history, null) + required_signatures = try(each.value.ruleset.rules.required_signatures, null) + + # PR rules + dynamic "pull_request" { + for_each = try(length(each.value.ruleset.rules.pull_request) > 0 ? [each.value.ruleset.rules.pull_request] : [], []) + content { + required_approving_review_count = try(pull_request.value.required_approving_review_count, null) + } + } + } } diff --git a/test.yaml b/test.yaml index 1e5de7f..1ad21e4 100644 --- a/test.yaml +++ b/test.yaml @@ -1,7 +1,25 @@ --- -default-properties: - # Global features - has_issues: true +organization: + all-repositories: + # All-repository default features + has_issues: true + # All-repository default rulesets + rulesets: + - name: "Main Branch" + target: branch + enforcement: active + conditions: + ref_name: + include: + - ~DEFAULT_BRANCH + rules: + creation: false + update: false + deletion: false + pull_request: + required_approving_review_count: 0 + required_linear_history: true + required_signatures: true repositories: - name: .github # Repository metadata