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
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,9 @@ Run `make repo-settings` to reconcile your GitHub repository with the organizati
It configures:

- **Labels** — creates/updates the standard set of issue and PR labels
- **Merge strategy** — merge commits only by default (configurable via `REPO_ALLOW_MERGE_COMMIT`, `REPO_ALLOW_SQUASH_MERGE`, `REPO_ALLOW_REBASE_MERGE`), auto-merge enabled, delete branch on merge
- **Merge strategy** — merge commits only by default, configurable via `REPO_ALLOW_MERGE_COMMIT`, `REPO_ALLOW_SQUASH_MERGE`, `REPO_ALLOW_REBASE_MERGE` (these also restrict the ruleset's allowed merge methods; at least one must be enabled or `repo-settings` fails); auto-merge enabled, delete branch on merge
- **Secret scanning** — enabled
- **Branch protection** — a "protect-main" ruleset on the default branch (and any `REPO_RULESET_BRANCHES` patterns): requires PRs with 1 approval, dismisses stale reviews, requires review thread resolution, enforces commit signatures, prevents direct pushes/deletions/non-fast-forwards
- **Branch protection** — a "protect-main" ruleset on the default branch (and any `REPO_RULESET_BRANCHES` patterns): requires PRs with 1 approval, dismisses stale reviews, requires review thread resolution, enforces commit signatures, requires approval of the latest push when `REPO_REQUIRE_LAST_PUSH_APPROVAL` is `true`, prevents direct pushes/deletions/non-fast-forwards

The repository settings are configurable via make variables (set them in your `Makefile` or pass them on the command line, e.g. `make repo-settings REPO_STATUS_CHECKS='["CI","lint"]' REPO_RULESET_BRANCHES='["release/*"]'`):

Expand All @@ -111,6 +111,7 @@ The repository settings are configurable via make variables (set them in your `M
| `REPO_ALLOW_MERGE_COMMIT` | `true` | Allow merge commits in the merge strategy |
| `REPO_ALLOW_SQUASH_MERGE` | `false` | Allow squash merging |
| `REPO_ALLOW_REBASE_MERGE` | `false` | Allow rebase merging |
| `REPO_REQUIRE_LAST_PUSH_APPROVAL` | `false` | Require the most recent push to be approved before merging |
| `REPO_ADMIN_BYPASS` | `true` | When `false`, org admins cannot bypass the ruleset |
| `REPO_REQUIRED_APPROVING_REVIEW_COUNT` | `1` | Number of approving reviews required to merge |
| `REPO_REQUIRE_CODE_OWNER_REVIEW` | `false` | Require an approving review from code owners |
Expand Down
6 changes: 5 additions & 1 deletion common.mk
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ SETUP_ENVTEST ?= $(LOCALGOBIN)/setup-envtest
# adds further branch patterns (a JSON array, e.g. '["release/*"]'; short names are
# normalized to refs/heads/...). REPO_STATUS_CHECKS is a JSON array of status-check
# contexts that must pass (each job name is used as-is, so contexts with spaces work).
# REPO_ALLOW_MERGE_COMMIT/SQUASH_MERGE/REBASE_MERGE configure the merge strategy.
# REPO_ALLOW_MERGE_COMMIT/SQUASH_MERGE/REBASE_MERGE configure the merge strategy and
# the ruleset's allowed merge methods; at least one must be `true` (repo-settings fails otherwise).
# REPO_REQUIRE_LAST_PUSH_APPROVAL requires the most recent push to be approved before merging.
# Booleans must be `true` or `false`. Example:
# make repo-settings REPO_ADMIN_BYPASS=false REPO_STATUS_CHECKS='["CI","Check action pins"]' REPO_RULESET_BRANCHES='["release/*"]'
REPO_ADMIN_BYPASS ?= true
Expand All @@ -69,6 +71,7 @@ REPO_RULESET_BRANCHES ?= []
REPO_ALLOW_MERGE_COMMIT ?= true
REPO_ALLOW_SQUASH_MERGE ?= false
REPO_ALLOW_REBASE_MERGE ?= false
REPO_REQUIRE_LAST_PUSH_APPROVAL ?= false

.PHONY: repo-settings
repo-settings: ## Reconcile GitHub repository settings (labels, merge strategy, branch protection, security)
Expand All @@ -81,6 +84,7 @@ repo-settings: ## Reconcile GitHub repository settings (labels, merge strategy,
REPO_REQUIRE_BRANCH_UP_TO_DATE='$(REPO_REQUIRE_BRANCH_UP_TO_DATE)' \
REPO_REQUIRE_CODE_OWNER_REVIEW='$(REPO_REQUIRE_CODE_OWNER_REVIEW)' \
REPO_REQUIRED_APPROVING_REVIEW_COUNT='$(REPO_REQUIRED_APPROVING_REVIEW_COUNT)' \
REPO_REQUIRE_LAST_PUSH_APPROVAL='$(REPO_REQUIRE_LAST_PUSH_APPROVAL)' \
REPO_RULESET_BRANCHES='$(REPO_RULESET_BRANCHES)' \
REPO_STATUS_CHECKS='$(REPO_STATUS_CHECKS)' \
DEV_KIT_VERSION='$(DEV_KIT_VERSION)' \
Expand Down
2 changes: 1 addition & 1 deletion docs/NEW_REPO.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Run:
make repo-settings
```

This reconciles labels, merge strategy (merge commits only by default, configurable via the `REPO_ALLOW_*` variables; auto-merge enabled, delete branch on merge), secret scanning, and the `protect-main` branch ruleset. See `make help` for details.
This reconciles labels, merge strategy (merge commits only by default, configurable via the `REPO_ALLOW_*` variables, which also restrict the ruleset's allowed merge methods; at least one must be enabled; auto-merge enabled, delete branch on merge), last-push-approval requirements (`REPO_REQUIRE_LAST_PUSH_APPROVAL`), secret scanning, and the `protect-main` branch ruleset. See `make help` for details.

The branch protection ruleset is configurable via make variables, e.g.:

Expand Down
28 changes: 25 additions & 3 deletions scripts/repo-settings.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ set -euo pipefail
# REPO_REQUIRE_BRANCH_UP_TO_DATE require branches up to date (requires status checks)
# REPO_STATUS_CHECKS JSON array of required status-check contexts
# REPO_RULESET_BRANCHES JSON array of additional branch patterns
# REPO_ALLOW_MERGE_COMMIT allow merge commits in the merge strategy
# REPO_ALLOW_MERGE_COMMIT allow merge commits in the merge strategy and ruleset
# REPO_ALLOW_SQUASH_MERGE allow squash merging
# REPO_ALLOW_REBASE_MERGE allow rebase merging
# REPO_REQUIRE_LAST_PUSH_APPROVAL require the most recent push to be approved before merging
# DEV_KIT_VERSION dev-kit version to fetch the workflow from
# GH, JQ commands used to talk to GitHub and build JSON

Expand All @@ -43,6 +44,25 @@ if [ "$REPO_REQUIRE_BRANCH_UP_TO_DATE" = "true" ] &&
exit 1
fi

allowed_merge_methods=$(
# shellcheck disable=SC2016 # $variables belong to jq, not the shell
"$JQ" -cn \
--argjson merge "$REPO_ALLOW_MERGE_COMMIT" \
--argjson squash "$REPO_ALLOW_SQUASH_MERGE" \
--argjson rebase "$REPO_ALLOW_REBASE_MERGE" \
'[
if $merge then "merge" else empty end,
if $squash then "squash" else empty end,
if $rebase then "rebase" else empty end
]
'
)

if [ "$allowed_merge_methods" = "[]" ]; then
echo "error: at least one merge method must be allowed" >&2
exit 1
fi

echo "Reconciling settings for $REPO..."

echo " Syncing labels..."
Expand Down Expand Up @@ -94,6 +114,8 @@ RULESET_JSON=$(
--argjson codeOwner "$REPO_REQUIRE_CODE_OWNER_REVIEW" \
--argjson adminBypass "$REPO_ADMIN_BYPASS" \
--argjson upToDate "$REPO_REQUIRE_BRANCH_UP_TO_DATE" \
--argjson allowedMergeMethods "$allowed_merge_methods" \
--argjson requireLastPushApproval "$REPO_REQUIRE_LAST_PUSH_APPROVAL" \
'{ name: "protect-main", target: "branch", enforcement: "active",
conditions: { ref_name: { include: $branches, exclude: [] } },
rules: ([
Expand All @@ -106,9 +128,9 @@ RULESET_JSON=$(
dismiss_stale_reviews_on_push: true,
required_reviewers: [],
require_code_owner_review: $codeOwner,
require_last_push_approval: false,
require_last_push_approval: $requireLastPushApproval,
required_review_thread_resolution: true,
allowed_merge_methods: ["squash", "rebase", "merge"]
allowed_merge_methods: $allowedMergeMethods
} }
] + (if ($checks | length > 0) then
[{ type: "required_status_checks", parameters: {
Expand Down
Loading