feat: manage organization repository topics centrally - #51
Merged
Conversation
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.
Contributor
OpenTofu TestOpenTofu test passed. View run output |
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.
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.
Contributor
OpenTofu PlanOpenTofu plan passed. View run outputOpenTofu will perform the following actions:
# github_repository.repositories[".github"] will be updated in-place
~ resource "github_repository" "repositories" {
id = ".github"
name = ".github"
~ topics = [
+ "community-health",
+ "org-profile",
# (1 unchanged element hidden)
]
# (37 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["agent-knowledge"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "agent-knowledge"
name = "agent-knowledge"
~ topics = [
+ "agents",
+ "documentation",
+ "knowledge-base",
+ "opencode",
]
# (34 unchanged attributes hidden)
}
# github_repository.repositories["charts"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "charts"
name = "charts"
~ topics = [
+ "ghcr",
+ "gitops",
+ "helm",
+ "helm-charts",
+ "oci",
]
# (36 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["images"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "images"
name = "images"
~ topics = [
+ "github-actions",
+ "opentofu",
# (3 unchanged elements hidden)
]
# (37 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["kustomize-cluster"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "kustomize-cluster"
name = "kustomize-cluster"
~ topics = [
+ "app-of-apps",
+ "gitops",
+ "k3s",
[REDACTED: potentially sensitive plan output]
[REDACTED: potentially sensitive plan output]
# (2 unchanged elements hidden)
]
# (35 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["shared-workflows"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "shared-workflows"
name = "shared-workflows"
~ topics = [
+ "github-actions",
+ "opentofu",
+ "reusable-workflows",
# (2 unchanged elements hidden)
]
# (36 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["terraform-libvirt-domain"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "terraform-libvirt-domain"
name = "terraform-libvirt-domain"
~ topics = [
+ "cloud-init",
+ "libvirt",
# (2 unchanged elements hidden)
]
# (37 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["tfroot-aws"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "tfroot-aws"
name = "tfroot-aws"
~ topics = [
+ "kms",
+ "opentofu",
# (4 unchanged elements hidden)
]
# (37 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["tfroot-cloudflare"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "tfroot-cloudflare"
name = "tfroot-cloudflare"
~ topics = [
+ "cloudflare-access",
+ "cloudflare-tunnel",
+ "opentofu",
# (4 unchanged elements hidden)
]
# (37 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["tfroot-gcp"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "tfroot-gcp"
name = "tfroot-gcp"
~ topics = [
+ "gcp",
+ "gcs-backend",
+ "kms",
+ "opentofu",
[REDACTED: potentially sensitive plan output]
+ "tfstate",
+ "workload-identity-federation",
]
# (36 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["tfroot-github"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "tfroot-github"
name = "tfroot-github"
~ topics = [
- "github-provider-terraform",
+ "github-actions",
+ "opentofu",
+ "terraform-provider-github",
# (3 unchanged elements hidden)
]
# (37 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["tfroot-libvirt"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "tfroot-libvirt"
name = "tfroot-libvirt"
~ topics = [
- "ansible-automation-platform",
+ "cloud-init",
+ "k3s",
+ "libvirt",
+ "opentofu",
# (4 unchanged elements hidden)
]
# (37 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["tfroot-namecheap"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "tfroot-namecheap"
name = "tfroot-namecheap"
~ topics = [
+ "cloudflare",
+ "dns",
+ "domains",
+ "namecheap",
+ "opentofu",
]
# (36 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["www"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "www"
name = "www"
~ topics = [
+ "cloudflare",
+ "pwa",
+ "s3",
+ "static-site",
# (2 unchanged elements hidden)
]
# (38 unchanged attributes hidden)
# (1 unchanged block hidden)
}
Plan: 0 to add, 14 to change, 0 to destroy.
OpenTofu will perform the following actions:
# github_repository.repositories[".github"] will be updated in-place
~ resource "github_repository" "repositories" {
id = ".github"
name = ".github"
~ topics = [
+ "community-health",
+ "org-profile",
# (1 unchanged element hidden)
]
# (37 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["agent-knowledge"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "agent-knowledge"
name = "agent-knowledge"
~ topics = [
+ "agents",
+ "documentation",
+ "knowledge-base",
+ "opencode",
]
# (34 unchanged attributes hidden)
}
# github_repository.repositories["charts"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "charts"
name = "charts"
~ topics = [
+ "ghcr",
+ "gitops",
+ "helm",
+ "helm-charts",
+ "oci",
]
# (36 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["images"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "images"
name = "images"
~ topics = [
+ "github-actions",
+ "opentofu",
# (3 unchanged elements hidden)
]
# (37 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["kustomize-cluster"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "kustomize-cluster"
name = "kustomize-cluster"
~ topics = [
+ "app-of-apps",
+ "gitops",
+ "k3s",
[REDACTED: potentially sensitive plan output]
[REDACTED: potentially sensitive plan output]
# (2 unchanged elements hidden)
]
# (35 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["shared-workflows"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "shared-workflows"
name = "shared-workflows"
~ topics = [
+ "github-actions",
+ "opentofu",
+ "reusable-workflows",
# (2 unchanged elements hidden)
]
# (36 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["terraform-libvirt-domain"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "terraform-libvirt-domain"
name = "terraform-libvirt-domain"
~ topics = [
+ "cloud-init",
+ "libvirt",
# (2 unchanged elements hidden)
]
# (37 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["tfroot-aws"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "tfroot-aws"
name = "tfroot-aws"
~ topics = [
+ "kms",
+ "opentofu",
# (4 unchanged elements hidden)
]
# (37 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["tfroot-cloudflare"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "tfroot-cloudflare"
name = "tfroot-cloudflare"
~ topics = [
+ "cloudflare-access",
+ "cloudflare-tunnel",
+ "opentofu",
# (4 unchanged elements hidden)
]
# (37 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["tfroot-gcp"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "tfroot-gcp"
name = "tfroot-gcp"
~ topics = [
+ "gcp",
+ "gcs-backend",
+ "kms",
+ "opentofu",
[REDACTED: potentially sensitive plan output]
+ "tfstate",
+ "workload-identity-federation",
]
# (36 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["tfroot-github"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "tfroot-github"
name = "tfroot-github"
~ topics = [
- "github-provider-terraform",
+ "github-actions",
+ "opentofu",
+ "terraform-provider-github",
# (3 unchanged elements hidden)
]
# (37 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["tfroot-libvirt"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "tfroot-libvirt"
name = "tfroot-libvirt"
~ topics = [
- "ansible-automation-platform",
+ "cloud-init",
+ "k3s",
+ "libvirt",
+ "opentofu",
# (4 unchanged elements hidden)
]
# (37 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["tfroot-namecheap"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "tfroot-namecheap"
name = "tfroot-namecheap"
~ topics = [
+ "cloudflare",
+ "dns",
+ "domains",
+ "namecheap",
+ "opentofu",
]
# (36 unchanged attributes hidden)
# (1 unchanged block hidden)
}
# github_repository.repositories["www"] will be updated in-place
~ resource "github_repository" "repositories" {
id = "www"
name = "www"
~ topics = [
+ "cloudflare",
+ "pwa",
+ "s3",
+ "static-site",
# (2 unchanged elements hidden)
]
# (38 unchanged attributes hidden)
# (1 unchanged block hidden)
}
Plan: 0 to add, 14 to change, 0 to destroy. |
14 tasks
xnoto
added a commit
that referenced
this pull request
Sep 2, 2026
Comment-only follow-up to #51 per owner feedback; no functional change, plan is a no-op.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Brings organization repository topics under central management in this root for active repositories. Adds a
topics_by_repositorymap inmain.tfnext to the repository definitions and wires it intogithub_repository.repositoriesthrough the provider-supported inlinetopicsargument, so active repositories' topics become declared desired state instead of unmanaged GitHub metadata. Archived repositories are skipped (topics = null), so their existing GitHub topics are left untouched and unmanaged.Design notes:
github_repository_topicsas incompatible with thetopicsattribute and intended only for repositories not handled via Terraform ([FEAT]: Add github_repository_topics resource integrations/terraform-provider-github#1845). Every repository here is managed by this root, so the inline attribute is the supported path.github_repository.repositoriesis already in state for every repository, managing topics requires no newimport {}blocks; the existingtfroot-gcprepository import inimports.tfis unchanged. The CI plan confirms this: every repository plans as an in-place update, with no creates.ansible-*repositories (deprecated) are excluded from the map;gh-repositories.tfgates topics on the existinglocal.active_github_repositorieslocal, so archived repositories' topics stay unmanaged.Topic audit (live topics read from GitHub on 2026-09-02):
tfroot-libvirtdropsansible-automation-platform(no Ansible content in that root);tfroot-githubrenamesgithub-provider-terraform→terraform-provider-github(the provider's registry slug).charts,agent-knowledge,tfroot-gcp,tfroot-namecheap.ansible-*repositories carry no entry and no drift.cflan(zero drift in the plan).opentofuacross tfroot roots,app-of-apps/k3s/ksopsforkustomize-cluster,pwa/s3/static-siteforwww,workload-identity-federationfortfroot-gcp), each sourced from repository READMEs, repository source, or the agent-knowledge topology.Type of change
Validation
208f19fef557c12b7ec0d97e7bb4e0debb879ca3—opentofu / testandopentofu / planare green (validate, tflint, checkov, fmt, terraform-docs, and secret detection all passed). The plan is 0 to add, 14 to change, 0 to destroy — topics-only in-place updates on the 14 active repositories; no archived repository appears in the plan, and there are no protection, secret, file, team, or membership changes.README.mdrequires no regeneration.Impact and rollout
Merging starts the environment-gated apply on
main. The only runtime effect is GitHub repository topic metadata on active repositories; branch protections, teams, secrets, distributed files, and archived repositories are unchanged. Rollback is a revert (topics otherwise remain editable in the GitHub UI only until the next apply restores declared state).Safety and secrets
AI-agent disclosure: this change was authored by the makeitwork OpenCode agent under owner tasking; the evidence and decision trail are in this description.