ops(forgejo): apply-branch-protection script + main-branch rule
Codifies the branch protection applied to main on 2026-04-16: no
direct pushes, required checks = CI / {lint,test,validate-json}*,
zero approvals (2-person team), admin bypass left on for emergencies.
Script is idempotent (create-or-patch) and reads its token from
\$FORGEJO_TOKEN or the local git remote URL as a fallback, so a
clean re-run just reconciles the rule with branch-protection.json.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8498dd576f
commit
0f5e6bb950
2 changed files with 69 additions and 0 deletions
56
ops/forgejo/apply-branch-protection.sh
Executable file
56
ops/forgejo/apply-branch-protection.sh
Executable file
|
|
@ -0,0 +1,56 @@
|
|||
#!/usr/bin/env bash
|
||||
# Apply branch protection rules to Furtka's main branch on Forgejo.
|
||||
# Idempotent — re-runs safely (creates on first call, patches thereafter).
|
||||
#
|
||||
# Requires: jq, curl, and a Forgejo personal access token with repo write
|
||||
# scope. Token is read from $FORGEJO_TOKEN, or extracted from the local
|
||||
# git remote URL as a fallback.
|
||||
#
|
||||
# Usage:
|
||||
# FORGEJO_TOKEN=... ./ops/forgejo/apply-branch-protection.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
HOST="${FORGEJO_HOST:-forgejo.sourcegate.online}"
|
||||
REPO="${FORGEJO_REPO:-daniel/furtka}"
|
||||
BRANCH="${FORGEJO_BRANCH:-main}"
|
||||
|
||||
if [ -z "${FORGEJO_TOKEN:-}" ]; then
|
||||
FORGEJO_TOKEN=$(git config --get remote.origin.url \
|
||||
| sed -nE 's|https://[^:]+:([^@]+)@.*|\1|p')
|
||||
fi
|
||||
if [ -z "${FORGEJO_TOKEN:-}" ]; then
|
||||
echo "error: set FORGEJO_TOKEN or configure a token in remote.origin.url" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
here=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
|
||||
config="$here/branch-protection.json"
|
||||
base="https://${HOST}/api/v1/repos/${REPO}/branch_protections"
|
||||
|
||||
api() {
|
||||
curl --silent --show-error --fail-with-body \
|
||||
--header "Authorization: token ${FORGEJO_TOKEN}" \
|
||||
--header "Content-Type: application/json" \
|
||||
"$@"
|
||||
}
|
||||
|
||||
code=$(curl --silent --output /dev/null --write-out '%{http_code}' \
|
||||
--header "Authorization: token ${FORGEJO_TOKEN}" \
|
||||
"${base}/${BRANCH}")
|
||||
|
||||
case "$code" in
|
||||
200)
|
||||
echo "Updating existing protection on ${BRANCH}…"
|
||||
api --request PATCH "${base}/${BRANCH}" --data @"$config" | jq .
|
||||
;;
|
||||
404)
|
||||
echo "Creating protection on ${BRANCH}…"
|
||||
body=$(jq --arg b "$BRANCH" '. + {branch_name: $b}' "$config")
|
||||
api --request POST "${base}" --data "$body" | jq .
|
||||
;;
|
||||
*)
|
||||
echo "unexpected HTTP ${code} from ${base}/${BRANCH}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
13
ops/forgejo/branch-protection.json
Normal file
13
ops/forgejo/branch-protection.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"enable_push": false,
|
||||
"enable_status_check": true,
|
||||
"status_check_contexts": [
|
||||
"CI / lint*",
|
||||
"CI / test*",
|
||||
"CI / validate-json*"
|
||||
],
|
||||
"required_approvals": 0,
|
||||
"block_on_rejected_reviews": false,
|
||||
"block_on_outdated_branch": false,
|
||||
"require_signed_commits": false
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue