Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ The included `common.mk` provides:
| `shellcheck` | Run shellcheck on shell scripts |
| `scan` | Scan for vulnerabilities using osv-scanner |
| `setup-local-cluster` | Create a Kind cluster for local development |
| `repo-settings` | Reconcile GitHub repository settings |

### Variables

Expand Down Expand Up @@ -87,6 +88,17 @@ cobra: $(COBRA)
$(COBRA) help
```

### Repository settings

Run `make repo-settings` to reconcile your GitHub repository with the organization's standard configuration. This target is idempotent and requires the `gh` CLI to be authenticated.

It configures:

- **Labels** — creates/updates the standard set of issue and PR labels
- **Merge strategy** — merge commits only (no squash or rebase), auto-merge enabled, delete branch on merge
- **Secret scanning** — enabled
- **Branch protection** — a "protect-main" ruleset on the default branch: requires PRs with 1 approval, dismisses stale reviews, requires review thread resolution, enforces commit signatures, prevents direct pushes/deletions/non-fast-forwards (org admins can bypass)

### Default git hooks

The dev shell installs the following git hooks automatically:
Expand Down
88 changes: 88 additions & 0 deletions common.mk
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ KUBECTL ?= kubectl
SHELLCHECK ?= shellcheck
YQ ?= yq

# External prerequisites (not managed by flake.nix or tools.lock)
GH ?= gh

OS := $(or $(shell $(GO) env GOOS 2>/dev/null), \
$(shell uname -s | tr '[:upper:]' '[:lower:]'))
ARCH := $(or $(shell $(GO) env GOARCH 2>/dev/null), \
Expand All @@ -44,6 +47,91 @@ OPENAPI_GEN ?= $(LOCALGOBIN)/openapi-gen
OSV_SCANNER ?= $(LOCALGOBIN)/osv-scanner
SETUP_ENVTEST ?= $(LOCALGOBIN)/setup-envtest

##@ Repository

define REPO_LABELS
bug;d73a4a;Something isn't working
documentation;0075ca;Improvements or additions to documentation
duplicate;cfd3d7;This issue or pull request already exists
enhancement;a2eeef;New feature or request
good first issue;7057ff;Good for newcomers
help wanted;008672;Extra attention is needed
invalid;e4e669;This doesn't seem right
question;37326e;Further information is requested
wontfix;ffffff;This will not be worked on
chore;ededed;A routine task or common potentially re-occurring task
feature;a2eeef;New feature or request
go;16e2e2;Pull requests that update go code
ok-to-helm;0e8a16;PR is allowed to build an publish helm chart
dependencies;0366d6;Pull requests that update a dependency file
github-actions;80c4c6;PR created via GitHub action
help-wanted;811857;Extra attention is needed
good-first-issue;7057ff;Good for newcomers
needs-triage;eab668;Issue that has not been reviewed
ok-to-image;0e8a16;PR is allowed to run container build
ok-to-test;0e8a16;PR is allowed to be tested
spike;b23adb;A task to research a question and resolve problems
endef
export REPO_LABELS

REPO_RULESET := { \
"name": "protect-main", \
"target": "branch", \
"enforcement": "active", \
"conditions": { "ref_name": { "include": ["~DEFAULT_BRANCH"], "exclude": [] } }, \
"rules": [ \
{ "type": "deletion" }, \
{ "type": "non_fast_forward" }, \
{ "type": "creation" }, \
{ "type": "required_signatures" }, \
{ "type": "pull_request", "parameters": { \
"required_approving_review_count": 1, \
"dismiss_stale_reviews_on_push": true, \
"required_reviewers": [], \
"require_code_owner_review": false, \
"require_last_push_approval": false, \
"required_review_thread_resolution": true, \
"allowed_merge_methods": ["squash", "rebase", "merge"] \
}} \
], \
"bypass_actors": [{ "actor_type": "OrganizationAdmin", "bypass_mode": "always" }] \
}

.PHONY: repo-settings
repo-settings: ## Reconcile GitHub repository settings (labels, merge strategy, branch protection, security)
@REPO=$$($(GH) repo view --json nameWithOwner -q .nameWithOwner) || { echo "error: not a GitHub repository or gh not authenticated"; exit 1; }; \
echo "Reconciling settings for $$REPO..."; \
\
echo " Syncing labels..."; \
echo "$$REPO_LABELS" | while IFS=';' read -r name color desc; do \
[ -z "$$name" ] && continue; \
$(GH) label create "$$name" --repo "$$REPO" --color "$$color" --description "$$desc" --force 2>/dev/null; \
done; \
\
echo " Configuring merge strategy..."; \
$(GH) api "repos/$$REPO" -X PATCH \
-f allow_merge_commit=true \
-f allow_squash_merge=false \
-f allow_rebase_merge=false \
-f delete_branch_on_merge=true \
-f allow_auto_merge=true > /dev/null; \
\
echo " Enabling secret scanning..."; \
$(GH) api "repos/$$REPO" -X PATCH \
--input <(echo '{"security_and_analysis":{"secret_scanning":{"status":"enabled"}}}') > /dev/null; \
\
echo " Configuring branch protection ruleset..."; \
existing=$$($(GH) api "repos/$$REPO/rulesets" -q '.[] | select(.name=="protect-main") | .id' 2>/dev/null); \
if [ -n "$$existing" ]; then \
$(GH) api "repos/$$REPO/rulesets/$$existing" -X PUT --input <(echo '$(REPO_RULESET)') > /dev/null; \
echo " Updated existing ruleset (id: $$existing)"; \
else \
$(GH) api "repos/$$REPO/rulesets" -X POST --input <(echo '$(REPO_RULESET)') > /dev/null; \
echo " Created new ruleset"; \
fi; \
\
echo "Done."

##@ General

# The help target prints out all targets with their descriptions organized
Expand Down
Loading