diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..aad08f7 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,55 @@ +# 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 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. +version: 2 +updates: + - package-ecosystem: "github-actions" + 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" + include: scope + cooldown: + 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: "build" + include: scope + cooldown: + 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: "build" + include: scope + cooldown: + default-days: 7 + open-pull-requests-limit: 25 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..c063edc --- /dev/null +++ b/.github/workflows/gate.yml @@ -0,0 +1,34 @@ +# 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] + # `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; +# 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