diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3de522e..6fdce56 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,10 +18,10 @@ jobs: name: Static Analysis steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Run pre-commit - run: make test/docker/pre-commit + uses: docker://ghcr.io/antonbabenko/pre-commit-terraform:latest unit-tests: needs: pre-commit @@ -29,7 +29,7 @@ jobs: name: Unit Tests steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Check for Terraform file changes uses: getsentry/paths-filter@v2 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6561e23..d9e4dd2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/mineiros-io/pre-commit-hooks - rev: v0.4.1 + rev: v0.5.1 hooks: - id: terraform-fmt - id: terraform-validate diff --git a/examples/public-repository/README.md b/examples/public-repository/README.md index 6014f5a..48d0893 100644 --- a/examples/public-repository/README.md +++ b/examples/public-repository/README.md @@ -62,7 +62,7 @@ module "repository" { required_status_checks = { strict = true - contexts = ["ci/travis"] + checks = ["ci/travis"] } required_pull_request_reviews = { diff --git a/examples/public-repository/main.tf b/examples/public-repository/main.tf index e48dec7..c1ecb2f 100644 --- a/examples/public-repository/main.tf +++ b/examples/public-repository/main.tf @@ -6,8 +6,7 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ module "repository" { - source = "mineiros-io/repository/github" - version = "~> 0.13.0" + source = "../.." module_depends_on = [ module.team @@ -24,7 +23,6 @@ module "repository" { allow_rebase_merge = false allow_squash_merge = false allow_auto_merge = true - has_downloads = false auto_init = true gitignore_template = "Terraform" license_template = "mit" @@ -47,16 +45,15 @@ module "repository" { admin_collaborators = ["terraform-test-user-1"] - branch_protections = [ - { - branch = "main" + branch_protections = { + "main" = { enforce_admins = true require_conversation_resolution = true require_signed_commits = true required_status_checks = { - strict = true - contexts = ["ci/travis"] + strict = true + checks = ["ci/travis"] } required_pull_request_reviews = { @@ -70,7 +67,7 @@ module "repository" { teams = [module.team.name] } } - ] + } } # --------------------------------------------------------------------------------------------------------------------- @@ -78,8 +75,7 @@ module "repository" { # --------------------------------------------------------------------------------------------------------------------- module "team" { - source = "mineiros-io/team/github" - version = "~> 0.8.0" + source = "github.com/kevcube/terraform-github-team?ref=a0b2c37" name = "DevOps" description = "The DevOps Team" diff --git a/examples/public-repository/provider.tf b/examples/public-repository/provider.tf index b55f252..6f80645 100644 --- a/examples/public-repository/provider.tf +++ b/examples/public-repository/provider.tf @@ -1,12 +1,12 @@ provider "github" {} terraform { - required_version = "~> 1.0" + required_version = "~> 1.7" required_providers { github = { source = "integrations/github" - version = "~> 4.0" + version = "~> 6" } } } diff --git a/main.tf b/main.tf index 587e1bb..d81f9c8 100644 --- a/main.tf +++ b/main.tf @@ -3,86 +3,59 @@ # This module creates a GitHub repository with opinionated default settings. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Set some opinionated default settings through var.defaults and locals locals { - homepage_url = var.homepage_url == null ? lookup(var.defaults, "homepage_url", "") : var.homepage_url - private = var.private == null ? lookup(var.defaults, "private", true) : var.private - private_visibility = local.private ? "private" : "public" - visibility = var.visibility == null ? lookup(var.defaults, "visibility", local.private_visibility) : var.visibility - has_issues = var.has_issues == null ? lookup(var.defaults, "has_issues", false) : var.has_issues - has_projects = var.has_projects == null ? lookup(var.defaults, "has_projects", false) : length(var.projects) > 0 ? true : var.has_projects - has_wiki = var.has_wiki == null ? lookup(var.defaults, "has_wiki", false) : var.has_wiki - allow_merge_commit = var.allow_merge_commit == null ? lookup(var.defaults, "allow_merge_commit", true) : var.allow_merge_commit - allow_rebase_merge = var.allow_rebase_merge == null ? lookup(var.defaults, "allow_rebase_merge", false) : var.allow_rebase_merge - allow_squash_merge = var.allow_squash_merge == null ? lookup(var.defaults, "allow_squash_merge", false) : var.allow_squash_merge - allow_auto_merge = var.allow_auto_merge == null ? lookup(var.defaults, "allow_auto_merge", false) : var.allow_auto_merge - delete_branch_on_merge = var.delete_branch_on_merge == null ? lookup(var.defaults, "delete_branch_on_merge", true) : var.delete_branch_on_merge - is_template = var.is_template == null ? lookup(var.defaults, "is_template", false) : var.is_template - has_downloads = var.has_downloads == null ? lookup(var.defaults, "has_downloads", false) : var.has_downloads - auto_init = var.auto_init == null ? lookup(var.defaults, "auto_init", true) : var.auto_init - gitignore_template = var.gitignore_template == null ? lookup(var.defaults, "gitignore_template", "") : var.gitignore_template - license_template = var.license_template == null ? lookup(var.defaults, "license_template", "") : var.license_template - default_branch = var.default_branch == null ? lookup(var.defaults, "default_branch", null) : var.default_branch - standard_topics = var.topics == null ? lookup(var.defaults, "topics", []) : var.topics - topics = concat(local.standard_topics, var.extra_topics) - template = var.template == null ? [] : [var.template] - issue_labels_create = var.issue_labels_create == null ? lookup(var.defaults, "issue_labels_create", local.issue_labels_create_computed) : var.issue_labels_create - - issue_labels_create_computed = local.has_issues || length(var.issue_labels) > 0 - # for readability - var_gh_labels = var.issue_labels_merge_with_github_labels - gh_labels = local.var_gh_labels == null ? lookup(var.defaults, "issue_labels_merge_with_github_labels", true) : local.var_gh_labels + # var_gh_labels = var.issue_labels_merge_with_github_labels - issue_labels_merge_with_github_labels = local.gh_labels + # issue_labels_merge_with_github_labels = var.gh_labels # Per default, GitHub activates vulnerability alerts for public repositories and disables it for private repositories - vulnerability_alerts = var.vulnerability_alerts != null ? var.vulnerability_alerts : local.private ? false : true + vulnerability_alerts = coalesce(var.vulnerability_alerts, var.visibility == "public" ? true : false) } -locals { - branch_protections_v3 = [ - for b in var.branch_protections_v3 : merge({ - branch = null - enforce_admins = null - require_conversation_resolution = null - require_signed_commits = null - required_status_checks = {} - required_pull_request_reviews = {} - restrictions = {} - }, b) - ] - - required_status_checks = [ - for b in local.branch_protections_v3 : - length(keys(b.required_status_checks)) > 0 ? [ - merge({ - strict = null - contexts = [] - }, b.required_status_checks)] : [] - ] - - required_pull_request_reviews = [ - for b in local.branch_protections_v3 : - length(keys(b.required_pull_request_reviews)) > 0 ? [ - merge({ - dismiss_stale_reviews = true - dismissal_users = [] - dismissal_teams = [] - require_code_owner_reviews = null - required_approving_review_count = null - }, b.required_pull_request_reviews)] : [] - ] - - restrictions = [ - for b in local.branch_protections_v3 : - length(keys(b.restrictions)) > 0 ? [ - merge({ - users = [] - teams = [] - apps = [] - }, b.restrictions)] : [] - ] -} +# locals { +# branch_protections_v3 = [ +# for b in var.branch_protections_v3 : merge({ +# branch = null +# enforce_admins = null +# require_conversation_resolution = null +# require_signed_commits = null +# required_status_checks = {} +# required_pull_request_reviews = {} +# restrictions = {} +# }, b) +# ] + +# required_status_checks = [ +# for b in local.branch_protections_v3 : +# length(keys(b.required_status_checks)) > 0 ? [ +# merge({ +# strict = null +# checks = [] +# }, b.required_status_checks)] : [] +# ] + +# required_pull_request_reviews = [ +# for b in local.branch_protections_v3 : +# length(keys(b.required_pull_request_reviews)) > 0 ? [ +# merge({ +# dismiss_stale_reviews = true +# dismissal_users = [] +# dismissal_teams = [] +# require_code_owner_reviews = null +# required_approving_review_count = null +# }, b.required_pull_request_reviews)] : [] +# ] + +# restrictions = [ +# for b in local.branch_protections_v3 : +# length(keys(b.restrictions)) > 0 ? [ +# merge({ +# users = [] +# teams = [] +# apps = [] +# }, b.restrictions)] : [] +# ] +# } # --------------------------------------------------------------------------------------------------------------------- # Create the repository @@ -91,33 +64,39 @@ locals { resource "github_repository" "repository" { name = var.name description = var.description - homepage_url = local.homepage_url - visibility = local.visibility - has_issues = local.has_issues - has_projects = local.has_projects - has_wiki = local.has_wiki - allow_merge_commit = local.allow_merge_commit - allow_rebase_merge = local.allow_rebase_merge - allow_squash_merge = local.allow_squash_merge - allow_auto_merge = local.allow_auto_merge - delete_branch_on_merge = local.delete_branch_on_merge - is_template = local.is_template - has_downloads = local.has_downloads - auto_init = local.auto_init - gitignore_template = local.gitignore_template - license_template = local.license_template + homepage_url = var.homepage_url + visibility = var.visibility + has_issues = var.has_issues + has_projects = var.has_projects + has_wiki = var.has_wiki + allow_merge_commit = var.allow_merge_commit + allow_rebase_merge = var.allow_rebase_merge + allow_squash_merge = var.allow_squash_merge + allow_auto_merge = var.allow_auto_merge + delete_branch_on_merge = var.delete_branch_on_merge + is_template = var.is_template + auto_init = var.auto_init + gitignore_template = var.gitignore_template + license_template = var.license_template archived = var.archived - topics = local.topics + topics = var.topics + + merge_commit_message = var.merge_commit_message + merge_commit_title = var.merge_commit_title + + squash_merge_commit_message = var.squash_merge_commit_message + squash_merge_commit_title = var.squash_merge_commit_title archive_on_destroy = var.archive_on_destroy vulnerability_alerts = local.vulnerability_alerts dynamic "template" { - for_each = local.template + for_each = var.template != null ? [true] : [] content { - owner = template.value.owner - repository = template.value.repository + owner = var.template.value.owner + repository = var.template.value.repository + include_all_branches = var.template.value.include_all_branches } } @@ -148,17 +127,13 @@ resource "github_repository" "repository" { # https://registry.terraform.io/providers/integrations/github/latest/docs/resources/branch # --------------------------------------------------------------------------------------------------------------------- -locals { - branches_map = { for b in var.branches : b.name => b } -} - resource "github_branch" "branch" { - for_each = local.branches_map + for_each = var.branches repository = github_repository.repository.name branch = each.key - source_branch = try(each.value.source_branch, null) - source_sha = try(each.value.source_sha, null) + source_branch = each.value.source_branch + source_sha = each.value.source_sha } # --------------------------------------------------------------------------------------------------------------------- @@ -167,25 +142,20 @@ resource "github_branch" "branch" { # --------------------------------------------------------------------------------------------------------------------- resource "github_branch_default" "default" { - count = local.default_branch != null ? 1 : 0 + count = var.default_branch != null ? 1 : 0 repository = github_repository.repository.name - branch = local.default_branch - - depends_on = [github_branch.branch] + branch = var.default_branch } # --------------------------------------------------------------------------------------------------------------------- -# v4 Branch Protection +# Branch Protection # https://registry.terraform.io/providers/integrations/github/latest/docs/resources/branch_protection # --------------------------------------------------------------------------------------------------------------------- -locals { - branch_protections_v4_map = { for idx, e in var.branch_protections_v4 : try(e._key, e.pattern) => idx } -} - resource "github_branch_protection" "branch_protection" { - for_each = local.branch_protections_v4_map + #checkov:skip=CKV_GIT_6:Signed commits are not required + for_each = var.branch_protections # ensure we have all members and collaborators added before applying # any configuration for them @@ -198,93 +168,49 @@ resource "github_branch_protection" "branch_protection" { repository_id = github_repository.repository.node_id - pattern = var.branch_protections_v4[each.value].pattern - - allows_deletions = try(var.branch_protections_v4[each.value].allows_deletions, false) - allows_force_pushes = try(var.branch_protections_v4[each.value].allows_force_pushes, false) - blocks_creations = try(var.branch_protections_v4[each.value].blocks_creations, false) - enforce_admins = try(var.branch_protections_v4[each.value].enforce_admins, true) - push_restrictions = try(var.branch_protections_v4[each.value].push_restrictions, []) - require_conversation_resolution = try(var.branch_protections_v4[each.value].require_conversation_resolution, false) - require_signed_commits = try(var.branch_protections_v4[each.value].require_signed_commits, false) - required_linear_history = try(var.branch_protections_v4[each.value].required_linear_history, false) + pattern = each.key - dynamic "required_pull_request_reviews" { - for_each = try([var.branch_protections_v4[each.value].required_pull_request_reviews], []) - - content { - dismiss_stale_reviews = try(required_pull_request_reviews.value.dismiss_stale_reviews, true) - restrict_dismissals = try(required_pull_request_reviews.value.restrict_dismissals, null) - dismissal_restrictions = try(required_pull_request_reviews.value.dismissal_restrictions, []) - pull_request_bypassers = try(required_pull_request_reviews.value.pull_request_bypassers, []) - require_code_owner_reviews = try(required_pull_request_reviews.value.require_code_owner_reviews, true) - required_approving_review_count = try(required_pull_request_reviews.value.required_approving_review_count, 0) - } - } + enforce_admins = each.value.enforce_admins + require_signed_commits = each.value.require_signed_commits + required_linear_history = each.value.required_linear_history + require_conversation_resolution = each.value.require_conversation_resolution dynamic "required_status_checks" { - for_each = try([var.branch_protections_v4[each.value].required_status_checks], []) + for_each = try([each.value.required_status_checks], []) content { - strict = try(required_status_checks.value.strict, false) - contexts = try(required_status_checks.value.contexts, []) - } - } -} - -# --------------------------------------------------------------------------------------------------------------------- -# v3 Branch Protection -# https://registry.terraform.io/providers/integrations/github/latest/docs/resources/branch_protection_v3 -# --------------------------------------------------------------------------------------------------------------------- - -resource "github_branch_protection_v3" "branch_protection" { - count = length(local.branch_protections_v3) - - # ensure we have all members and collaborators added before applying - # any configuration for them - depends_on = [ - github_repository_collaborator.collaborator, - github_team_repository.team_repository, - github_team_repository.team_repository_by_slug, - github_branch.branch, - ] - - repository = github_repository.repository.name - branch = local.branch_protections_v3[count.index].branch - enforce_admins = local.branch_protections_v3[count.index].enforce_admins - require_conversation_resolution = local.branch_protections_v3[count.index].require_conversation_resolution - require_signed_commits = local.branch_protections_v3[count.index].require_signed_commits - - dynamic "required_status_checks" { - for_each = local.required_status_checks[count.index] - - content { - strict = required_status_checks.value.strict - contexts = required_status_checks.value.contexts + strict = required_status_checks.strict + contexts = required_status_checks.contexts } } dynamic "required_pull_request_reviews" { - for_each = local.required_pull_request_reviews[count.index] + for_each = try([each.value.required_pull_request_reviews], []) content { dismiss_stale_reviews = required_pull_request_reviews.value.dismiss_stale_reviews - dismissal_users = required_pull_request_reviews.value.dismissal_users - dismissal_teams = [for t in required_pull_request_reviews.value.dismissal_teams : replace(lower(t), "/[^a-z0-9_]/", "-")] + restrict_dismissals = required_pull_request_reviews.value.restrict_dismissals + dismissal_restrictions = required_pull_request_reviews.value.dismissal_restrictions + pull_request_bypassers = required_pull_request_reviews.value.pull_request_bypassers require_code_owner_reviews = required_pull_request_reviews.value.require_code_owner_reviews required_approving_review_count = required_pull_request_reviews.value.required_approving_review_count + require_last_push_approval = required_pull_request_reviews.value.require_last_push_approval } } - dynamic "restrictions" { - for_each = local.restrictions[count.index] + dynamic "restrict_pushes" { + for_each = try([each.value.restrict_pushes], []) content { - users = restrictions.value.users - teams = [for t in restrictions.value.teams : replace(lower(t), "/[^a-z0-9_]/", "-")] - apps = restrictions.value.apps + blocks_creations = restrict_pushes.blocks_creations + push_allowances = restrict_pushes.push_allowances } } + + force_push_bypassers = each.value.force_push_bypassers + allows_deletions = each.value.allows_deletions + allows_force_pushes = each.value.allows_force_pushes + lock_branch = each.value.lock_branch } # --------------------------------------------------------------------------------------------------------------------- @@ -296,7 +222,7 @@ locals { # all deployed repositories. # add labels if new labels in github are added by default. # this is the set of labels and colors as of 2020-02-02 - github_default_issue_labels = local.issue_labels_merge_with_github_labels ? [ + github_default_issue_labels = var.issue_labels_merge_with_github_labels ? [ { name = "bug" description = "Something isn't working" @@ -354,7 +280,7 @@ locals { } resource "github_issue_label" "label" { - for_each = local.issue_labels_create ? local.issue_labels : {} + for_each = var.issue_labels_create ? local.issue_labels : {} repository = github_repository.repository.name name = each.value.name diff --git a/secrets.tf b/secrets.tf index f8f494f..f9ca765 100644 --- a/secrets.tf +++ b/secrets.tf @@ -2,18 +2,18 @@ # Action Secrets # --------------------------------------------------------------------------------------------------------------------- -locals { - plaintext_secrets = { for name, value in var.plaintext_secrets : name => { plaintext = value } } - encrypted_secrets = { for name, value in var.encrypted_secrets : name => { encrypted = value } } +resource "github_actions_secret" "plaintext_repository_secret" { + for_each = var.plaintext_secrets - secrets = merge(local.plaintext_secrets, local.encrypted_secrets) + repository = github_repository.repository.name + secret_name = each.key + plaintext_value = each.value } resource "github_actions_secret" "repository_secret" { - for_each = local.secrets + for_each = var.encrypted_secrets repository = github_repository.repository.name secret_name = each.key - plaintext_value = try(each.value.plaintext, null) - encrypted_value = try(each.value.encrypted, null) + encrypted_value = each.value.encrypted } diff --git a/test/unit-complete/main.tf b/test/unit-complete/main.tf index f307097..164fd55 100644 --- a/test/unit-complete/main.tf +++ b/test/unit-complete/main.tf @@ -32,7 +32,7 @@ module "repository" { name = var.name description = var.description homepage_url = var.url - private = false + visibility = "public" has_issues = var.has_issues has_projects = var.has_projects has_wiki = var.has_wiki @@ -42,23 +42,19 @@ module "repository" { allow_auto_merge = var.allow_auto_merge delete_branch_on_merge = var.delete_branch_on_merge is_template = var.is_template - has_downloads = var.has_downloads auto_init = var.auto_init gitignore_template = var.gitignore_template license_template = var.license_template archived = false topics = var.topics + archive_on_destroy = false - branches = [ - { - name = "develop" - }, - { - name = "staging" - }, - ] + branches = { + develop = {}, + staging = {}, + } - admin_collaborators = ["terraform-test-user-1"] + admin_collaborators = ["kevcube"] admin_team_ids = [ github_team.team.id @@ -86,9 +82,8 @@ module "repository" { secret = var.webhook_secret }] - branch_protections_v4 = [ - { - pattern = "staging" + branch_protections = { + staging = { allows_deletions = false allows_force_pushes = false @@ -108,39 +103,7 @@ module "repository" { strict = true } } - ] - - branch_protections_v3 = [ - { - branch = "main" - enforce_admins = true - require_conversation_resolution = true - require_signed_commits = true - - required_status_checks = { - strict = true - contexts = ["ci/travis"] - } - - required_pull_request_reviews = { - dismiss_stale_reviews = true - dismissal_users = [var.team_user] - dismissal_teams = [github_team.team.name] - require_code_owner_reviews = true - required_approving_review_count = 1 - } - - restrictions = { - users = [var.team_user] - teams = [github_team.team.name] - } - }, - { - branch = "develop" - enforce_admins = true - require_signed_commits = true - } - ] + } issue_labels = var.issue_labels @@ -169,14 +132,12 @@ module "repository" { module "repository-with-defaults" { source = "../.." - name = var.repository_with_defaults_name - description = var.repository_with_defaults_description - defaults = var.repository_defaults - default_branch = "development" + name = var.repository_with_defaults_name + description = var.repository_with_defaults_description + default_branch = "development" + archive_on_destroy = false - branches = [ - { name = "development" }, - ] + branches = { development = {} } } # --------------------------------------------------------------------------------------------------------------------- diff --git a/test/unit-complete/provider.tf b/test/unit-complete/provider.tf index e80c4cc..b95beaa 100644 --- a/test/unit-complete/provider.tf +++ b/test/unit-complete/provider.tf @@ -7,11 +7,11 @@ terraform { github = { source = "integrations/github" # mask providers with broken branch protection v3 imlementation - version = "~> 5.0, !=5.3.0, !=5.4.0, !=5.5.0, !=5.6.0, !=5.7.0" + version = "~> 6" } tls = { source = "hashicorp/tls" - version = "~> 2.1" + version = "~> 4" } } } diff --git a/test/unit-complete/variables.tf b/test/unit-complete/variables.tf index 55b155f..98aa630 100644 --- a/test/unit-complete/variables.tf +++ b/test/unit-complete/variables.tf @@ -146,7 +146,7 @@ variable "team_description" { variable "team_user" { description = "The user that should be added to the created team." type = string - default = "terraform-test-user" + default = "kevcube" } variable "repository_defaults" { diff --git a/variables.tf b/variables.tf index 7599034..d4ce400 100644 --- a/variables.tf +++ b/variables.tf @@ -15,25 +15,17 @@ variable "name" { variable "branches" { description = "(Optional) A list of branches to be created in this repository." - type = any - # type = list(object({ - # name = string - # source_branch = optional(string) - # source_sha = optional(string) - # })) - default = [] -} - -variable "defaults" { - description = "(Deprecated) DEPRECATED. Please convert defaults to Terraform Module for_each" - type = any - default = {} + type = map(object({ + source_branch = optional(string) + source_sha = optional(string) + })) + default = {} } variable "description" { description = "(Optional) A description of the repository." type = string - default = "" + default = null } variable "homepage_url" { @@ -42,14 +34,8 @@ variable "homepage_url" { default = null } -variable "private" { - description = "(Optional) (DEPRECATED: use visibility)" - type = bool - default = null -} - variable "visibility" { - description = "(Optional) Can be 'public', 'private' or 'internal' (GHE only).The visibility parameter overrides the private parameter. Defaults to 'private' if neither private nor visibility are set, default to state of private parameter if it is set." + description = "(Optional) Can be 'public', 'private' or 'internal' (GHE only). The visibility parameter overrides the private parameter. Defaults to 'private' if neither private nor visibility are set, default to state of private parameter if it is set." type = string default = null } @@ -102,12 +88,6 @@ variable "delete_branch_on_merge" { default = null } -variable "has_downloads" { - description = "(Optional) Set to true to enable the (deprecated) downloads features on the repository. (Default: false)" - type = bool - default = null -} - variable "auto_init" { description = "(Optional) Wether or not to produce an initial commit in the repository. (Default: true)" type = bool @@ -116,12 +96,15 @@ variable "auto_init" { variable "pages" { description = "(Optional) The repository's GitHub Pages configuration. (Default: {})" - # type = object({ - # branch = string - # path = string - # cname = string - # }) - type = any + type = object({ + source = optional(object({ + branch = string + path = optional(string) + }), null) + build_type = optional(string) # Can be `legacy` or `workflow` + cname = optional(string) # Can only be set after repository is created + }) + default = null } @@ -144,7 +127,7 @@ variable "license_template" { } variable "default_branch" { - description = "(Optional) The name of the default branch of the repository. NOTE: This can only be set after a repository has already been created, and after a correct reference has been created for the target branch inside the repository. This means a user will have to omit this parameter from the initial repository creation and create the target branch inside of the repository prior to setting this attribute." + description = "(Optional) The name of the default branch of the repository." type = string default = null } @@ -161,6 +144,30 @@ variable "topics" { default = null } +variable "merge_commit_title" { + description = "Can be PR_TITLE or MERGE_MESSAGE for a default merge commit title. Applicable only if allow_merge_commit is true." + type = string + default = null +} + +variable "merge_commit_message" { + description = "Can be PR_BODY, PR_TITLE, or BLANK for a default merge commit message. Applicable only if allow_merge_commit is true." + type = string + default = null +} + +variable "squash_merge_commit_title" { + description = "(Optional) Can be PR_TITLE or COMMIT_OR_PR_TITLE for a default squash merge commit title. Applicable only if allow_squash_merge is true." + type = string + default = null +} + +variable "squash_merge_commit_message" { + description = "(Optional) Can be PR_BODY, COMMIT_MESSAGES, or BLANK for a default squash merge commit message. Applicable only if allow_squash_merge is true." + type = string + default = null +} + variable "extra_topics" { description = "(Optional) The list of additional topics of the repository. (Default: [])" type = list(string) @@ -170,8 +177,9 @@ variable "extra_topics" { variable "template" { description = "(Optional) Template repository to use. (Default: {})" type = object({ - owner = string - repository = string + owner = string + repository = string + include_all_branches = optional(bool, false) }) default = null } @@ -266,110 +274,58 @@ variable "maintain_teams" { default = [] } -variable "branch_protections_v3" { - description = "(Optional) A list of branch protections to apply to the repository. Default is [] unless branch_protections is set." - type = any - - # We can't use a detailed type specification due to a terraform limitation. However, this might be changed in a future - # Terraform version. See https://github.com/hashicorp/terraform/issues/19898 and https://github.com/hashicorp/terraform/issues/22449 - # - # type = list(object({ - # branch = string - # enforce_admins = bool - # require_signed_commits = bool - # required_status_checks = object({ - # strict = bool - # contexts = list(string) - # }) - # required_pull_request_reviews = object({ - # dismiss_stale_reviews = bool - # dismissal_users = list(string) - # dismissal_teams = list(string) - # require_code_owner_reviews = bool - # required_approving_review_count = number - # }) - # restrictions = object({ - # users = list(string) - # teams = list(string) - # }) - # })) - - default = [] - - # Example: - # branch_protections = [ - # { - # branch = "main" - # enforce_admins = true - # require_signed_commits = true - # - # required_status_checks = { - # strict = false - # contexts = ["ci/travis"] - # } - # - # required_pull_request_reviews = { - # dismiss_stale_reviews = true - # dismissal_users = ["user1", "user2"] - # dismissal_teams = ["team-slug-1", "team-slug-2"] - # require_code_owner_reviews = true - # required_approving_review_count = 1 - # } - # - # restrictions = { - # users = ["user1"] - # teams = ["team-slug-1"] - # } - # } - # ] -} - -variable "branch_protections_v4" { - description = "(Optional) A list of v4 branch protections to apply to the repository. Default is []." - type = any - # type = list( - # object( - # { - # pattern = string - # allows_deletions = optional(bool, false) - # allows_force_pushes = optional(bool, false) - # blocks_creations = optional(bool, false) - # enforce_admins = optional(bool, false) - # push_restrictions = optional(list(string), []) - # require_conversation_resolution = optional(bool, false) - # require_signed_commits = optional(bool, false) - # required_linear_history = optional(bool, false) - # required_pull_request_reviews = optional(object( - # { - # dismiss_stale_reviews = optional(bool, false) - # dismissal_restrictions = optional(list(string), []) - # pull_request_bypassers = optional(list(string), []) - # require_code_owner_reviews = optional(bool, false) - # required_approving_review_count = optional(number, 0) - # } - # )) - # required_status_checks = optional(object( - # { - # strict = optional(bool, false) - # contexts = optional(list(string), []) - # } - # )) - # } - # ) - # ) - default = [] +variable "branch_protections" { + description = "(Optional) A list of v4 branch protections to apply to the repository. A map of `pattern` to branch protection config." + type = map( + object( + { + enforce_admins = optional(bool, false) + require_signed_commits = optional(bool, false) + required_linear_history = optional(bool, false) + require_conversation_resolution = optional(bool, false) + required_status_checks = optional(object( + { + strict = optional(bool) + contexts = optional(list(string)) + } + )) + required_pull_request_reviews = optional(object( + { + dismiss_stale_reviews = optional(bool) + restrict_dismissals = optional(bool) + dismissal_restrictions = optional(list(string)) + pull_request_bypassers = optional(list(string)) + require_code_owner_reviews = optional(bool) + required_approving_review_count = optional(number) + require_last_push_approval = optional(bool) + } + )) + restrict_pushes = optional(object( + { + blocks_creations = optional(bool) + push_allowances = optional(list(string)) + } + )) + force_push_bypassers = optional(list(string)) + allows_deletions = optional(bool, false) + allows_force_pushes = optional(bool, false) + lock_branch = optional(bool, false) + } + ) + ) + default = {} validation { condition = alltrue( [ - for cfg in var.branch_protections_v4 : try( + for cfg in var.branch_protections : try( cfg.required_pull_request_reviews.required_approving_review_count >= 0 && cfg.required_pull_request_reviews.required_approving_review_count <= 6, true ) ] ) - error_message = "The value for branch_protections_v4.required_pull_request_reviews.required_approving_review_count must be between 0 and 6, inclusively." + error_message = "The value for branch_protections.required_pull_request_reviews.required_approving_review_count must be between 0 and 6, inclusively." } } diff --git a/versions.tf b/versions.tf index 01e52ac..5fd52fb 100644 --- a/versions.tf +++ b/versions.tf @@ -3,13 +3,13 @@ # --------------------------------------------------------------------------------------------------------------------- terraform { - required_version = "~> 1.0" + required_version = "~> 1.7" # branch_protections_v3 are broken in >= 5.3 required_providers { github = { source = "integrations/github" - version = ">= 4.20, < 6.0" + version = "~> 6" } } }