Repository navigation
Expand file tree
/
Copy pathsetup-github.sh
More file actions
executable file
·150 lines (135 loc) · 6.01 KB
/
Copy pathsetup-github.sh
File metadata and controls
executable file
·150 lines (135 loc) · 6.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#!/usr/bin/env bash
# One-time GitHub setup: branch protection + auto-merge.
# This is your last line of defence if the agent misbehaves.
# Run it once and forget it.
#
# Two ways to run it — both need ADMIN permission on the repo:
# In the container (no host gh login needed):
# security add-generic-password -s gh-admin -a "$USER" -w '<admin PAT>'
# ./run.sh --github-setup
# On the host, with your own gh session:
# ./setup-github.sh
set -euo pipefail
command -v gh >/dev/null || { echo "error: gh CLI not found"; exit 1; }
gh auth status >/dev/null 2>&1 || { echo "error: no gh credentials (login with 'gh auth login' or provide GH_TOKEN)"; exit 1; }
REPO="$(gh repo view --json nameWithOwner -q .nameWithOwner)"
CHECK="${CHECK:-}" # empty = auto-detect from the checks that ran on main
# ── Resolve the required status check name ───────────────────────────────────
# Branch protection that requires a check which never reports = nothing ever
# merges, silently. So instead of guessing, ask GitHub which checks actually
# ran on main and validate/auto-detect against that list.
#
# Source: Actions job names via the workflow-runs API (a job's name IS its
# status-check context). Not the check-runs API — fine-grained PATs have no
# "Checks" permission, but "Actions: Read-only" covers this.
detect_checks() {
gh api "repos/$REPO/actions/runs?branch=main&per_page=10" \
--jq '.workflow_runs[].id' 2>/dev/null \
| head -5 \
| while read -r run_id; do
gh api "repos/$REPO/actions/runs/$run_id/jobs?per_page=100" \
--jq '.jobs[].name' 2>/dev/null || true
done | sort -u
}
NAMES="$(detect_checks || true)"
# CHECK accepts a comma-separated list: CHECK="Lint & Format,Tests (3.12)".
# IMPORTANT: only require checks that run on EVERY pull request. A job that
# only runs on main, tags or releases (deploy, release-please, publish...)
# will never report on a PR — requiring it means nothing can ever merge.
CHECK_LIST=()
if [[ -n "$CHECK" ]]; then
IFS=',' read -r -a CHECK_LIST <<<"$CHECK"
for i in "${!CHECK_LIST[@]}"; do
CHECK_LIST[$i]="$(echo "${CHECK_LIST[$i]}" | sed 's/^ *//; s/ *$//')"
done
for c in "${CHECK_LIST[@]}"; do
if [[ -n "$NAMES" ]] && ! grep -qxF "$c" <<<"$NAMES"; then
echo "error: no check named '$c' has reported on main." >&2
echo "Checks seen on main:" >&2
sed 's/^/ - /' <<<"$NAMES" >&2
echo "Re-run with CHECK set to one or more of the above (comma-separated)." >&2
exit 1
fi
done
elif [[ -n "$NAMES" ]] && grep -qxF "ci" <<<"$NAMES"; then
CHECK_LIST=(ci)
elif [[ -n "$NAMES" && "$(wc -l <<<"$NAMES" | tr -d ' ')" == "1" ]]; then
CHECK_LIST=("$NAMES")
echo "note: auto-detected required check '$NAMES' (the only check reporting on main)"
elif [[ -z "$NAMES" ]]; then
CHECK_LIST=(ci)
echo "note: no check runs found on main yet — defaulting to 'ci'."
echo " If your CI job is named differently, re-run with CHECK=<name>."
else
echo "error: several checks report on main and none is named 'ci':" >&2
sed 's/^/ - /' <<<"$NAMES" >&2
echo "Pick the one(s) that must gate merges — comma-separated, and ONLY jobs" >&2
echo "that run on every pull request (never release/deploy-only jobs):" >&2
echo " CHECK=\"Lint & Format,Tests (3.12)\" ./run.sh --github-setup" >&2
exit 1
fi
CONTEXTS_JSON="$(printf '"%s",' "${CHECK_LIST[@]}")"
CONTEXTS_JSON="[${CONTEXTS_JSON%,}]"
echo "repo: $REPO"
echo "required checks: ${CHECK_LIST[*]}"
echo
if [[ "${AGENTLOOP_YES:-}" == "1" ]]; then
echo "AGENTLOOP_YES=1 — proceeding without confirmation."
else
read -rp "This will lock down main and enable auto-merge. Continue? [y/N] " ans
[[ "$ans" == "y" || "$ans" == "Y" ]] || { echo "aborted."; exit 0; }
fi
echo
echo "> branch protection (main)"
gh api -X PUT "repos/$REPO/branches/main/protection" \
--input - <<EOF
{
"required_status_checks": {
"strict": true,
"contexts": $CONTEXTS_JSON
},
"enforce_admins": false,
"required_pull_request_reviews": {
"required_approving_review_count": 0,
"dismiss_stale_reviews": false
},
"restrictions": null,
"allow_force_pushes": false,
"allow_deletions": false
}
EOF
echo " OK main protected: force push off, CI required"
echo
echo "> repository settings"
gh repo edit --enable-auto-merge --enable-squash-merge --delete-branch-on-merge
echo " OK auto-merge + squash + delete branch on merge"
echo
echo "> labels"
gh label create automated --color 0e8a16 --description "Opened by the agent, auto-merge when green" --force >/dev/null
gh label create blocked --color d93f0b --description "Agent is stuck, needs a human" --force >/dev/null
gh label create plan --color 1d76db --description "Change to PLAN.md, review before merging" --force >/dev/null
echo " OK automated, blocked, plan"
cat <<'EOF'
========================================================
Done. Two manual steps remain:
1) Give the agent token access to this repo.
ONE token serves all your agentloop projects — if you already have it,
just add this repo to its list:
github.com/settings/personal-access-tokens
-> your agent token -> Repository access -> add this repo
Creating it for the first time:
github.com/settings/personal-access-tokens/new
· Repository access -> Only select repositories -> your agentloop repos
· Permissions -> Contents: Read and write
· Permissions -> Pull requests: Read and write
· Permissions -> Actions: Read-only (CI verdict polling — note:
GitHub offers no "Checks" permission on fine-grained PATs)
· Select NOTHING else (no admin, no org scopes)
Then store it in the keychain:
security add-generic-password -s gh-agent -a "$USER" -w 'github_pat_...'
2) Let Actions open and merge pull requests:
Settings -> Actions -> General -> Workflow permissions
· Select "Read and write permissions"
· Check "Allow GitHub Actions to create and approve pull requests"
========================================================
EOF