This Terraform project manages GitHub repositories and their branch protection rules using the GitHub provider.
- Configure branch protection rules
- Terraform >= 1.0
- GitHub account with appropriate permissions
- GitHub Personal Access Token with
repoandadmin:orgscopes
By default, this configuration manages EXISTING repositories (read-only reference). It only manages:
- ✅ Branch protection rules
- ✅ Reading repository information
It does NOT:
- ❌ Create new repositories
- ❌ Modify repository settings (description, visibility, etc.)
- ❌ Delete repositories
Only required_status_checks is managed. The generated config keeps just
the required_status_checks block per branch. Every other branch-protection
setting (PR reviews, enforce_admins, signed commits, linear history, push
restrictions, etc.) is intentionally left unchanged on GitHub via
lifecycle { ignore_changes } in branch_protection.tf — even if you add those
fields to the YAML, Terraform will not touch them.
To manage an additional field, register a translator for it in
PROTECTION_FIELD_TRANSLATORS (scripts/generate_gazebo_config.py) and remove
it from the ignore_changes list in branch_protection.tf. Those two are
complements: every field the generator does not emit must be in ignore_changes
(Terraform's ignore_changes only accepts a literal list, so it is maintained
by hand).
-
Create a GitHub Personal Access Token
Option A: Fine-Grained Personal Access Token
Fine-grained tokens provide better security with granular permissions:
- Go to GitHub Settings → Developer settings → Personal access tokens → Fine-grained tokens
- Click "Generate new token"
- Configure:
- Token name:
terraform-github-repos - Expiration: Set as needed (90 days, 1 year, etc.)
- Repository access:
- Select "Public Repositories (read-only)" for reading gazebodistro
- OR select "All repositories" if managing org-wide
- OR select specific repositories you want to manage
- Permissions:
- Repository permissions → Administration: Read and write (for branch protection)
- Repository permissions → Contents: Read-only (for reading configs)
- Token name:
- Generate and copy the token (format:
github_pat_...)
-
Set environment variable
export GITHUB_TOKEN="your_github_token"
-
Generate or create a configuration file
For Gazebo repositories, this will generate the
gazebo-repos-config.yamlfor the active collections in gazebodistro (those listed in release-tools'gz-collections.yaml)../scripts/update-gazebo-repos.sh
Or manually create
gazebo-repos-config.yaml:github_organization: gazebosim repositories: - name: my-repo branches: - branch: main required_status_checks: strict: true contexts: - ci/test - ci/lint
The workflow will use gazebo-repos-config.yaml file as input for the configurations and
terraform for syncing the configurations in that yaml file into the github repositories:
-
Initialize Terraform
terraform init
-
Import existing branch protection rules (first time only)
./scripts/import-branch-protection.sh gazebo-repos-config.yaml
-
Review the plan (no changes done in this step)
terraform plan
-
Apply the configuration
terraform apply
-
To remove branch protection (if needed)
terraform destroy
The gazebo-repos-config.yaml file contains:
github_organization: gazebosim # GitHub org or username
repositories:
- name: gz-common # Repository name
branches: # List of branch-protection rules
- branch: main # Rule pattern (fnmatch; may be a glob, e.g. gz-common[7-9])
required_status_checks: # The only managed field
strict: true
contexts:
- DCO
- CI-testYou can protect multiple branches per repository:
repositories:
- name: gz-sim
branches:
- branch: main
required_status_checks:
strict: true
contexts:
- DCO
- branch: gz-sim7
required_status_checks:
strict: true
contexts:
- gz_sim-ci-pr_any-jammy-amd64
- branch: gz-sim8
required_status_checks:
strict: true
contexts:
- gz_sim-ci-pr_any-noble-amd64This repository includes automation to manage all Gazebo repositories from the gazebo-tooling/gazebodistro collection files.
- Configuration Generation: A Python script reads collection files from gazebodistro and generates a YAML configuration
- Terraform Deployment: Terraform reads the YAML file and applies repository and branch protection settings
The generated gazebo-repos-config.yaml contains:
- GitHub organization name
- List of repositories with their branches
- Branch protection rules for each branch
github_organization: gazebosim
repositories:
- name: gz-common
branches:
- branch: main
required_status_checks:
strict: true
contexts:
- DCO
- gz_common-ci-pr_any-homebrew-amd64The Python script automatically:
- Fetches the active collections from release-tools'
gz-collections.yamland parses only the matchingcollection-<name>.yamlfiles from gazebodistro - Extracts all
gz-*andsdformatrepositories and their active branch versions - Enumerates each repository's actual branch-protection rule patterns via the
GitHub GraphQL API. GitHub stores protection as
fnmatchpattern rules (e.g.gz-sim[7-9]) that can cover several branches — there is not one rule per branch, and the pattern rarely equals a concrete branch name. Terraform matches rules by their exact pattern, so the config must use these patterns - Keeps only the rules whose pattern matches at least one active branch (EOL-only
patterns such as
ign-common[0-2]are dropped), then filters each rule down to the fields registered inPROTECTION_FIELD_TRANSLATORS(currently justrequired_status_checks) and drops rules that have none of them - Generates
gazebo-repos-config.yamlwith one entry per kept rule pattern. Thebranch:value is the rule pattern, which is also the Terraform import id (<repo>:<pattern>)
Run the update script locally:
./scripts/update-gazebo-repos.shOr run the Python script directly:
pip install -r requirements.txt
python scripts/generate_gazebo_config.py