Skip to content

Labels

Manage repository labels declaratively. Labels declared in the manifest are created or updated on GitHub. Existing labels not listed in the manifest are left untouched by default.

spec:
labels:
- name: kind/bug
color: d73a4a
description: "A bug; unintended behavior"
- name: kind/feature
color: "425df5"
description: "A feature request"
- name: priority/high
color: ff0000
FieldTypeRequiredDescription
namestringyesLabel name (must be unique within the list)
colorstringyesHex color code without # prefix (e.g., d73a4a)
descriptionstringnoShort description of the label’s purpose

By default, gh-infra only creates and updates labels. Labels on GitHub that are not in the manifest are left untouched. To delete unmanaged labels, set label_sync to mirror:

spec:
label_sync: mirror # additive (default) | mirror
labels:
- name: kind/bug
color: d73a4a
- name: kind/feature
color: "425df5"
ValueBehavior
additiveCreate and update only. Unmanaged labels are left in place. This is the default when label_sync is omitted.
mirrorCreate, update, and delete. Labels on GitHub that are not in the manifest are removed.

When mirror mode marks labels for deletion, plan shows usage information (issue/PR count and when the label was last used) so you can verify before applying:

~ org/my-repo
+ labels.kind/bug #d73a4a
- labels.help wanted #0e8a16 (42 issues/PRs, last used 3d ago)
- labels.wontfix #ffffff (0 issues/PRs)

With label_sync: mirror, gh-infra can replace dedicated label synchronization GitHub Actions such as EndBug/label-sync and crazy-max/ghaction-github-labeler.

Instead of maintaining a separate workflow and label config file, define labels directly in your gh-infra manifest alongside other repository settings:

# Before: separate workflow + label-definitions.yaml
# After: everything in one manifest
apiVersion: gh-infra/v1
kind: Repository
metadata:
name: my-repo
owner: my-org
spec:
label_sync: mirror
labels:
- name: kind/bug
color: d73a4a
description: "A bug; unintended behavior"
- name: kind/feature
color: "425df5"
description: "A feature request"
rulesets:
# ... other settings managed in the same file

A workflow that applies on push looks like this:

.github/workflows/infra.yaml
on:
push:
branches: [main]
paths: [repos/**]
workflow_dispatch:
jobs:
apply:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: gh extension install babarot/gh-infra
- run: gh infra apply ./repos/
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

gh CLI is preinstalled on all GitHub-hosted runners, so no additional setup is needed.

Benefits over dedicated Actions:

  • Single source of truth: labels, rulesets, secrets, and other settings live in one manifest.
  • Better preview: plan shows a full diff with usage stats before applying.
  • One fewer third-party Action: no additional SHA pin to maintain.