labelsync

command module
v0.1.0-rc.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 21, 2026 License: MIT Imports: 5 Imported by: 0

README

labelsync

labelsync

Documentation: labelsync.specs.dev

Synchronise GitHub issue/PR labels across a set of repositories from a local YAML file.

labelsync is a reconciler, not a script: for each target repository it reads the current labels, resolves the desired set, computes an ordered plan, and then applies it — or prints it, under --dry-run. One labels.yml describes the labels you want; groups describe which repositories should have them. Running it twice changes nothing the second time.

labelsync selecting three repositories and printing the plan for them

The command surface, then a real dry run against three public repositories — two renames each, one drifted description, and everything else already in sync. It writes nothing, and the exit code carries the 2 bit because it found drift.

# labels.yml
version: 1

groups:
  ours:
    org: yourorg
    exclude: ["*-archive"]

defaults:
  groups: [ours]

renames:
  - from: "bug"
    to: "type: bug"

labels:
  - name: "type: bug"
    color: "d73a4a"
    description: "Something isn't working"
  - name: "type: feature"
    color: "0e8a16"
    description: "New functionality"
labelsync groups            # which repositories that selects, and why the rest were filtered out
labelsync sync --dry-run    # the plan; writes nothing; exits 2 if anything has drifted
labelsync sync              # apply it

What it does, in one list:

  • Creates, updates, and converges names, colours, descriptions, and casing across every selected repository. Nothing is deleted unless you ask for --mode=prune, which reports first and then asks which labels to remove.
  • Renames without losing anything. A renames: entry becomes a PATCH, so every issue and pull request that carried the old label still carries it under the new name.
  • Never touches a repository no group selects. That is the safety property the rest is built on.
  • Runs in CI. --dry-run sets the 2 bit on drift, so a pull-request check fails when the committed config and the live labels disagree — test the bit, because a run that also skipped a repository exits 6. --output=json emits NDJSON with a stable error_kind.

Install

brew install specsnl/tap/labelsync

Or go install github.com/specsnl/labelsync@latest, or download a tar.gz for your platform from the releases page — Linux and macOS, amd64 and arm64.

In a container, docker run --rm ghcr.io/specsnl/labelsync:0.1 --help — also published as ghcr.io/specsnl/labelsync/debian for when a step needs a shell.

Release candidates are a separate, opt-in cask, so brew upgrade never moves a stable install onto one — while the rc cask itself tracks the leading edge and upgrades onto a stable release once it ships:

brew install specsnl/tap/labelsync@rc

The two casks both provide a labelsync command and cannot be installed side by side — see Install channels.

Building from a checkout needs nothing but Docker and Task:

task build

Getting started

Export before you write a config. Descriptions in the config file are authoritative, so a config written from scratch clears every description your repositories already have:

labelsync export yourorg/yourrepo --out labels.yml

The rest — describing the repositories, the dry run, the first apply — is in Getting started, and everything else — the configuration file, every command and flag, running in CI, and how it is built — is on the same site: labelsync.specs.dev.


Contributing

Every command runs through Task, which wraps the Docker Compose services that pin the Go, golangci-lint, Node, and Hugo versions — so a check runs the same way locally as it does in CI. Run task --list for the full set.

task checkall   # tidy:check, lint, test, md:check — run this before opening a pull request

Conventions, workflow, and the house rules that reviews are held to: AGENTS.md.


License

MIT — see LICENSE.

Documentation

Overview

Command labelsync synchronises GitHub issue/PR labels across a configured set of repositories, using a local YAML file as the source of truth.

Directories

Path Synopsis
internal
apply
Package apply executes a plan.Plan.
Package apply executes a plan.Plan.
cmd
Package cmd is the labelsync command tree.
Package cmd is the labelsync command tree.
config
Package config finds the labelsync config file, parses it, normalises what it parsed, and validates the result.
Package config finds the labelsync config file, parses it, normalises what it parsed, and validates the result.
github
Package github is labelsync's GitHub boundary.
Package github is labelsync's GitHub boundary.
github/ratelimit
Package ratelimit keeps a run inside GitHub's limits, proactively and reactively.
Package ratelimit keeps a run inside GitHub's limits, proactively and reactively.
labelsync
Package labelsync holds the values every other labelsync package depends on: the sentinel errors that describe how a run can fail, and the XDG paths and file names that describe where its files live.
Package labelsync holds the values every other labelsync package depends on: the sentinel errors that describe how a run can fail, and the XDG paths and file names that describe where its files live.
palette
Package palette owns colour allocation: the fixed grid of candidate colours a displaced label may be moved to, and the rule that picks one of them.
Package palette owns colour allocation: the fixed grid of candidate colours a displaced label may be moved to, and the rule that picks one of them.
plan
Package plan turns "these labels are configured" and "these labels exist" into an ordered list of changes.
Package plan turns "these labels are configured" and "these labels exist" into an ordered list of changes.
util/exit
Package exit holds the process exit codes labelsync returns, and the error type that carries one out of a command.
Package exit holds the process exit codes labelsync returns, and the error type that carries one out of a command.
util/output
Package output is the single channel for user-facing output.
Package output is the single channel for user-facing output.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL