-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathpush_to_github.sh
More file actions
205 lines (182 loc) · 8.13 KB
/
push_to_github.sh
File metadata and controls
205 lines (182 loc) · 8.13 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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#!/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."