From 22bbf50ddc8b1355ed9745f75e1f7f9799b46eb4 Mon Sep 17 00:00:00 2001 From: Steven Welch Date: Wed, 2 Sep 2026 09:43:09 -0600 Subject: [PATCH 1/3] feat: manage organization repository topics centrally Add topics_by_repository to main.tf beside the repository definitions and wire it into github_repository.repositories via the provider-supported inline topics attribute. Topics were audited against live GitHub state on 2026-09-02: stale tags corrected, initial topics added for previously untagged repositories, and factual topics expanded where evidenced. --- gh-repositories.tf | 5 +++++ main.tf | 25 +++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/gh-repositories.tf b/gh-repositories.tf index 0e788a2..3f864a0 100644 --- a/gh-repositories.tf +++ b/gh-repositories.tf @@ -13,6 +13,11 @@ resource "github_repository" "repositories" { delete_branch_on_merge = true squash_merge_commit_title = "PR_TITLE" squash_merge_commit_message = "PR_BODY" + # Topics are declared in main.tf (local.topics_by_repository) next to the + # repository list so every repository's topics live where repositories are + # defined. A missing entry fails the plan; use an explicit empty list for a + # repository that should carry no topics. + topics = local.topics_by_repository[each.key] lifecycle { ignore_changes = [ description, diff --git a/main.tf b/main.tf index 4b2aa60..0044384 100644 --- a/main.tf +++ b/main.tf @@ -31,6 +31,31 @@ locals { private_github_repositories = toset([ "agent-knowledge" ]) + # Topics are managed for every repository in github_repositories. The + # lookup in gh-repositories.tf is direct, so adding a repository without a + # topics entry fails the plan; a repository intentionally without topics + # declares an explicit empty list. Values audited against live GitHub + # repository topics on 2026-09-02. + topics_by_repository = { + ".github" = ["community-health", "github", "org-profile"] + "agent-knowledge" = ["agents", "documentation", "knowledge-base", "opencode"] + "ansible-project-libvirt" = ["ansible-playbooks", "libvirt"] + "ansible-role-crc" = ["ansible", "ansible-role", "crc", "openshift-local"] + "ansible-site-cluster" = ["ansible", "ansible-playbook", "gitops", "ksops", "openshift", "openshift-local"] + "cflan" = ["cloudflare", "dns", "networking", "networkmanager", "python"] + "charts" = ["ghcr", "gitops", "helm", "helm-charts", "oci"] + "images" = ["buildah", "containerfiles", "custom-runners", "github-actions", "opentofu"] + "kustomize-cluster" = ["app-of-apps", "argocd", "gitops", "k3s", "ksops", "kustomize", "sops"] + "shared-workflows" = ["github-actions", "github-workflows", "opentofu", "reusable-workflows", "shared-workflows"] + "terraform-libvirt-domain" = ["cloud-init", "libvirt", "libvirt-provider", "terraform-module"] + "tfroot-aws" = ["aws-provider", "kms", "opentofu", "s3-backend", "sops", "tfstate"] + "tfroot-cloudflare" = ["cloudflare", "cloudflare-access", "cloudflare-tunnel", "opentofu", "s3-backend", "sops", "tfstate"] + "tfroot-gcp" = ["gcp", "gcs-backend", "kms", "opentofu", "sops", "tfstate", "workload-identity-federation"] + "tfroot-github" = ["github-actions", "opentofu", "s3-backend", "sops", "tfstate", "terraform-provider-github"] + "tfroot-libvirt" = ["cloud-init", "k3s", "libvirt", "libvirt-provider", "opentofu", "s3-backend", "sops", "tfstate"] + "tfroot-namecheap" = ["cloudflare", "dns", "domains", "namecheap", "opentofu"] + "www" = ["cloudflare", "css", "html", "pwa", "s3", "static-site"] + } relaxed_branch_protection_github_repositories = toset([ "agent-knowledge" ]) From a177fa634387160b9697b85016ca86154eb1c6c6 Mon Sep 17 00:00:00 2001 From: Steven Welch Date: Wed, 2 Sep 2026 09:50:21 -0600 Subject: [PATCH 2/3] refactor: skip topic management for archived repositories Owner feedback: the archived ansible-* repositories are deprecated; limit topics_by_repository to active repositories and set topics to null for archived ones so the provider leaves their GitHub topics unmanaged. --- gh-repositories.tf | 11 ++++++----- main.tf | 15 +++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/gh-repositories.tf b/gh-repositories.tf index 3f864a0..c70f955 100644 --- a/gh-repositories.tf +++ b/gh-repositories.tf @@ -13,11 +13,12 @@ resource "github_repository" "repositories" { delete_branch_on_merge = true squash_merge_commit_title = "PR_TITLE" squash_merge_commit_message = "PR_BODY" - # Topics are declared in main.tf (local.topics_by_repository) next to the - # repository list so every repository's topics live where repositories are - # defined. A missing entry fails the plan; use an explicit empty list for a - # repository that should carry no topics. - topics = local.topics_by_repository[each.key] + # Topics are declared in main.tf (local.topics_by_repository) for active + # repositories only; archived repositories are skipped and their existing + # GitHub topics stay unmanaged. A missing entry for an active repository + # fails the plan; use an explicit empty list for a repository that should + # carry no topics. + topics = contains(local.archived_github_repositories, each.key) ? null : local.topics_by_repository[each.key] lifecycle { ignore_changes = [ description, diff --git a/main.tf b/main.tf index 0044384..a87c983 100644 --- a/main.tf +++ b/main.tf @@ -31,17 +31,16 @@ locals { private_github_repositories = toset([ "agent-knowledge" ]) - # Topics are managed for every repository in github_repositories. The - # lookup in gh-repositories.tf is direct, so adding a repository without a - # topics entry fails the plan; a repository intentionally without topics - # declares an explicit empty list. Values audited against live GitHub - # repository topics on 2026-09-02. + # Topics are managed for active repositories only. Archived repositories + # are skipped entirely (see gh-repositories.tf) and their existing GitHub + # topics stay unmanaged, so they carry no entry here. The lookup for active + # repositories is direct, so adding an active repository without a topics + # entry fails the plan; a repository intentionally without topics declares + # an explicit empty list. Values audited against live GitHub repository + # topics on 2026-09-02. topics_by_repository = { ".github" = ["community-health", "github", "org-profile"] "agent-knowledge" = ["agents", "documentation", "knowledge-base", "opencode"] - "ansible-project-libvirt" = ["ansible-playbooks", "libvirt"] - "ansible-role-crc" = ["ansible", "ansible-role", "crc", "openshift-local"] - "ansible-site-cluster" = ["ansible", "ansible-playbook", "gitops", "ksops", "openshift", "openshift-local"] "cflan" = ["cloudflare", "dns", "networking", "networkmanager", "python"] "charts" = ["ghcr", "gitops", "helm", "helm-charts", "oci"] "images" = ["buildah", "containerfiles", "custom-runners", "github-actions", "opentofu"] From 208f19fef557c12b7ec0d97e7bb4e0debb879ca3 Mon Sep 17 00:00:00 2001 From: Steven Welch Date: Wed, 2 Sep 2026 09:56:36 -0600 Subject: [PATCH 3/3] refactor: gate topics on the existing active_github_repositories local Reuse the established active-repository local instead of re-testing the archived set, and reference it from the map comment for discoverability. No semantic change: the same 14 active repositories are managed. --- gh-repositories.tf | 12 ++++++------ main.tf | 7 ++++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/gh-repositories.tf b/gh-repositories.tf index c70f955..ed1cec8 100644 --- a/gh-repositories.tf +++ b/gh-repositories.tf @@ -13,12 +13,12 @@ resource "github_repository" "repositories" { delete_branch_on_merge = true squash_merge_commit_title = "PR_TITLE" squash_merge_commit_message = "PR_BODY" - # Topics are declared in main.tf (local.topics_by_repository) for active - # repositories only; archived repositories are skipped and their existing - # GitHub topics stay unmanaged. A missing entry for an active repository - # fails the plan; use an explicit empty list for a repository that should - # carry no topics. - topics = contains(local.archived_github_repositories, each.key) ? null : local.topics_by_repository[each.key] + # Topics are declared in main.tf (local.topics_by_repository) and managed + # for active repositories only (local.active_github_repositories); + # archived repositories are skipped and their existing GitHub topics stay + # unmanaged. A missing entry for an active repository fails the plan; use + # an explicit empty list for a repository that should carry no topics. + topics = contains(local.active_github_repositories, each.key) ? local.topics_by_repository[each.key] : null lifecycle { ignore_changes = [ description, diff --git a/main.tf b/main.tf index a87c983..c54e5c6 100644 --- a/main.tf +++ b/main.tf @@ -31,9 +31,10 @@ locals { private_github_repositories = toset([ "agent-knowledge" ]) - # Topics are managed for active repositories only. Archived repositories - # are skipped entirely (see gh-repositories.tf) and their existing GitHub - # topics stay unmanaged, so they carry no entry here. The lookup for active + # Topics are managed for active repositories only + # (local.active_github_repositories). Archived repositories are skipped + # entirely (see gh-repositories.tf) and their existing GitHub topics stay + # unmanaged, so they carry no entry here. The lookup for active # repositories is direct, so adding an active repository without a topics # entry fails the plan; a repository intentionally without topics declares # an explicit empty list. Values audited against live GitHub repository