Expected Behavior
I commented out the whole the content of the terraform file and expected the repo to be completely deleted. I also tried terraform destroy and got the same error
Actual Behavior
I got the error
│ Error: error deleting GitHub branch reference exnihilo-studio/test_terraform_repo (refs/heads/main): DELETE https://api.github.com/repos/exnihilo-studio/test_terraform_repo/git/refs/heads/main: 422 Cannot delete the default branch []
Terraform Version
Terraform v1.14.8
on darwin_arm64
+ provider registry.terraform.io/integrations/github v6.11.1
Affected Resource(s)
Terraform Configuration Files
variable "repo_name" {
description = "The name of the GitHub repository"
type = string
}
variable "github_repo_visibility" {
description = "The visibility of the GitHub repository (e.g. public, private, internal)"
type = string
default = "private"
validation {
condition = contains(["public", "private", "internal"], var.github_repo_visibility)
error_message = "GitHub repository visibility must be either 'public', 'private', or 'internal'"
}
}
variable "environment_name" {
description = "The name of the environment (e.g. dev, prod)"
type = string
}
variable "github_organization" {
description = "The name of the GitHub organization to create the repository in"
type = string
}
variable "description" {
description = "A short description of the repository"
type = string
default = ""
}
variable "default_branch" {
description = "Name of the default (main) branch"
type = string
default = "main"
}
variable "token_rotation_branch" {
description = "Name of the branch used for token rotation"
type = string
default = "token-rotation"
}
variable "default_branch_files" {
description = <<-EOT
Map of files to commit to the default branch.
Key is the file path within the repository (e.g. "README.md").
Each object has:
- content : the file contents as a string
- overwrite_on_create: whether to overwrite if the file already exists
EOT
type = map(object({
content = string
overwrite_on_create = optional(bool, true)
}))
default = {}
}
variable "token_rotation_branch_files" {
description = <<-EOT
Map of files to commit to the toke rotation branch.
Key is the file path within the repository (e.g. "README.md").
Each object has:
- content : the file contents as a string
- overwrite_on_create: whether to overwrite if the file already exists
EOT
type = map(object({
content = string
overwrite_on_create = optional(bool, true)
}))
default = {}
}
variable "environments" {
description = "List of GitHub Actions environment names to create (e.g. [\"dev\", \"prod\"])"
type = list(string)
default = ["dev", "prod"]
}
variable "environment_secrets" {
description = <<-EOT
Secrets to create per environment.
Outer key is the environment name, inner key is the secret name, value is the plaintext secret value.
Values are marked sensitive.
EOT
type = list(map(string))
default = []
sensitive = true
}
variable "environment_variables" {
description = <<-EOT
Variables to create per environment.
Outer key is the environment name, inner key is the variable name, value is the variable value.
EOT
type = list(map(string))
default = []
}
variable "maintainer_team_slug" {
description = "Slug of the GitHub team to grant maintain permission on the repository"
type = string
}
variable "required_approving_review_count" {
description = "Number of required approving reviews before a PR can be merged into the default branch"
type = number
default = 1
}
resource "github_repository" "this" {
count = var.environment_name == "dev" ? 1 : 0
name = var.repo_name
description = var.description
visibility = var.github_repo_visibility
has_discussions = true
allow_merge_commit = false
allow_squash_merge = true
allow_rebase_merge = false
allow_auto_merge = true
delete_branch_on_merge = true
# Initialise with an empty commit so branches can be created immediately
auto_init = true
}
data "github_repository" "this_data" {
count = var.environment_name == "dev" ? 0 : 1
full_name = "${var.github_organization}/${var.repo_name}"
}
resource "github_branch" "default" {
count = var.environment_name == "dev" ? 1 : 0
repository = github_repository.this[0].name
branch = "main"
depends_on = [github_repository.this]
}
resource "github_branch_default" "this" {
count = var.environment_name == "dev" ? 1 : 0
repository = github_repository.this[0].name
branch = github_branch.default[0].branch
}
resource "github_branch" "token_rotation" {
count = var.environment_name == "dev" ? 1 : 0
repository = github_repository.this[0].name
branch = var.token_rotation_branch
source_branch = github_branch_default.this[0].branch
}
# ─── Commit files to the default branch ──────────────────────────────────────
resource "github_repository_file" "commit_default_branch_files" {
for_each = var.default_branch_files
repository = github_repository.this[0].name
branch = github_branch_default.this[0].branch
file = each.key
content = each.value.content
overwrite_on_create = each.value.overwrite_on_create
commit_message = "chore: add ${each.key} via Terraform"
commit_author = "Terraform"
commit_email = "[email protected]"
depends_on = [github_branch_default.this]
}
resource "github_repository_file" "commit_token_rotation_branch_files" {
for_each = var.token_rotation_branch_files
repository = github_repository.this[0].name
branch = github_branch.token_rotation[0].branch
file = each.key
content = each.value.content
overwrite_on_create = each.value.overwrite_on_create
commit_message = "chore: add ${each.key} via Terraform"
commit_author = "Terraform"
commit_email = "[email protected]"
depends_on = [github_branch_default.this]
}
# ─── Branch protection (main: PRs only, no direct push) ──────────────────────
resource "github_branch_protection" "main" {
count = var.environment_name == "dev" ? 1 : 0
repository_id = github_repository.this[0].node_id
pattern = github_branch_default.this[0].branch
enforce_admins = true
allows_deletions = false
allows_force_pushes = false
require_signed_commits = false
required_pull_request_reviews {
dismiss_stale_reviews = true
require_code_owner_reviews = false
required_approving_review_count = var.required_approving_review_count
}
# Branch protection must be applied after files are committed so the branch exists
depends_on = [github_repository_file.commit_default_branch_files]
}
# ─── Environments ─────────────────────────────────────────────────────────────
resource "github_repository_environment" "envs" {
for_each = toset(var.environments)
repository = github_repository.this[0].name
environment = each.key
}
# ─── Environment secrets ──────────────────────────────────────────────────────
resource "github_actions_environment_secret" "secrets" {
count = length(var.environment_secrets)
repository = var.environment_name == "dev" ? github_repository.this[0].name : data.github_repository.this_data[0]
environment = var.environment_secrets[count.index].environment
secret_name = var.environment_secrets[count.index].name
plaintext_value = var.environment_secrets[count.index].value
depends_on = [github_repository_environment.envs]
}
# ─── Environment variables ────────────────────────────────────────────────────
resource "github_actions_environment_variable" "variables" {
count = length(var.environment_variables)
repository = var.environment_name == "dev" ? github_repository.this[0].name : data.github_repository.this_data[0]
environment = var.environment_variables[count.index].environment
variable_name = var.environment_variables[count.index].name
value = var.environment_variables[count.index].value
depends_on = [github_repository_environment.envs]
}
# ─── Team maintainers ─────────────────────────────────────────────────────────¬
resource "github_team_repository" "maintainers" {
count = var.environment_name == "dev" ? 1 : 0
team_id = var.maintainer_team_slug
repository = github_repository.this[0].name
permission = "maintain"
}
Steps to Reproduce
The above Terraform configuration file is stored as a module and I have this file that uses the module
module "github_repo" {
source = "../../genesis-api/genesis_api/terraform_modules/github"
environment_name = "dev"
github_repo_visibility = "public"
github_organization = "exnihilo-studio"
repo_name = "test_terraform_repo"
description = "Repository to test terraform delete"
default_branch_files = {
"README.md" = {
content = "This is a test repository."
overwrite_on_create = true
}
}
token_rotation_branch_files = {
"README.md" = {
content = "README file for the token rotation branch."
overwrite_on_create = true
}
}
environments = ["dev", "prod"]
environment_variables = [
{
"environment" = "dev",
"name" = "GCP_PROJECT_ID",
"value" = "some_value"
}
]
environment_secrets = []
maintainer_team_slug = "exnihilo-team"
}
- I run
terraform apply -auto-approve to create the repo
- I comment out the above content and run
terraform apply -auto-approve to delete the repo
- I also tried
terraform destroy and got the same error
This is the plan for the terraform destroy which I run after the 2nd step
❯ terraform destroy
module.github_repo.github_repository.this[0]: Refreshing state... [id=test_terraform_repo]
module.github_repo.github_branch.default[0]: Refreshing state... [id=test_terraform_repo:main]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
- destroy
Terraform will perform the following actions:
# module.github_repo.github_branch.default[0] will be destroyed
- resource "github_branch" "default" {
- branch = "main" -> null
- etag = "W/\"44a566205da62dd406e48103fbd646d9d09c520c061b9fa8ba566ef5b4a9b80f\"" -> null
- id = "test_terraform_repo:main" -> null
- ref = "refs/heads/main" -> null
- repository = "test_terraform_repo" -> null
- sha = "c22aa321a8fe5f9870cd6f6566c8073fe1c7d69a" -> null
- source_branch = "main" -> null
- source_sha = "a6ff23273f150f4b44ed5ca67a06d91f2c356bb1" -> null
}
# module.github_repo.github_repository.this[0] will be destroyed
- resource "github_repository" "this" {
- allow_auto_merge = true -> null
- allow_forking = true -> null
- allow_merge_commit = false -> null
- allow_rebase_merge = false -> null
- allow_squash_merge = true -> null
- allow_update_branch = false -> null
- archived = false -> null
- auto_init = true -> null
- default_branch = "main" -> null
- delete_branch_on_merge = true -> null
- description = "Repository to test terraform delete" -> null
- etag = "W/\"bd5bd280d5410275f45f32bf7ca749851807e6b52741e3c625ee66c2b7740a7b\"" -> null
- fork = "false" -> null
- full_name = "exnihilo-studio/test_terraform_repo" -> null
- git_clone_url = "git://github.com/exnihilo-studio/test_terraform_repo.git" -> null
- has_discussions = true -> null
- has_downloads = false -> null
- has_issues = false -> null
- has_projects = false -> null
- has_wiki = false -> null
- html_url = "https://github.com/exnihilo-studio/test_terraform_repo" -> null
- http_clone_url = "https://github.com/exnihilo-studio/test_terraform_repo.git" -> null
- id = "test_terraform_repo" -> null
- ignore_vulnerability_alerts_during_read = false -> null
- is_template = false -> null
- merge_commit_message = "PR_TITLE" -> null
- merge_commit_title = "MERGE_MESSAGE" -> null
- name = "test_terraform_repo" -> null
- node_id = "R_kgDOSAb99A" -> null
- private = false -> null
- repo_id = 1208417780 -> null
- squash_merge_commit_message = "COMMIT_MESSAGES" -> null
- squash_merge_commit_title = "COMMIT_OR_PR_TITLE" -> null
- ssh_clone_url = "[email protected]:exnihilo-studio/test_terraform_repo.git" -> null
- svn_url = "https://github.com/exnihilo-studio/test_terraform_repo" -> null
- topics = [] -> null
- visibility = "public" -> null
- vulnerability_alerts = true -> null
- web_commit_signoff_required = false -> null
# (4 unchanged attributes hidden)
- security_and_analysis {
- secret_scanning {
- status = "disabled" -> null
}
- secret_scanning_push_protection {
- status = "disabled" -> null
}
}
}
Plan: 0 to add, 0 to change, 2 to destroy.
Debug Output
module.github_repo.github_branch.default[0]: Destroying... [id=test_terraform_repo:main]
╷
│ Error: error deleting GitHub branch reference exnihilo-studio/test_terraform_repo (refs/heads/main): DELETE https://api.github.com/repos/exnihilo-studio/test_terraform_repo/git/refs/heads/main: 422 Cannot delete the default branch []
│
│
╵
Panic Output
Code of Conduct
Expected Behavior
I commented out the whole the content of the terraform file and expected the repo to be completely deleted. I also tried terraform destroy and got the same error
Actual Behavior
I got the error
Terraform Version
Affected Resource(s)
Terraform Configuration Files
Steps to Reproduce
The above Terraform configuration file is stored as a module and I have this file that uses the module
terraform apply -auto-approveto create the repoterraform apply -auto-approveto delete the repoterraform destroyand got the same errorThis is the plan for the
terraform destroywhich I run after the 2nd stepDebug Output
module.github_repo.github_branch.default[0]: Destroying... [id=test_terraform_repo:main] ╷ │ Error: error deleting GitHub branch reference exnihilo-studio/test_terraform_repo (refs/heads/main): DELETE https://api.github.com/repos/exnihilo-studio/test_terraform_repo/git/refs/heads/main: 422 Cannot delete the default branch [] │ │ ╵Panic Output
Code of Conduct