- Fix option text handling to check for None instead of falsy - Improve HTML cleaning with html.unescape and better tag removal - Fix multi-line string in die() function - Add html module import for proper HTML entity handling Co-authored-by: iaretechnician <2749183+iaretechnician@users.noreply.github.com>
205 lines
8.1 KiB
Bash
205 lines
8.1 KiB
Bash
#!/usr/bin/env bash
|
|
#
|
|
# GSP GitHub Push Script
|
|
# ======================
|
|
# This script commits local changes in your GSP panel directory and pushes
|
|
# them to GitHub via a Pull Request.
|
|
#
|
|
# HOW IT WORKS:
|
|
# 1. Initializes git in the panel directory (if needed)
|
|
# 2. Commits all changes (excluding sensitive files like config.inc.php)
|
|
# 3. Creates a timestamped branch
|
|
# 4. Attempts to push to upstream repo (requires write access)
|
|
# 5. If no write access, creates/uses a fork and submits PR from there
|
|
#
|
|
# CONFIGURATION:
|
|
# Configure settings via environment variables or by editing the defaults below.
|
|
#
|
|
# ENVIRONMENT VARIABLES:
|
|
# - PANEL_DIR: Path to your GSP panel installation (default: /var/www/html/panel)
|
|
# - TOKEN_FILE: File containing GitHub Personal Access Token (default: ~/.github-token)
|
|
# - GITHUB_TOKEN: GitHub token directly (used if TOKEN_FILE doesn't exist)
|
|
# - UPSTREAM_REPO: Target repository in "owner/repo" format (default: GameServerPanel/GSP)
|
|
# - BR_PREFIX: Branch name prefix for PRs (default: panel-sync)
|
|
# - GIT_USER_NAME: Git commit author name (default: Server Sync Bot)
|
|
# - GIT_USER_EMAIL: Git commit author email (default: server-sync@local)
|
|
#
|
|
# GITHUB TOKEN SETUP:
|
|
# You need a GitHub Personal Access Token with 'repo' scope.
|
|
# Create one at: https://github.com/settings/tokens
|
|
#
|
|
# Option 1: Store in file (recommended):
|
|
# echo "your_token_here" > ~/.github-token
|
|
# chmod 600 ~/.github-token
|
|
#
|
|
# Option 2: Use environment variable:
|
|
# export GITHUB_TOKEN="your_token_here"
|
|
#
|
|
# EXAMPLE USAGE:
|
|
# # Use defaults:
|
|
# ./push_to_github.sh
|
|
#
|
|
# # Custom panel directory:
|
|
# PANEL_DIR=/home/panel/public_html ./push_to_github.sh
|
|
#
|
|
# # Using environment token:
|
|
# GITHUB_TOKEN="ghp_xxxx" ./push_to_github.sh
|
|
#
|
|
set -Eeuo pipefail
|
|
umask 022
|
|
|
|
# ---------- CONFIGURABLE SETTINGS ----------
|
|
PANEL_DIR="${PANEL_DIR:-/var/www/html/panel}"
|
|
TOKEN_FILE="${TOKEN_FILE:-$HOME/.github-token}"
|
|
|
|
UPSTREAM_REPO="${UPSTREAM_REPO:-GameServerPanel/GSP}" # owner/repo
|
|
UPSTREAM_URL="https://github.com/${UPSTREAM_REPO}.git"
|
|
|
|
BR_PREFIX="${BR_PREFIX:-panel-sync}" # branch prefix for PRs
|
|
GIT_USER_NAME="${GIT_USER_NAME:-Server Sync Bot}"
|
|
GIT_USER_EMAIL="${GIT_USER_EMAIL:-server-sync@local}"
|
|
|
|
log(){ printf '[%s] %s\n' "$(date +'%F %T')" "$*"; }
|
|
die(){ echo "ERROR: $*" >&2; exit 1; }
|
|
|
|
# ---------- PRECHECKS ----------
|
|
[[ -d "$PANEL_DIR" ]] || die "Panel dir not found: $PANEL_DIR"
|
|
|
|
# Try to get token from file or environment
|
|
TOKEN=""
|
|
if [[ -s "$TOKEN_FILE" ]]; then
|
|
TOKEN="$(<"$TOKEN_FILE")"
|
|
elif [[ -n "${GITHUB_TOKEN:-}" ]]; then
|
|
TOKEN="$GITHUB_TOKEN"
|
|
else
|
|
die "GitHub token not found. Set GITHUB_TOKEN env var or create $TOKEN_FILE with your token. Get a token at: https://github.com/settings/tokens (requires 'repo' scope)"
|
|
fi
|
|
|
|
[[ ${#TOKEN} -ge 10 ]] || die "Token looks invalid (too short)"
|
|
|
|
cd "$PANEL_DIR"
|
|
if [[ ! -d ".git" ]]; then
|
|
log "No .git found here; initializing a repo."
|
|
git init
|
|
fi
|
|
|
|
git config --global --add safe.directory "$PANEL_DIR" || true
|
|
git config user.name "$GIT_USER_NAME"
|
|
git config user.email "$GIT_USER_EMAIL"
|
|
|
|
# ---------- SAFEGUARDS: ignore secrets/runtime ----------
|
|
ensure_ignore(){ grep -qxF "$1" .gitignore 2>/dev/null || echo "$1" >> .gitignore; }
|
|
touch .gitignore
|
|
ensure_ignore "includes/config.inc.php"
|
|
ensure_ignore "modules/billing/includes/config.inc.php"
|
|
ensure_ignore "templates_c/"
|
|
ensure_ignore "cache/"
|
|
ensure_ignore "logs/"
|
|
ensure_ignore "uploads/"
|
|
ensure_ignore "storage/"
|
|
ensure_ignore "tmp/"
|
|
ensure_ignore "modules/*/templates_c/"
|
|
ensure_ignore "modules/*/cache/"
|
|
ensure_ignore "modules/*/logs/"
|
|
ensure_ignore "modules/*/uploads/"
|
|
ensure_ignore "themes/*/dist/php/uploads/"
|
|
ensure_ignore "*.log"
|
|
ensure_ignore "*.bak"
|
|
ensure_ignore "*.orig"
|
|
ensure_ignore ".DS_Store"
|
|
ensure_ignore "*.zip"
|
|
ensure_ignore "*.tar"
|
|
ensure_ignore "*.tar.gz"
|
|
ensure_ignore "*.7z"
|
|
ensure_ignore "vendor/"
|
|
ensure_ignore "node_modules/"
|
|
|
|
# If secrets were ever tracked, stop tracking (keep files on disk)
|
|
git rm --cached -f includes/config.inc.php modules/billing/includes/config.inc.php 2>/dev/null || true
|
|
|
|
# ---------- XXL file check (>100MB rejected by GitHub) ----------
|
|
LARGE=$(find . -type f -not -path './.git/*' -size +100M -printf '%s\t%p\n' || true)
|
|
if [[ -n "$LARGE" ]]; then
|
|
echo "The following files exceed 100 MB and will be rejected by GitHub:"
|
|
echo "$LARGE" | awk '{printf " - %.2f MB %s\n", $1/1024/1024, $2}'
|
|
die "Remove or Git LFS these files before pushing."
|
|
fi
|
|
|
|
# ---------- Commit changes on a fresh branch ----------
|
|
git add -A
|
|
if git diff --cached --quiet; then
|
|
log "No changes to commit."
|
|
else
|
|
git commit -m "Panel sync: $(date +'%F %T %Z')"
|
|
fi
|
|
|
|
STAMP="$(date +%Y%m%d-%H%M%S)"
|
|
NEW_BRANCH="${BR_PREFIX}-${STAMP}"
|
|
git checkout -B "$NEW_BRANCH"
|
|
|
|
# ---------- Discover upstream default branch via API ----------
|
|
API_REPO_JSON="$(curl -fsSL -H "Authorization: token ${TOKEN}" \
|
|
"https://api.github.com/repos/${UPSTREAM_REPO}")" || die "Cannot reach GitHub API for ${UPSTREAM_REPO}"
|
|
BASE_BRANCH="$(printf '%s\n' "$API_REPO_JSON" | sed -n 's/.*"default_branch"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')"
|
|
[[ -n "$BASE_BRANCH" ]] || BASE_BRANCH="main"
|
|
|
|
# ---------- Try pushing branch directly to UPSTREAM ----------
|
|
AUTH_UPSTREAM_URL="https://${TOKEN}@github.com/${UPSTREAM_REPO}.git"
|
|
log "Attempting to push ${NEW_BRANCH} to upstream ${UPSTREAM_REPO} ..."
|
|
if git push "$AUTH_UPSTREAM_URL" "$NEW_BRANCH"; then
|
|
log "Pushed to upstream. Creating PR (same-repo head=${NEW_BRANCH} → base=${BASE_BRANCH}) ..."
|
|
PR_BODY="Automated push from ${HOSTNAME} at ${STAMP}."
|
|
PR_PAYLOAD=$(printf '{ "title":"%s","head":"%s","base":"%s","body":"%s" }' \
|
|
"Panel sync: ${STAMP}" "${NEW_BRANCH}" "${BASE_BRANCH}" "${PR_BODY}")
|
|
PR_RESP=$(curl -fsS -H "Authorization: token ${TOKEN}" \
|
|
-H "Accept: application/vnd.github+json" \
|
|
-X POST "https://api.github.com/repos/${UPSTREAM_REPO}/pulls" \
|
|
-d "$PR_PAYLOAD") || die "PR creation failed."
|
|
PR_URL=$(echo "$PR_RESP" | sed -n 's/.*"html_url":[[:space:]]*"\([^"]*\)".*/\1/p')
|
|
[[ -n "$PR_URL" ]] || { echo "$PR_RESP"; die "Could not parse PR URL."; }
|
|
echo "Pull Request created: $PR_URL"
|
|
exit 0
|
|
fi
|
|
|
|
# ---------- No push rights → fork to your account, push there, open PR ----------
|
|
log "No upstream push rights. Using your fork."
|
|
|
|
# Who am I?
|
|
ME_JSON="$(curl -fsSL -H "Authorization: token ${TOKEN}" https://api.github.com/user)" || die "Cannot fetch /user"
|
|
ME_LOGIN="$(printf '%s\n' "$ME_JSON" | sed -n 's/.*"login"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')"
|
|
[[ -n "$ME_LOGIN" ]] || die "Could not determine user login from token."
|
|
|
|
# Ensure fork exists (create if needed)
|
|
FORK_REPO="${ME_LOGIN}/GSP"
|
|
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: token ${TOKEN}" "https://api.github.com/repos/${FORK_REPO}")
|
|
if [[ "$HTTP_CODE" != "200" ]]; then
|
|
log "Creating fork ${FORK_REPO} ..."
|
|
curl -fsS -H "Authorization: token ${TOKEN}" \
|
|
-X POST "https://api.github.com/repos/${UPSTREAM_REPO}/forks" >/dev/null
|
|
# Wait for GitHub to finish fork
|
|
for i in {1..15}; do
|
|
sleep 2
|
|
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: token ${TOKEN}" "https://api.github.com/repos/${FORK_REPO}")
|
|
[[ "$HTTP_CODE" == "200" ]] && break
|
|
done
|
|
[[ "$HTTP_CODE" == "200" ]] || die "Fork did not become available."
|
|
fi
|
|
|
|
AUTH_FORK_URL="https://${TOKEN}@github.com/${FORK_REPO}.git"
|
|
log "Pushing branch ${NEW_BRANCH} to fork ${FORK_REPO} ..."
|
|
git push -u "$AUTH_FORK_URL" "$NEW_BRANCH"
|
|
|
|
# Create PR from fork: yourlogin:branch -> upstream:base
|
|
PR_BODY="Automated push from ${HOSTNAME} at ${STAMP}."
|
|
PR_PAYLOAD=$(printf '{ "title":"%s","head":"%s:%s","base":"%s","body":"%s" }' \
|
|
"Panel sync: ${STAMP}" "${ME_LOGIN}" "${NEW_BRANCH}" "${BASE_BRANCH}" "${PR_BODY}")
|
|
PR_RESP=$(curl -fsS -H "Authorization: token ${TOKEN}" \
|
|
-H "Accept: application/vnd.github+json" \
|
|
-X POST "https://api.github.com/repos/${UPSTREAM_REPO}/pulls" \
|
|
-d "$PR_PAYLOAD") || die "PR creation failed."
|
|
|
|
PR_URL=$(echo "$PR_RESP" | sed -n 's/.*"html_url":[[:space:]]*"\([^"]*\)".*/\1/p')
|
|
[[ -n "$PR_URL" ]] || { echo "$PR_RESP"; die "Could not parse PR URL."; }
|
|
|
|
echo "Pull Request created: $PR_URL"
|
|
log "Done."
|