Skip to content

Dogfood: run labelsync against its own labels from CI (GH-48) - #97

Merged
Ilyes512 merged 3 commits into
mainfrom
feat/GH-48-dogfood-ci
Aug 12, 2026
Merged

Ilyes512 merged 3 commits into
mainfrom
feat/GH-48-dogfood-ci

Conversation

@Ilyes512

@Ilyes512 Ilyes512 commented Aug 11, 2026 •

Copy link
Copy Markdown
Member

Summary

  • .github/workflows/labels.yml — labelsync becomes its own first user. A pull request touching
    labels.yml gets sync --dry-run --output=json, which exits 2 and fails the job when the
    committed config and the live labels disagree; a merge to main, a weekly 0 6 * * 1 cron, and a
    workflow_dispatch apply it. The cron is the only trigger that ever sees a label somebody edited
    in the web UI. GH_TOKEN from secrets.LABELSYNC_TOKEN at job level, permissions: contents: read, timeout-minutes: 30, serialised per ref and never cancelled. Append-only — no prune.
  • The binary is built from the checkout, not installed from a release, so the run exercises the
    labelsync in the commit under test.
  • renames: in labels.yml — bug → type: bug and enhancement → type: feature. That is
    the decision the issue's last box asked for: a rename is a PATCH, so the label keeps its id and
    its issues, where a delete and a create would look identical in the label list and strip it from
    all of them. Both entries are inert here — the targets exist, so the planner skips them — and that
    is the point: they migrate the next repository the catalogue covers.
  • New tests over the workflow, in the shape release_test.go uses for goreleaser: the three
    triggers and their paths, the dry-run check gated to pull requests, the apply not being a second
    dry run and never pruning, GH_TOKEN coming from the PAT secret, no --token and no
    GITHUB_TOKEN anywhere, permissions narrowed to contents: read, and a timeout long enough for
    a paced apply. Plus TestCatalogue_MigratesGitHubsStockLabels pinning the two renames.
  • Docs — usage/ci.md mirrors the workflow this repository runs and says where the copyable
    version differs, and gains a rotation burden section and a not a required status check section.
    architecture/authentication.md gains What CI resolves to, and what comes after it: the App as a
    fifth step in the same resolver, which is what makes it a decision rather than a migration.
    design.md § CI integration is marked landed; usage/configuration.md points at the live renames.

Two things to know before merging

  • LABELSYNC_TOKEN does not exist yet. Until it does the job annotates a warning and skips
    rather than failing, and it is deliberately not a required status check: a fork's pull request
    never sees the secret, and paths: means the job does not run on most pull requests at all. A red
    X on every pull request until somebody creates the secret is worse than a loud skip.

  • The first apply will recolour three labels. Configured colours are reserved, and three stock
    leftovers are sitting on them:

    ~  recolour  bug            #936d1f   (displaced by "type: bug")
    ~  recolour  documentation  #13ec80   (displaced by "area: docs")
    ~  recolour  enhancement    #a50d73   (displaced by "type: feature")
    

    Every stock label here is unused (0 issues, 0 pull requests), so the tidier outcome is to remove
    them once with labelsync sync --mode prune --prune all, after which the apply is a clean no-op.
    That deletes live labels, so this branch does not do it.

Closes #48

`bug` and `enhancement` exist in every new GitHub repository, and this
catalogue's own `type: bug` and `type: feature` are where they belong. Declaring
them as renames rather than leaving them as prune candidates keeps a label's
identity: a rename is a PATCH, so every issue and pull request already carrying
the label still carries it, where a delete and a create would look the same in
the label list and silently unlabel all of them.

On specsnl/labelsync both entries are inert — the targets already exist, so the
planner skips them — and that is what makes them worth committing: they are what
migrates the next repository the catalogue covers instead of unlabelling its
issues.
labelsync becomes its own first user. A pull request touching labels.yml gets
`sync --dry-run --output=json`, which exits 2 and fails the job when the
committed config and the live labels disagree; a merge to main and a weekly cron
apply it. The scheduled run is the only trigger that ever sees a label somebody
edited in the web UI, and it is a no-op whenever there is nothing to fix.

The binary is built from the checkout rather than installed from a release, so
the run exercises the labelsync in the commit under test.

Two things the job does that the documented recipe does not, both because this
workflow has to survive contexts a copied one need not:

- It checks for the token first and annotates a warning rather than failing when
  it is absent. A fork's pull request never sees the secret, and a red X on every
  pull request until somebody creates it is worse than a loud skip. It is not a
  required status check for the same reason, and because `paths:` means it does
  not run on most pull requests at all.
- Runs are serialised per ref and never cancelled: an apply halfway through its
  writes has to finish.

The job is append-only. Pruning stays a deliberate manual act.
)

The CI page's workflow now mirrors the one this repository runs, and says where
the two deliberately differ. The PAT's rotation burden gets a section of its own:
nothing can warn as the expiry approaches, because a token is an opaque string
until a request is made with it, so the mitigation is a date written down and a
scheduled-failure email nobody filters away.

The GitHub App is recorded as the later option and why it can wait — an
installation token is a fifth step in the same resolver, or a value handed to the
first one, and either way it resolves to the same Token and no call site changes.
The chain is what makes it a decision rather than a migration.
@Ilyes512
Ilyes512 merged commit 6f4aec6 into main Aug 12, 2026
6 checks passed
@Ilyes512
Ilyes512 deleted the feat/GH-48-dogfood-ci branch August 12, 2026 09:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dogfood: run labelsync against specsnl from CI

1 participant