bug or documentation. Keeping them tidy by hand is tedious: names drift, colours differ between repositories, and people forget to add them.
The labels feature does three jobs for you:
- Label sync. It makes the repository’s list of labels match the
labelssection of your config: it creates missing labels, fixes colours and descriptions, renames old labels, and (only if you ask) deletes labels you did not define. - Labelling. It adds a label to a pull request or issue while a rule’s conditions pass, and takes it off again when they stop passing. For example, “label every pull request that touches
docs/**as documentation”. - Size labels. With a
sizeLabelssection, it adds built-inSize: XStoSize: XLlabels to pull requests by how many lines they change.
labels, labelling or sizeLabels section. You can use any of the three on its own.
Turn it on
Add the workflow events
push, schedule, workflow_dispatch, repository_dispatch and merge_group. Labelling runs on pull request and issue events. The workflow in Getting started listens to all of them. At minimum you need:Grant the permissions
issues: write (repository labels, and labels on issues) and pull-requests: write (labels on pull requests). The workflow token is enough; no app or personal token is needed.Define your labels
labels section to .github/smartcloud.yml. Each entry has a key you choose, a name and a color:000000, is read back as the six digits you wrote. Quoting it (color: '000000') is still the clearest.Add a labelling rule (optional)
Run it
main (or run the workflow by hand) to sync the labels. Open a pull request that changes a file under docs/ to see the label applied.Options
labels and labelling are any non-empty text without leading or trailing spaces, except __proto__.
Renaming a label with aliases
To rename bug to Type: Bug without losing it on existing issues, give the new name and list the old one as an alias:
bug label in place. Every issue that had bug now shows Type: Bug.
An alias is simply an old name. You keep it in the config so smartcloud still recognises the label wherever the old name is still in use.
Before the sync has run. Label sync only runs on pushes and scheduled or manual runs, so a pull request can be labelled before the rename reaches the repository (always the case for a pull request from a fork, whose token cannot rename labels). Labelling knows about aliases, so it never leaves the label on twice:
- If the rule for
bugpasses and the pull request still hasdefect, smartcloud addsType: Bugand removesdefect. The job summary showsadded label "Type: Bug" to #7, replacing its old name "defect"andremoved label "defect" (an old name of "Type: Bug") from #7. - If the pull request already has both
Type: Buganddefect, smartcloud removesdefect, so the label is on once. - If the rule for
bugfails, smartcloud removesType: Buganddefect, whichever are there. - If GitHub refuses to add
Type: Bug(a read-only token),defectstays, so the pull request never loses the label. You get the usuallabels.addwarning.
Size: M to medium keeps Size: M as an alias for you (see Size labels), so a pull request that had Size: M ends up with medium only.
When an alias is another label’s name. Current names win. If bug lists Type: Feature as an alias but another entry is called Type: Feature, labelling treats Type: Feature as that other label and never removes it as an old name of bug. The same holds for a name a labelling rule applies directly. When two entries list the same alias, the first entry in the config keeps it.
Several rules for one label
A label is on when any rule naming it passes. That lets you use one rule per subject kind:Size thresholds
Change a threshold undersizeLabels.thresholds. Sizes you leave out keep their defaults. The thresholds must rise from s to xl, or the section is rejected:
Complete example
How it works
Label sync
Label sync runs onpush, schedule, workflow_dispatch, repository_dispatch and merge_group events. It never runs on pull request events, because those from forks carry a read-only token. For each entry in labels:
- A repository label with the same name, ignoring case, is matched and updated when its name, colour or description differs.
- Failing that, a repository label named in
aliasesis renamed. Exact names are matched before aliases, so an alias never takes a label another entry names directly. - Anything else is created.
- A
descriptionleft out of the config is left as it is on GitHub, so a config that only sets colours never blanks descriptions set by hand. - A label whose description is longer than 100 characters is reported as an error and left as it is. The rest still sync.
- When two entries name the same label, ignoring case, only the first is synced, with a warning.
- With
labelSync.prune: true, repository labels the config does not define are deleted. A label named in an entry’saliasescounts as defined, even when the entry’s own name already exists.
skipDelete input deleted unconfigured labels unless it was set. v2 never deletes a label unless
labelSync.prune is true.Labelling
Labelling runs on pull request events (pull_request, pull_request_target, pull_request_review, pull_request_review_comment) and on issues events. It does not run on comments.
labelis a key oflabels, and that label’snameis applied. A value that is not a key is used as the name itself.- For each label, smartcloud checks every rule that names it and applies to the subject’s kind. The label is added when any of them passes, and removed when all of them fail.
- Names compare ignoring case, as GitHub does.
- A label still on the item under one of its
aliasescounts as present. When the label is wanted the old name is swapped for the current one, and when it is not the old name is removed. See Renaming a label withaliases. - A label that has already gone when smartcloud removes it is a warning, not a failure.
- A label GitHub forbids adding or removing, as on the read-only token of a fork’s pull request, is a warning (
labels.addorlabels.remove), and the run carries on.
Size labels
sizeLabels adds five labels and a labelling rule for each, so every pull request carries one size label that moves as it grows or shrinks. Changed lines are additions plus deletions.
- The built-in labels and rules are ordinary
labelsandlabellingentries, so label sync creates the labels andlabelSync.prunecounts them as defined. - A
labelsorlabellingentry you write with the same key replaces the built-in one. Definelabels.size-xlto rename or recolour XL, orlabelling.size-xlto change when it applies. A renamed size keeps its built-in name among itsaliases, so label sync renames the existing label instead of leaving the old one on pull requests. - The rules use the
changesSizecondition and apply to pull requests only.
/label.
What you will see on GitHub
- Labels page. After a sync, the repository’s labels (Issues, then Labels) match your config.
- Labels on items. Labels appear on pull requests and issues as their rules pass, and disappear when they stop passing. The timeline shows them added by the account smartcloud runs as.
- Check run. A
smartcloud / labelscheck run on the commit. It succeeds when there is nothing wrong, is neutral with warnings (a repeated label name, a label already gone, a write refused), and fails on an error (an over-long description). - Job summary. Every label created, updated, renamed, deleted, added or removed is listed as a change.
Forks and restricted runs
On a pull request from a fork, or a Dependabot pull request, smartcloud acts with the read-only workflow token (see restricted runs). Labelling still evaluates its rules, but GitHub refuses the write: each refused add or remove becomes alabels.add or labels.remove warning and is listed under Restricted access in the job summary. Label sync never runs on pull request events, so it is not affected.
To label fork pull requests, also run the workflow on pull_request_target, where GitHub gives the workflow token write access. The run is still restricted (smartcloud acts with the workflow token, never a stronger one), but that token can now write labels. That event runs your default branch’s workflow, and smartcloud reads the config from the default branch, so the fork cannot change the rules.
In the house preset
The house preset defines nine labels and nothing else from this page: the AI policy’s process labelsneeds-disclosure, needs-dco, needs-reproduction, needs-evidence, needs-tests, needs-human-explanation, needs-scope-approval and needs-refactor, and house-sync for its own sync pull requests. It sets no labelSync, labelling or sizeLabels.
A Resnovas repository adds its own labels and rules below house:local under new keys. It cannot change the name, colour or description of a house label, and should not turn on labelSync.prune unless every label it wants to keep is in the config.
Troubleshooting
A label was not created or updated
A label was not created or updated
push, schedule, workflow_dispatch, repository_dispatch and merge_group. A pull request run does not sync labels. Push to the default branch or run the workflow by hand.labels.x.color: Expected Six hex digits
labels.x.color: Expected Six hex digits
red. YAML reads some unquoted values as numbers, such as 1e3 or 0x1f; smartcloud keeps what you wrote, so these are reported rather than turned into a different colour. An all-digit colour such as 000123 is fine unquoted. When in doubt, put the colour in quotes: color: '0E8A16'.label ... was not synced: its description is longer than GitHub's 100 characters
label ... was not synced: its description is longer than GitHub's 100 characters
labels.<key>.description to 100 characters or fewer.labels.x names ..., which labels.y already names; only the first is synced
labels.x names ..., which labels.y already names; only the first is synced
name, ignoring case. Remove or rename one of them.could not add ... on a read-only token, for example a pull request from a fork
could not add ... on a read-only token, for example a pull request from a fork
The old label is still there after a rename
The old label is still there after a rename
aliases. Without it, sync creates a new label and leaves the old one (and deletes it only with labelSync.prune: true, which drops it from every issue).A pull request shows both the old and the new name of a renamed label
A pull request shows both the old and the new name of a renamed label
aliases. Labelling then removes the old name the next time it runs on that pull request (any new commit or edit), and the next label sync renames the repository label.size thresholds must rise from s to xl
size thresholds must rise from s to xl
m: 5 fails because s is still 10.A label I added by hand keeps being removed
A label I added by hand keeps being removed