Skip to content

Commit 7ba14f9

Browse files
committed
chore: add branch ruleset template + apply script; release on every main push
1 parent 81e2ad0 commit 7ba14f9

3 files changed

Lines changed: 169 additions & 0 deletions

File tree

.github/workflows/release.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
name: Release
22

33
on:
4+
push:
5+
branches: [main]
46
workflow_dispatch:
57

68
jobs:

rulesets/template.json

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"name": "default-branch-protection",
3+
"target": "branch",
4+
"enforcement": "active",
5+
"conditions": {
6+
"ref_name": {
7+
"include": ["~DEFAULT_BRANCH"],
8+
"exclude": []
9+
}
10+
},
11+
"bypass_actors": [
12+
{
13+
"actor_id": 5,
14+
"actor_type": "RepositoryRole",
15+
"bypass_mode": "always"
16+
}
17+
],
18+
"rules": [
19+
{ "type": "deletion" },
20+
{ "type": "non_fast_forward" },
21+
{
22+
"type": "pull_request",
23+
"parameters": {
24+
"required_approving_review_count": 0,
25+
"dismiss_stale_reviews_on_push": true,
26+
"require_code_owner_review": false,
27+
"require_last_push_approval": false,
28+
"required_review_thread_resolution": false,
29+
"allowed_merge_methods": ["rebase"]
30+
}
31+
},
32+
{
33+
"type": "required_status_checks",
34+
"parameters": {
35+
"strict_required_status_checks_policy": false,
36+
"do_not_enforce_on_create": false,
37+
"required_status_checks": []
38+
}
39+
}
40+
]
41+
}

scripts/apply-rulesets.sh

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
#!/usr/bin/env bash
2+
# Apply branch rulesets + repo settings across jitsucom repos.
3+
#
4+
# Dry by default. Pass --apply to write.
5+
#
6+
# Required: gh auth status as a user with Admin on each target repo.
7+
# Idempotent: deletes existing ruleset named "default-branch-protection" before recreating.
8+
#
9+
# Usage:
10+
# scripts/apply-rulesets.sh # dry, all repos
11+
# scripts/apply-rulesets.sh --apply # write, all repos
12+
# scripts/apply-rulesets.sh --apply jitsu # write, single repo
13+
14+
set -euo pipefail
15+
16+
ORG=jitsucom
17+
RULESET_NAME=default-branch-protection
18+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
19+
TEMPLATE="$SCRIPT_DIR/../rulesets/template.json"
20+
21+
# Format: repo:policy:pipe-separated-check-contexts
22+
# Policy: flexible | pr-required | settings-only
23+
MATRIX=(
24+
"jitsu:flexible:✨ Lint & Test|🧪 Bulker Test|ai-review / ai-review"
25+
"jitsu-cloud-infra:flexible:ai-review / ai-review"
26+
"github-workflows:flexible:ai-review"
27+
"jitsu-bi:flexible:"
28+
"mongobetween:pr-required:tests|lint|salus"
29+
"websites:settings-only:"
30+
)
31+
32+
DRY=1
33+
TARGET=""
34+
for arg in "$@"; do
35+
case "$arg" in
36+
--apply) DRY=0 ;;
37+
--help|-h)
38+
sed -n '2,/^set -e/p' "$0" | sed 's/^# \{0,1\}//' | sed '$d'
39+
exit 0
40+
;;
41+
*) TARGET="$arg" ;;
42+
esac
43+
done
44+
45+
run() {
46+
if [ "$DRY" = "1" ]; then
47+
printf ' [dry] '; printf '%q ' "$@"; echo
48+
else
49+
"$@"
50+
fi
51+
}
52+
53+
apply_repo_settings() {
54+
local repo=$1
55+
echo "$repo: repo settings (auto-merge on, rebase only, delete branch on merge)"
56+
run gh api -X PATCH "/repos/$ORG/$repo" \
57+
-F allow_auto_merge=true \
58+
-F allow_rebase_merge=true \
59+
-F allow_squash_merge=false \
60+
-F allow_merge_commit=false \
61+
-F delete_branch_on_merge=true
62+
}
63+
64+
apply_ruleset() {
65+
local repo=$1 policy=$2 checks_csv=$3
66+
echo "$repo: ruleset ($policy)"
67+
68+
local reviews=0
69+
[ "$policy" = "pr-required" ] && reviews=1
70+
71+
local checks_json
72+
if [ -n "$checks_csv" ]; then
73+
checks_json=$(echo "$checks_csv" | tr '|' '\n' | jq -R '{context:.}' | jq -s .)
74+
else
75+
checks_json="[]"
76+
fi
77+
78+
local existing
79+
existing=$(gh api "/repos/$ORG/$repo/rulesets" --jq ".[] | select(.name==\"$RULESET_NAME\") | .id" 2>/dev/null || true)
80+
if [ -n "$existing" ]; then
81+
echo " existing ruleset id=$existing — replacing"
82+
run gh api -X DELETE "/repos/$ORG/$repo/rulesets/$existing"
83+
fi
84+
85+
local body
86+
body=$(jq --argjson reviews "$reviews" --argjson checks "$checks_json" '
87+
.rules |= map(
88+
if .type == "pull_request" then
89+
.parameters.required_approving_review_count = $reviews
90+
elif .type == "required_status_checks" then
91+
.parameters.required_status_checks = $checks
92+
else
93+
.
94+
end
95+
)
96+
' "$TEMPLATE")
97+
98+
if [ "$DRY" = "1" ]; then
99+
echo " [dry] POST /repos/$ORG/$repo/rulesets with body:"
100+
echo "$body" | sed 's/^/ /'
101+
else
102+
echo "$body" | gh api -X POST "/repos/$ORG/$repo/rulesets" --input - > /dev/null
103+
echo " ruleset created"
104+
fi
105+
}
106+
107+
for line in "${MATRIX[@]}"; do
108+
repo="${line%%:*}"
109+
rest="${line#*:}"
110+
policy="${rest%%:*}"
111+
checks="${rest#*:}"
112+
113+
if [ -n "$TARGET" ] && [ "$TARGET" != "$repo" ]; then
114+
continue
115+
fi
116+
117+
apply_repo_settings "$repo"
118+
if [ "$policy" != "settings-only" ]; then
119+
apply_ruleset "$repo" "$policy" "$checks"
120+
fi
121+
echo
122+
done
123+
124+
if [ "$DRY" = "1" ]; then
125+
echo "Dry run complete. Re-run with --apply to write."
126+
fi

0 commit comments

Comments
 (0)