|
| 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