mirror of
git://f0xx.org/android_cast
synced 2026-07-29 05:37:52 +03:00
gitea sync
This commit is contained in:
@@ -331,6 +331,40 @@ GITEA_SUBMODULES_CONF=/root/my-submodules.list sudo ./gitea_mirror_submodules.sh
|
|||||||
sudo -u gitea gitea -c /var/lib/gitea/custom/conf/app.ini admin repo-sync-mirrors
|
sudo -u gitea gitea -c /var/lib/gitea/custom/conf/app.ini admin repo-sync-mirrors
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Branch protection (`master`, `next` only)
|
||||||
|
|
||||||
|
Server-side rules per [docs/GIT_FLOW.md](../../../../docs/GIT_FLOW.md) §7. **Two places:**
|
||||||
|
|
||||||
|
| Where | Tool |
|
||||||
|
|-------|------|
|
||||||
|
| **Gitea** `AndroidCast/android_cast` | `gitea_protect_branches.sh` |
|
||||||
|
| **Canonical FE** `git://10.7.0.10/android_cast` | `examples/git/hooks/pre-receive.android_cast.example` |
|
||||||
|
|
||||||
|
**Gitea (BE):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ./examples/crash_reporter/backend/scripts/gitea/gitea_protect_branches.sh
|
||||||
|
sudo ./examples/crash_reporter/backend/scripts/gitea/gitea_protect_branches.sh --list
|
||||||
|
```
|
||||||
|
|
||||||
|
- `master` and `next` only (no `*` wildcard — `feature/*` stays free)
|
||||||
|
- Force-push **disabled for everyone**
|
||||||
|
- Push/merge allowlist: **admin**, **foxx**, org team **Owners**
|
||||||
|
- Admins cannot bypass merge rules
|
||||||
|
|
||||||
|
**FE bare repo** (primary enforcement for `git push origin`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# on FE, in bare repo hooks/
|
||||||
|
cp examples/git/hooks/pre-receive.android_cast.example \
|
||||||
|
/path/to/android_cast.git/hooks/pre-receive
|
||||||
|
chmod +x /path/to/android_cast.git/hooks/pre-receive
|
||||||
|
```
|
||||||
|
|
||||||
|
Rejects on `master` / `next`: branch delete, non-fast-forward (force-push). Other branches unchanged.
|
||||||
|
|
||||||
|
`gitea_polish_project.sh` runs branch protection automatically unless `GITEA_SKIP_BRANCH_PROTECT=1`.
|
||||||
|
|
||||||
## Polish (finish line — safe BE run)
|
## Polish (finish line — safe BE run)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -200,7 +200,12 @@ if command -v "$SCRIPT_DIR/gitea_set_default_branch.sh" >/dev/null 2>&1; then
|
|||||||
sh "$SCRIPT_DIR/gitea_set_default_branch.sh" || warn "default branch set failed (sync first)"
|
sh "$SCRIPT_DIR/gitea_set_default_branch.sh" || warn "default branch set failed (sync first)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 7) Summary
|
# 7) Branch protection (master, next)
|
||||||
|
if [ "${GITEA_SKIP_BRANCH_PROTECT:-0}" -eq 0 ]; then
|
||||||
|
sh "$SCRIPT_DIR/gitea_protect_branches.sh" || warn "branch protection failed — run manually"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 8) Summary
|
||||||
log "=== done ==="
|
log "=== done ==="
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
|
|
||||||
@@ -208,6 +213,8 @@ UI checklist:
|
|||||||
• foxx/admin: open ${GITEA_ROOT_URL%/}/$GITEA_ORG (org page — not only "Your repositories")
|
• foxx/admin: open ${GITEA_ROOT_URL%/}/$GITEA_ORG (org page — not only "Your repositories")
|
||||||
• Expect: android_cast, libvpx, opus, speex under $GITEA_ORG
|
• Expect: android_cast, libvpx, opus, speex under $GITEA_ORG
|
||||||
• If android_cast still stale: sudo ./gitea_diagnose_mirror_sync.sh
|
• If android_cast still stale: sudo ./gitea_diagnose_mirror_sync.sh
|
||||||
|
• Branch protection: master/next on Gitea; install FE hook:
|
||||||
|
examples/git/hooks/pre-receive.android_cast.example
|
||||||
• Email/2FA later: app.ini REGISTER_EMAIL_CONFIRM=false; add SMTP when ready
|
• Email/2FA later: app.ini REGISTER_EMAIL_CONFIRM=false; add SMTP when ready
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
|
|||||||
172
examples/crash_reporter/backend/scripts/gitea/gitea_protect_branches.sh
Executable file
172
examples/crash_reporter/backend/scripts/gitea/gitea_protect_branches.sh
Executable file
@@ -0,0 +1,172 @@
|
|||||||
|
#!/bin/ash
|
||||||
|
#
|
||||||
|
# Server-side protection for master and next on Gitea (android_cast).
|
||||||
|
# Blocks force-push for everyone; push/merge limited to org Owners (admin, foxx).
|
||||||
|
# Side branches (feature/*, fix/*) are unaffected — no wildcard rule.
|
||||||
|
#
|
||||||
|
# Usage (BE as root):
|
||||||
|
# sudo ./gitea_protect_branches.sh
|
||||||
|
# GITEA_OWNER=AndroidCast GITEA_REPO=android_cast sudo ./gitea_protect_branches.sh
|
||||||
|
# sudo ./gitea_protect_branches.sh --list
|
||||||
|
#
|
||||||
|
# Note: canonical git on FE (git://10.7.0.10/android_cast) needs its own hook —
|
||||||
|
# see examples/git/hooks/pre-receive.android_cast.example
|
||||||
|
#
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
# shellcheck source=gitea_ini.sh
|
||||||
|
. "$SCRIPT_DIR/gitea_ini.sh"
|
||||||
|
# shellcheck source=gitea_mirror_lib.sh
|
||||||
|
. "$SCRIPT_DIR/gitea_mirror_lib.sh"
|
||||||
|
|
||||||
|
GITEA_OWNER="${GITEA_OWNER:-${GITEA_ORG:-AndroidCast}}"
|
||||||
|
GITEA_REPO="${GITEA_REPO:-android_cast}"
|
||||||
|
# Space-separated branches to protect (exact names only).
|
||||||
|
GITEA_PROTECT_BRANCHES="${GITEA_PROTECT_BRANCHES:-master next}"
|
||||||
|
# Users allowed to push (fast-forward / merge) to protected branches.
|
||||||
|
GITEA_PROTECT_PUSH_USERS="${GITEA_PROTECT_PUSH_USERS:-admin foxx}"
|
||||||
|
# Org team with push access (AndroidCast Owners).
|
||||||
|
GITEA_PROTECT_PUSH_TEAM="${GITEA_PROTECT_PUSH_TEAM:-Owners}"
|
||||||
|
|
||||||
|
log() { printf '[gitea-protect] %s\n' "$*"; }
|
||||||
|
warn() { printf '[gitea-protect] WARN: %s\n' "$*" >&2; }
|
||||||
|
die() { printf '[gitea-protect] ERROR: %s\n' "$*" >&2; exit 1; }
|
||||||
|
|
||||||
|
gitea_api_token() {
|
||||||
|
_t="${GITEA_ADMIN_TOKEN:-}"
|
||||||
|
[ -n "$_t" ] || _t="$(gitea_resolve_push_token)" || return 1
|
||||||
|
printf '%s' "$_t"
|
||||||
|
}
|
||||||
|
|
||||||
|
gitea_list_branch_protections() {
|
||||||
|
command -v curl >/dev/null 2>&1 || return 1
|
||||||
|
_token="$(gitea_api_token)" || return 1
|
||||||
|
_api="$(gitea_api_base)"
|
||||||
|
curl -sS "$_api/repos/$GITEA_OWNER/$GITEA_REPO/branch_protections" \
|
||||||
|
-H "Authorization: token $_token"
|
||||||
|
}
|
||||||
|
|
||||||
|
gitea_protection_exists() {
|
||||||
|
_branch="$1"
|
||||||
|
gitea_list_branch_protections 2>/dev/null | grep -q "\"branch_name\":\"$_branch\""
|
||||||
|
}
|
||||||
|
|
||||||
|
gitea_protect_payload() {
|
||||||
|
_branch="$1"
|
||||||
|
_prio="$2"
|
||||||
|
_users_json=""
|
||||||
|
for _u in $GITEA_PROTECT_PUSH_USERS; do
|
||||||
|
[ -n "$_u" ] || continue
|
||||||
|
_users_json="$_users_json\"$_u\","
|
||||||
|
done
|
||||||
|
_users_json="${_users_json%,}"
|
||||||
|
|
||||||
|
cat <<EOF
|
||||||
|
{
|
||||||
|
"rule_name": "$_branch",
|
||||||
|
"branch_name": "$_branch",
|
||||||
|
"priority": $_prio,
|
||||||
|
"enable_push": true,
|
||||||
|
"enable_push_whitelist": true,
|
||||||
|
"push_whitelist_usernames": [$_users_json],
|
||||||
|
"push_whitelist_teams": ["$GITEA_PROTECT_PUSH_TEAM"],
|
||||||
|
"enable_force_push": false,
|
||||||
|
"enable_force_push_allowlist": false,
|
||||||
|
"block_admin_merge_override": true
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
gitea_apply_protection() {
|
||||||
|
_branch="$1"
|
||||||
|
_prio="$2"
|
||||||
|
command -v curl >/dev/null 2>&1 || return 1
|
||||||
|
_token="$(gitea_api_token)" || return 1
|
||||||
|
_api="$(gitea_api_base)"
|
||||||
|
_payload="$(gitea_protect_payload "$_branch" "$_prio")"
|
||||||
|
_resp="$(mktemp /tmp/gitea-protect-XXXXXX.json)"
|
||||||
|
|
||||||
|
if gitea_protection_exists "$_branch"; then
|
||||||
|
log "update protection: $GITEA_OWNER/$GITEA_REPO::$_branch"
|
||||||
|
_http="$(curl -sS -o "$_resp" -w '%{http_code}' \
|
||||||
|
-X PATCH "$_api/repos/$GITEA_OWNER/$GITEA_REPO/branch_protections/$_branch" \
|
||||||
|
-H "Authorization: token $_token" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "$_payload")"
|
||||||
|
else
|
||||||
|
log "create protection: $GITEA_OWNER/$GITEA_REPO::$_branch"
|
||||||
|
_http="$(curl -sS -o "$_resp" -w '%{http_code}' \
|
||||||
|
-X POST "$_api/repos/$GITEA_OWNER/$GITEA_REPO/branch_protections" \
|
||||||
|
-H "Authorization: token $_token" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "$_payload")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$_http" in
|
||||||
|
200|201|204) gitea_rm_path "$_resp"; return 0 ;;
|
||||||
|
*)
|
||||||
|
warn "HTTP $_http for $_branch:"
|
||||||
|
head -c 500 "$_resp" >&2 2>/dev/null || true
|
||||||
|
printf '\n' >&2
|
||||||
|
gitea_rm_path "$_resp"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
list_protections() {
|
||||||
|
gitea_load_config || exit 1
|
||||||
|
gitea_ensure_cli_access || exit 1
|
||||||
|
log "branch protections: $GITEA_OWNER/$GITEA_REPO"
|
||||||
|
gitea_list_branch_protections | tr ',' '\n' | grep -E 'branch_name|enable_force_push|enable_push' || true
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- main ---
|
||||||
|
|
||||||
|
case "${1:-}" in
|
||||||
|
-h|--help|help)
|
||||||
|
sed -n '2,16p' "$0"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
--list|list)
|
||||||
|
list_protections
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
gitea_load_config || exit 1
|
||||||
|
gitea_ensure_cli_access || exit 1
|
||||||
|
|
||||||
|
if ! gitea_repo_exists_api "$GITEA_OWNER" "$GITEA_REPO"; then
|
||||||
|
die "repo $GITEA_OWNER/$GITEA_REPO not found — run gitea_polish_project.sh first"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "repo=$GITEA_OWNER/$GITEA_REPO branches=$GITEA_PROTECT_BRANCHES"
|
||||||
|
log "push allowlist: users=$GITEA_PROTECT_PUSH_USERS team=$GITEA_PROTECT_PUSH_TEAM"
|
||||||
|
log "force-push: disabled for all | side branches: unprotected"
|
||||||
|
|
||||||
|
_prio=1
|
||||||
|
_fail=0
|
||||||
|
for _b in $GITEA_PROTECT_BRANCHES; do
|
||||||
|
gitea_apply_protection "$_b" "$_prio" || _fail=1
|
||||||
|
_prio=$((_prio + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
cat <<EOF
|
||||||
|
|
||||||
|
Gitea rules applied. Verify in UI:
|
||||||
|
$GITEA_OWNER/$GITEA_REPO → Settings → Branches
|
||||||
|
|
||||||
|
Protected: master, next only
|
||||||
|
• No force-push (anyone)
|
||||||
|
• Push/merge: $GITEA_PROTECT_PUSH_USERS + team $GITEA_PROTECT_PUSH_TEAM
|
||||||
|
• Admins cannot bypass (block_admin_merge_override)
|
||||||
|
|
||||||
|
IMPORTANT — canonical origin on FE is separate:
|
||||||
|
Install examples/git/hooks/pre-receive.android_cast.example on the bare repo
|
||||||
|
at git://10.7.0.10/android_cast (hooks/pre-receive).
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
[ "$_fail" -eq 0 ]
|
||||||
70
examples/git/hooks/pre-receive.android_cast.example
Normal file
70
examples/git/hooks/pre-receive.android_cast.example
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Canonical bare repo hook: git://10.7.0.10/android_cast
|
||||||
|
# Install on FE (or wherever the bare repo lives):
|
||||||
|
# cp pre-receive.android_cast.example /path/to/android_cast.git/hooks/pre-receive
|
||||||
|
# chmod +x /path/to/android_cast.git/hooks/pre-receive
|
||||||
|
#
|
||||||
|
# Protects master and next only:
|
||||||
|
# - reject branch deletion (git push origin :master)
|
||||||
|
# - reject non-fast-forward / force-push
|
||||||
|
# Side branches (feature/*, fix/*, hotfix/*) are not listed — any push allowed.
|
||||||
|
#
|
||||||
|
# Optional: restrict who may update master/next (SSH user name in AUTH_USER
|
||||||
|
# or GL_USERNAME depending on git daemon setup). Uncomment ALLOWED_USERS block.
|
||||||
|
#
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
PROTECTED_BRANCHES="master next"
|
||||||
|
# ALLOWED_USERS="foxx admin git"
|
||||||
|
|
||||||
|
zero="0000000000000000000000000000000000000000"
|
||||||
|
|
||||||
|
is_protected() {
|
||||||
|
for _p in $PROTECTED_BRANCHES; do
|
||||||
|
[ "$1" = "$_p" ] && return 0
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Optional user gate (uncomment ALLOWED_USERS above to enable)
|
||||||
|
check_user() {
|
||||||
|
[ -z "${ALLOWED_USERS:-}" ] && return 0
|
||||||
|
_u="${GL_USERNAME:-${AUTH_USER:-${USER:-}}}"
|
||||||
|
for _a in $ALLOWED_USERS; do
|
||||||
|
[ "$_u" = "$_a" ] && return 0
|
||||||
|
done
|
||||||
|
echo "hooks: user '$_u' not allowed to update protected branches" >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
while read -r oldrev newrev refname; do
|
||||||
|
case "$refname" in
|
||||||
|
refs/heads/*) ;;
|
||||||
|
*) continue ;;
|
||||||
|
esac
|
||||||
|
branch="${refname#refs/heads/}"
|
||||||
|
is_protected "$branch" || continue
|
||||||
|
|
||||||
|
check_user || exit 1
|
||||||
|
|
||||||
|
# Deletion
|
||||||
|
if [ "$newrev" = "$zero" ]; then
|
||||||
|
echo "hooks: refusing to delete protected branch '$branch'" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# New branch creation on protected name (allow only if empty repo edge case)
|
||||||
|
if [ "$oldrev" = "$zero" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Non-fast-forward => force-push or history rewrite
|
||||||
|
if ! git merge-base --is-ancestor "$oldrev" "$newrev" 2>/dev/null; then
|
||||||
|
echo "hooks: refusing non-fast-forward push to protected branch '$branch'" >&2
|
||||||
|
echo "hooks: use feature/* branch + merge (see docs/GIT_FLOW.md)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
exit 0
|
||||||
Reference in New Issue
Block a user