Skip to content

Overview

gh-infra manages GitHub infrastructure through four resource kinds, organized in two pairs:

1 repo N repos
Repository settings Repository RepositorySet
File management File FileSet

The single-repo resource (Repository, File) manages one repository in detail. The set resource (RepositorySet, FileSet) applies shared configuration across multiple repositories — each entry can override specific values.

All resources share the same top-level structure:

apiVersion: gh-infra/v1
kind: <Repository | RepositorySet | File | FileSet>
metadata:
owner: <github-owner>
name: <repo-name> # single-repo resources; optional label for FileSet
spec:
# Resource-specific fields
Resource metadata.owner metadata.name Identifies
Repository required required A single repo (owner/name)
File required required A single repo (owner/name)
RepositorySet required — All repos listed in repositories
FileSet required optional All repos listed in repositories

A FileSet’s metadata.name does not select repositories. It names the FileSet in plan output and in the defaults for its commit message, pull request branch (gh-infra/sync-<owner>-<name>), and pull request body. Without it, the FileSet is named <owner>/<repo-a>+<repo-b> after its sorted repository names (see Delivery Method).

You can organize YAML files however you like. gh-infra accepts a file or directory path:

Terminal window
gh infra plan ./repos/ # All YAML files in the directory
gh infra plan ./repos/my-cli.yaml # A single file

Multiple resource kinds can coexist in the same directory. gh-infra processes each file based on its kind.

A single YAML file can contain multiple documents separated by ---. This lets you group related resources together without creating separate files:

apiVersion: gh-infra/v1
kind: Repository
metadata:
name: my-app
owner: my-org
spec:
description: "Application repository"
visibility: public
---
apiVersion: gh-infra/v1
kind: File
metadata:
name: my-app
owner: my-org
spec:
files:
- path: .github/CODEOWNERS
content: |
* @my-org/platform
via: push

You can mix any resource kinds within a single file. Each document is parsed independently, so they do not share YAML anchors or other state.