| order | 10 |
|---|
This walkthrough takes one repository from nothing to a settings file that is applied on every change: create the token, add the settings file and the workflow, run check mode first, then switch to apply. What each section of the settings file manages, and what applying it deletes or keeps, is specified in the Sections table; this page only gets you to a first green run.
The action authenticates with a fine-grained personal access token. Many sections need the Administration permission, which the default workflow GITHUB_TOKEN can never hold, so plan on a PAT.
The pre-filled token form starts you off with every repository permission the Sections table can need. Pick the resource owner and the repositories the token may touch. If the owner is an organization and you plan to manage the teams section, also add the Members organization permission at read; the form only offers organization permissions once an organization is selected.
You can also grant less. The token only needs the permissions for the sections your settings file declares, and Token permissions explains which grant maps to which section.
Save the token as a repository secret. The examples below call it ADMIN_TOKEN.
Settings live in .github/settings.yml by default (the settings-file input moves it). A comment at the top wires editor autocomplete and hover documentation to the published JSON Schema. A small first file:
# yaml-language-server: $schema=https://raw.githubusercontent.com/Vivswan/github-settings-as-code/v2/lib/settings.schema.json # x-release-please-major
repository:
description: Payments service
has_wiki: false
delete_branch_on_merge: true
labels:
- name: bug
color: "d73a4a"
description: Something isn't workingOnly declared keys are ever applied or compared, so everything this file does not mention stays as it is. The exceptions are the sections the Sections table marks as deleting undeclared entries: declaring labels, autolinks, collaborators, actions_variables, or agents_variables makes the declared list authoritative, and live entries missing from it are deleted on apply. That is why the first run below is a check, not an apply.
The action reads the settings file from the workspace, so the workflow needs actions/checkout before the action step.
# .github/workflows/settings.yml
name: Apply settings
on:
push:
branches: [main]
paths: [.github/settings.yml]
schedule:
- cron: "23 6 * * 1"
workflow_dispatch:
permissions:
contents: read
jobs:
apply:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: Vivswan/github-settings-as-code@v2 # x-release-please-major
with:
token: ${{ secrets.ADMIN_TOKEN }}
mode: checkEach trigger earns its place:
pushruns the action on every reviewed change to the settings file: a check whilemode: checkis set, an apply once step 5 removes it.workflow_dispatchlets you run the action by hand from the Actions tab, which is how the first run happens.schedulecatches drift. In check mode a weekly run turns red when the live settings diverge from the file, and after the switch to apply it re-asserts the declared keys and reverts anything changed through the UI in the meantime (apply is convergent, see Semantics).
The @v2 pin is the moving major tag, stable within its line; @latest is a moving tag on the packaged commit of the newest main commit (main itself is source-only), where breaking changes arrive unannounced, so keep production on the major pin.
mode: check compares the declared settings against the live repository, makes no settings changes, and exits 1 when anything differs. Trigger the workflow from the Actions tab.
On a repository with existing labels the run will fail with drift, and that is the point: the report lists exactly what an apply would change or delete. The log shows one line per difference:
drift: repository.description: "Payments service" != ""
drift: labels[bug].color: declared "d73a4a" != live "ee0701"; apply will set the declared value
drift: labels[wontfix]: undeclared - not in the settings file, so apply will DELETE it; add it to the settings file to keep it
Work through the deletions first: add the labels you want to keep to the settings file, and leave out the ones you are happy to lose. Re-run check until the only remaining drift is change you intend.
Remove the mode: check line (the default is apply) and push, then run the workflow once from the Actions tab: the push that edits only the workflow file does not match the paths filter, so the first apply is a manual dispatch.
From then on every push that touches .github/settings.yml applies it, and the scheduled run keeps the repository converged. In apply mode the log shows what was written instead:
labels: created label "bug"
labels: DELETED undeclared label "wontfix"
result: applied
To keep a permanent drift-report workflow alongside the applying one, see the check mode guide.
Three surfaces carry the result, the same three the check mode guide describes:
- The log holds the per-drift and per-change lines shown above. Every run ends in a
result:line naming its outcome: for the check and apply runs on this page,applied,clean,drift,partial, orfailed. A failing run writes its error annotation first. - The step summary renders a table with one row per declared section: its status plus the same detail lines, so you rarely need to open the log at all.
- Annotations surface problems on the run page: errors carry the GitHub API's message verbatim plus the fix, warnings mark sections skipped under
on-missing-permission: warn, and notices carry advisory notes (for example thatenable_git_lfsis write-only, so check mode cannot verify it).
The action also sets a result output for downstream steps; the Inputs and outputs page documents it alongside every input.
The examples cookbook has a full-featured settings file and the null semantics. Multi-repo mode scales this setup from one repository to a fleet. When a run fails, troubleshooting covers the common failure shapes.