diff --git a/PUBLISH.md b/PUBLISH.md new file mode 100644 index 00000000..0a7e5e5b --- /dev/null +++ b/PUBLISH.md @@ -0,0 +1,61 @@ +# نشر نظيف على Gitea + +سكربت `scripts/publish-to-gitea.sh` يدفع نسخة **نظيفة 100% من أي أثر لـ Replit** إلى مستودع Gitea، بدون ما يلمس بيئة Replit أو شغلك المحلي. + +## وش يسوّي بالضبط + +عند كل تشغيل، يبني نسخة مؤقتة في `/tmp/` ويعمل عليها التالي قبل الدفع: + +| الإجراء | التفاصيل | +|---|---| +| يحذف الملفات الخاصة بـ Replit | `.replit`, `.replitignore`, `replit.nix`, `.local/`, `.agents/`, `attached_assets/`, كل `.replit-artifact/` | +| ينظّف رسائل الـ commits | يشيل أي سطر يبدأ بـ `Replit-` (مثل `Replit-Commit-Author`, `Replit-Commit-Screenshot-Url`) | +| يعيد كتابة هوية المؤلف | يستبدل `*@users.noreply.replit.com` باسم وإيميل من اختيارك (الافتراضي: `Riyadh `) | +| يطبّق التغييرات على **كل** الـ commits السابقة | يعني حتى الـ history القديم ينظّف، مو بس الـ commits الجديدة | +| يدفع force-push للـ remote | فقط لو أعطيت `--push` | + +## الاستخدام + +### 1) معاينة (dry run) — لا يدفع شي +```bash +./scripts/publish-to-gitea.sh +``` +يعرض لك آخر 5 commits بعد التنظيف عشان تتأكد قبل الدفع الفعلي. + +### 2) دفع فعلي لـ Gitea +```bash +./scripts/publish-to-gitea.sh --push +``` + +### 3) تخصيص الاسم/الإيميل +```bash +AUTHOR_NAME="Mohammed Ali" AUTHOR_EMAIL="me@example.com" ./scripts/publish-to-gitea.sh --push +``` + +### 4) دفع لمستودع/فرع مختلف +```bash +GITEA_REMOTE_URL="https://gitea.example.com/me/my-repo.git" \ +GITEA_BRANCH="main" \ +./scripts/publish-to-gitea.sh --push +``` + +## ضمانات الأمان + +- ✅ كل العمل في مجلد مؤقت (`/tmp/tx-publish-XXXXXX`) — يتحذف تلقائياً. +- ✅ الـ git history الأصلي عندك في Replit ما يتغيّر. +- ✅ Docker setup والـ workflows تكمل تشتغل بشكل عادي. +- ⚠️ Force-push يستبدل تاريخ Gitea كاملاً — لو في clones أخرى للمستودع، لازم تعمل clone جديد. + +## متى أشغّله + +كل ما تبي تنشر تحديثات لـ Gitea، شغّل السكربت بـ `--push`. ما يحتاج تشغيله إلا لما تبي تحدّث Gitea. + +## استرجاع نسخة العمل من Gitea (على الماك) + +```bash +git clone https://desktop-11cj93j.tail866923.ts.net/rafraa/TX.git +cd TX +./start.sh +``` + +ما راح تلقى أي إشارة لـ Replit في الكود ولا في الـ history. diff --git a/scripts/publish-to-gitea.sh b/scripts/publish-to-gitea.sh new file mode 100755 index 00000000..0cac377c --- /dev/null +++ b/scripts/publish-to-gitea.sh @@ -0,0 +1,143 @@ +#!/usr/bin/env bash +# ----------------------------------------------------------------------------- +# publish-to-gitea.sh +# +# Publishes a SANITIZED copy of this repository to a remote git server (Gitea +# by default). Runs entirely in a throw-away temp directory — your real +# working tree, Replit workspace, and local git history are never touched. +# +# What gets stripped from the published mirror: +# • Files: .replit, .replitignore, replit.nix, .local/, .agents/, +# attached_assets/, every .replit-artifact/ directory, +# every artifact.toml inside .replit-artifact/, .gitsafe-backup +# • Commit messages: every line starting with "Replit-" is removed. +# • Author/committer identity: rewritten to AUTHOR_NAME / AUTHOR_EMAIL +# (default: Riyadh ; override via env vars). +# +# Usage: +# ./scripts/publish-to-gitea.sh # dry run preview +# ./scripts/publish-to-gitea.sh --push # actually force-push +# AUTHOR_NAME="John" AUTHOR_EMAIL=a@b.c ./scripts/publish-to-gitea.sh --push +# GITEA_REMOTE_URL=https://... ./scripts/publish-to-gitea.sh --push +# GITEA_BRANCH=main ./scripts/publish-to-gitea.sh --push +# ----------------------------------------------------------------------------- +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$REPO_ROOT" + +AUTHOR_NAME="${AUTHOR_NAME:-Riyadh}" +AUTHOR_EMAIL="${AUTHOR_EMAIL:-dev@tx.local}" +GITEA_REMOTE_URL="${GITEA_REMOTE_URL:-$(git config --get remote.origin.url || echo "")}" +GITEA_BRANCH="${GITEA_BRANCH:-main}" + +PUSH=0 +[[ "${1:-}" == "--push" ]] && PUSH=1 + +if [[ -z "$GITEA_REMOTE_URL" ]]; then + echo "ERROR: no remote URL. Set GITEA_REMOTE_URL or add a git remote named 'origin'." >&2 + exit 1 +fi + +echo "================================================================" +echo " Publish-to-Gitea — sanitized history mirror" +echo "----------------------------------------------------------------" +echo " Source repo: $REPO_ROOT" +echo " Target remote: $GITEA_REMOTE_URL" +echo " Target branch: $GITEA_BRANCH" +echo " New author: $AUTHOR_NAME <$AUTHOR_EMAIL>" +echo " Mode: $([[ $PUSH == 1 ]] && echo 'PUSH (will force-push)' || echo 'DRY RUN (no push)')" +echo "================================================================" +echo + +WORK_DIR="$(mktemp -d -t tx-publish-XXXXXX)" +trap 'rm -rf "$WORK_DIR"' EXIT + +# -- 1. Acquire git-filter-repo (single-file Python script) ------------------- +FILTER_REPO="$WORK_DIR/git-filter-repo" +if command -v git-filter-repo >/dev/null 2>&1; then + FILTER_REPO="$(command -v git-filter-repo)" + echo "[1/5] Using system git-filter-repo: $FILTER_REPO" +else + echo "[1/5] Downloading git-filter-repo into temp dir ..." + if command -v curl >/dev/null 2>&1; then + curl -fsSL -o "$FILTER_REPO" \ + "https://raw.githubusercontent.com/newren/git-filter-repo/v2.47.0/git-filter-repo" + elif command -v wget >/dev/null 2>&1; then + wget -q -O "$FILTER_REPO" \ + "https://raw.githubusercontent.com/newren/git-filter-repo/v2.47.0/git-filter-repo" + else + echo "ERROR: neither curl nor wget is available." >&2 + exit 1 + fi + chmod +x "$FILTER_REPO" +fi + +# -- 2. Mirror-clone the local repo into the temp dir ------------------------- +MIRROR="$WORK_DIR/mirror" +echo "[2/5] Cloning a fresh mirror of the local repo ..." +git clone --no-local --bare "$REPO_ROOT" "$MIRROR" >/dev/null 2>&1 || \ + git clone --bare "$REPO_ROOT" "$MIRROR" >/dev/null + +# -- 3. Strip Replit-only paths from the entire history ----------------------- +echo "[3/5] Removing Replit-specific files from every commit ..." +"$FILTER_REPO" --force --source "$MIRROR" --target "$MIRROR" \ + --invert-paths \ + --path .replit \ + --path .replitignore \ + --path replit.nix \ + --path replit.md \ + --path .local \ + --path .agents \ + --path attached_assets \ + --path .gitsafe-backup \ + --path-glob '**/.replit-artifact' \ + --path-glob '**/.replit-artifact/**' + +# -- 4. Rewrite commit messages and author identity --------------------------- +echo "[4/5] Stripping 'Replit-*' trailers and rewriting author identity ..." +MSG_CALLBACK=' +import re +text = message.decode("utf-8", errors="replace") +# Drop every line that begins with "Replit-" +cleaned = "\n".join( + line for line in text.splitlines() + if not re.match(r"^\s*Replit-", line) +) +# Collapse trailing whitespace +cleaned = re.sub(r"\n{3,}$", "\n\n", cleaned).rstrip() + "\n" +return cleaned.encode("utf-8") +' + +NAME_BYTES="$(printf '%s' "$AUTHOR_NAME")" +EMAIL_BYTES="$(printf '%s' "$AUTHOR_EMAIL")" + +NAME_CALLBACK="return b\"$NAME_BYTES\"" +EMAIL_CALLBACK="return b\"$EMAIL_BYTES\"" + +"$FILTER_REPO" --force --source "$MIRROR" --target "$MIRROR" \ + --message-callback "$MSG_CALLBACK" \ + --name-callback "$NAME_CALLBACK" \ + --email-callback "$EMAIL_CALLBACK" + +# -- 5. Push (or preview) ----------------------------------------------------- +echo "[5/5] Final state of the sanitized mirror:" +echo +git --git-dir="$MIRROR" log --pretty=format:'%h %an <%ae> %s' -n 5 +echo +echo +echo "Tip: inspect the cleaned tree with:" +echo " git --git-dir=$MIRROR log --all --stat | less" +echo + +if [[ $PUSH -eq 1 ]]; then + echo "Force-pushing branch '$GITEA_BRANCH' to $GITEA_REMOTE_URL ..." + git --git-dir="$MIRROR" remote add gitea "$GITEA_REMOTE_URL" 2>/dev/null || \ + git --git-dir="$MIRROR" remote set-url gitea "$GITEA_REMOTE_URL" + git --git-dir="$MIRROR" push --force gitea "HEAD:refs/heads/$GITEA_BRANCH" + echo + echo "Done. Open $GITEA_REMOTE_URL to verify." +else + echo "DRY RUN complete — nothing was pushed." + echo "Re-run with --push to publish: ./scripts/publish-to-gitea.sh --push" +fi