From 1207faa8a455f24ab29137cc57466de0ac7bc717 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Sat, 15 Aug 2026 15:38:43 +0100 Subject: [PATCH 1/2] chore: adopt gt repo governance Adds the committed .gt-repo.yaml that declares this repository's governance, plus the files gt renders from it: Dependabot config for the three ecosystems detected here (github-actions, gomod, npm at /web), the PR gate caller, the weekly drift-repair caller, and Dependabot auto-merge. checks.required was seeded from the job names ci.yml already produces, so the gate waits on exactly the checks this repo already enforces. Branch protection needs a single required check, "PR / Gate", which aggregates the rest. That name never changes, so protection is configured once. --- .github/dependabot.yml | 37 ++++++++++++++ .github/workflows/dependabot-auto-merge.yml | 28 +++++++++++ .github/workflows/gate.yml | 28 +++++++++++ .github/workflows/gt-sync.yml | 25 ++++++++++ .gt-repo.yaml | 54 +++++++++++++++++++++ 5 files changed, 172 insertions(+) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/dependabot-auto-merge.yml create mode 100644 .github/workflows/gate.yml create mode 100644 .github/workflows/gt-sync.yml create mode 100644 .gt-repo.yaml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..b012a5f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,37 @@ +# Managed by gt — edit .gt-repo.yaml, then run `gt repo sync`. +# +# Shared policy (cooldown, commit-message prefix, schedule) lives in gt's +# template, not here, so changing it for every repo is a one-line edit in gt. +# +# The 3-day cooldown is the supply-chain guard: by the time a PR exists, +# the upstream release has been in the wild long enough to surface yanks and +# compromised publishers before an auto-merge-eligible PR lands on the default +# branch. +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + commit-message: + prefix: "ci(deps):" + cooldown: + default-days: 3 + + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "weekly" + commit-message: + prefix: "chore(deps):" + cooldown: + default-days: 3 + + - package-ecosystem: "npm" + directory: "/web" + schedule: + interval: "weekly" + commit-message: + prefix: "chore(deps):" + cooldown: + default-days: 3 diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml new file mode 100644 index 0000000..2325570 --- /dev/null +++ b/.github/workflows/dependabot-auto-merge.yml @@ -0,0 +1,28 @@ +# Managed by gt — edit .gt-repo.yaml, then run `gt repo sync`. +# +# Daily batch window for merging Dependabot's eligible bumps. The Dependabot +# cooldown (set in .github/dependabot.yml) is the supply-chain guard; this is +# the merge executor on top of it. +# +# Bumps above `minor` are left for human review. +# +# Known gap, not a bug: Dependabot PRs touching .github/workflows/** can never +# be merged here. There is no permissions: key granting GITHUB_TOKEN the +# `workflow` scope, so the github-actions ecosystem always needs a human or +# `gt repo fleet merge-pending`, which runs with your own credentials. +name: Dependabot auto-merge + +on: + schedule: + - cron: "0 1 * * *" + workflow_dispatch: + +# A called reusable workflow can only narrow the caller's token, never widen +# it, so the writes the merge job needs have to be granted here. +permissions: + contents: write + pull-requests: write + +jobs: + auto-merge: + uses: pedromvgomes/gt/.github/workflows/reusable-dependabot-auto-merge.yml@v0 diff --git a/.github/workflows/gate.yml b/.github/workflows/gate.yml new file mode 100644 index 0000000..ad893f4 --- /dev/null +++ b/.github/workflows/gate.yml @@ -0,0 +1,28 @@ +# Managed by gt — edit .gt-repo.yaml, then run `gt repo sync`. +# +# Thin caller. All gate logic lives in gt's reusable workflow, pinned to the +# moving v0 tag, so gate changes reach this repo without editing this file. +# That matters: GITHUB_TOKEN cannot write .github/workflows/**, so a workflow +# that had to be rewritten on every policy change could never self-update. +# +# Branch protection requires exactly one check: "PR / Gate". +# Reusable workflows report as " / ", which is why the +# caller job below is named PR and gt's called job is named Gate. +name: PR + +on: + pull_request: + branches: [main] + +# A called reusable workflow can only narrow these, never widen them. +# pull-requests: read is what lets the gate read the PR's own check results; +# without it the aggregation sees nothing and waits out the full timeout. +permissions: + contents: read + checks: read + statuses: read + pull-requests: read + +jobs: + PR: + uses: pedromvgomes/gt/.github/workflows/reusable-gate.yml@v0 diff --git a/.github/workflows/gt-sync.yml b/.github/workflows/gt-sync.yml new file mode 100644 index 0000000..01ef371 --- /dev/null +++ b/.github/workflows/gt-sync.yml @@ -0,0 +1,25 @@ +# Managed by gt — edit .gt-repo.yaml, then run `gt repo sync`. +# +# Weekly drift check and repair. Runs `gt repo sync`, and opens a PR only if +# something changed — it never pushes to main, so gt's own updates are +# reviewed by the gate like any other change. +# +# Workflow files are deliberately excluded: GITHUB_TOKEN cannot create or +# update anything under .github/workflows/**. When one of them has drifted the +# job reports it and asks for a local `gt repo fleet sync`, which runs with +# your own credentials. Because the callers pin the moving v0 tag, this is +# rare — gate logic changes need no file change at all. +name: gt sync + +on: + schedule: + - cron: "0 6 * * 1" + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + sync: + uses: pedromvgomes/gt/.github/workflows/reusable-sync.yml@v0 diff --git a/.gt-repo.yaml b/.gt-repo.yaml new file mode 100644 index 0000000..42fc2e4 --- /dev/null +++ b/.gt-repo.yaml @@ -0,0 +1,54 @@ +# Repository governance for gt. This file is the source of truth; run +# 'gt repo sync' to render it, and 'gt repo check' to verify. +# +# Shared policy (Dependabot cooldown, commit-message prefixes, the weekly sync +# schedule) lives in gt's templates, not here, so it stays consistent across +# every governed repo. +# +# checks.required lists the checks gt's gate waits on. Do not list the gate +# itself — it is the aggregator, and branch protection requires only it. + +gt_version: v0.7.0 +dependabot: + - ecosystem: github-actions + directory: / + - ecosystem: gomod + directory: / + - ecosystem: npm + directory: /web +checks: + timeout_minutes: 30 + required: + - build, vet & test + - dashboard bundle up to date + optional: [] +dependabot_auto_merge: + enabled: true + schedule: 0 1 * * * + max_bump: minor + delete_branch: true +conventional_commits: + enabled: true + scope: pr_title + types: + - feat + - fix + - chore + - ci + - docs + - refactor + - test +settings: + merge: + squash: true + merge_commit: false + rebase: false + delete_branch_on_merge: true + branch_protection: + branch: main + required_approvals: 0 + require_up_to_date: true +files: + - gate + - sync + - dependabot-auto-merge From 73ade3071426cae49f98a15488ef72cafcad1f72 Mon Sep 17 00:00:00 2001 From: Pedro Gomes Date: Sat, 15 Aug 2026 15:55:03 +0100 Subject: [PATCH 2/2] chore: adopt the settled dependabot and PR-title policy Re-rendered after gt's shared policy consolidated three different cooldowns and two prefix schemes into one: 7-day cooldown, build/ci prefixes with include: scope, and a 25 PR limit. The gate caller also gained the `edited` trigger, so a corrected PR title re-runs the check instead of staying red. --- .github/dependabot.yml | 32 +++++++++++++++++++++++++------- .github/workflows/gate.yml | 6 ++++++ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index b012a5f..aad08f7 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -3,7 +3,7 @@ # Shared policy (cooldown, commit-message prefix, schedule) lives in gt's # template, not here, so changing it for every repo is a one-line edit in gt. # -# The 3-day cooldown is the supply-chain guard: by the time a PR exists, +# The 7-day cooldown is the supply-chain guard: by the time a PR exists, # the upstream release has been in the wild long enough to surface yanks and # compromised publishers before an auto-merge-eligible PR lands on the default # branch. @@ -13,25 +13,43 @@ updates: directory: "/" schedule: interval: "weekly" + # Dependabot's commit message is also its PR title, and PRs are + # squash-merged, so the prefix is what keeps dependency updates inside + # Conventional Commits. `include: scope` appends the dependency scope, + # producing e.g. `ci(deps): bump …`. commit-message: - prefix: "ci(deps):" + prefix: "ci" + include: scope cooldown: - default-days: 3 + default-days: 7 + open-pull-requests-limit: 25 - package-ecosystem: "gomod" directory: "/" schedule: interval: "weekly" + # Dependabot's commit message is also its PR title, and PRs are + # squash-merged, so the prefix is what keeps dependency updates inside + # Conventional Commits. `include: scope` appends the dependency scope, + # producing e.g. `build(deps): bump …`. commit-message: - prefix: "chore(deps):" + prefix: "build" + include: scope cooldown: - default-days: 3 + default-days: 7 + open-pull-requests-limit: 25 - package-ecosystem: "npm" directory: "/web" schedule: interval: "weekly" + # Dependabot's commit message is also its PR title, and PRs are + # squash-merged, so the prefix is what keeps dependency updates inside + # Conventional Commits. `include: scope` appends the dependency scope, + # producing e.g. `build(deps): bump …`. commit-message: - prefix: "chore(deps):" + prefix: "build" + include: scope cooldown: - default-days: 3 + default-days: 7 + open-pull-requests-limit: 25 diff --git a/.github/workflows/gate.yml b/.github/workflows/gate.yml index ad893f4..c063edc 100644 --- a/.github/workflows/gate.yml +++ b/.github/workflows/gate.yml @@ -13,6 +13,12 @@ name: PR on: pull_request: branches: [main] + # `edited` is load-bearing when the PR title is enforced: without it, + # correcting a rejected title leaves the check red until an unrelated push. + # The gate runs no builds of its own — those live in the repo's own + # workflows with their own triggers — so re-running it on a title edit is + # cheap, and the aggregation step finds the other checks already concluded. + types: [opened, synchronize, reopened, edited, ready_for_review] # A called reusable workflow can only narrow these, never widen them. # pull-requests: read is what lets the gate read the PR's own check results;