#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" cd "$ROOT_DIR" DRY_RUN=1 APPLY=0 TARGETS="github,gitea" COMMIT_MSG="docs: sync consolidation and session starter" usage() { cat <<'USAGE' Usage: bash scripts/docs/docs_sync.sh [--dry-run] [--apply] [--targets github,gitea] [--message "..."] Behavior: - default mode is --dry-run (prints actions only) - --apply performs git add/commit/push for selected targets - targets values: github,gitea Safety: - refuses to apply with unstaged non-doc changes in index - only stages docs-related paths by default USAGE } while [[ $# -gt 0 ]]; do case "$1" in --dry-run) DRY_RUN=1 APPLY=0 shift ;; --apply) APPLY=1 DRY_RUN=0 shift ;; --targets) TARGETS="$2" shift 2 ;; --message) COMMIT_MSG="$2" shift 2 ;; -h|--help) usage exit 0 ;; *) echo "Unknown arg: $1" >&2 usage exit 2 ;; esac done if [[ "$APPLY" -eq 1 ]]; then # Prevent accidental mix with staged non-doc changes. staged_non_doc="$(git diff --cached --name-only | rg -v '^(docs/|scripts/docs/|PROJECT-MASTER-INDEX.md$|NODA1-SAFE-DEPLOY.md$|config/README.md$)' || true)" if [[ -n "$staged_non_doc" ]]; then echo "Refusing --apply: staged non-doc files detected:" >&2 echo "$staged_non_doc" >&2 exit 3 fi fi mapfile -t GH_REMOTES < <(git remote -v | awk '/github.com/ {print $1}' | sort -u) mapfile -t GITEA_REMOTES < <(git remote -v | awk '/gitea/ {print $1}' | sort -u) wants_target() { local needle="$1" [[ ",$TARGETS," == *",$needle,"* ]] } print_remotes() { echo "Detected remotes:" echo " github: ${GH_REMOTES[*]:-}" echo " gitea : ${GITEA_REMOTES[*]:-}" } run_or_echo() { if [[ "$DRY_RUN" -eq 1 ]]; then echo "[dry-run] $*" else eval "$@" fi } print_remotes echo "Targets: $TARGETS" echo "Commit message: $COMMIT_MSG" doc_paths=( docs/SESSION_STARTER.md docs/runbooks/DOCS_SERVICES_AUTOMATION_RUNBOOK.md docs/consolidation/README.md docs/consolidation/SOURCES.md docs/consolidation/docs_registry_curated.csv docs/consolidation/INTEGRATIONS_STATUS_LATEST.md docs/consolidation/jupyter/JUPYTER_SYNC_LATEST.md docs/consolidation/jupyter/notebooks_index_latest.csv docs/consolidation/pieces/PIECES_SYNC_LATEST.md docs/consolidation/pieces/pieces_index_latest.csv docs/backups/LATEST.txt docs/standards/DOCS_STYLE_GUIDE.md docs/standards/DOC_TEMPLATE.md docs/standards/lint_scope.txt PROJECT-MASTER-INDEX.md .markdownlint.yml .markdownlintignore .github/workflows/docs-lint.yml scripts/docs/session_bootstrap.sh scripts/docs/docs_backup.sh scripts/docs/docs_lint.sh scripts/docs/run_docs_maintenance.sh scripts/docs/install_local_cron.sh scripts/docs/jupyter_sync.sh scripts/docs/pieces_sync.sh scripts/docs/services_sync.sh scripts/docs/docs_sync.sh ) existing_paths=() for p in "${doc_paths[@]}"; do [[ -e "$p" ]] && existing_paths+=("$p") done if [[ "${#existing_paths[@]}" -eq 0 ]]; then echo "No docs paths found to sync." exit 0 fi run_or_echo "git add ${existing_paths[*]}" if [[ "$DRY_RUN" -eq 1 ]]; then echo "[dry-run] git diff --cached --name-status" git diff --cached --name-status || true else if git diff --cached --quiet; then echo "No staged changes after add; nothing to commit." exit 0 fi git commit -m "$COMMIT_MSG" fi if wants_target "github"; then if [[ "${#GH_REMOTES[@]}" -eq 0 ]]; then echo "Skip github: no matching remotes." else for r in "${GH_REMOTES[@]}"; do current_branch="$(git rev-parse --abbrev-ref HEAD)" run_or_echo "git push $r $current_branch" done fi fi if wants_target "gitea"; then if [[ "${#GITEA_REMOTES[@]}" -eq 0 ]]; then echo "Skip gitea: no matching remotes." else for r in "${GITEA_REMOTES[@]}"; do current_branch="$(git rev-parse --abbrev-ref HEAD)" run_or_echo "git push $r $current_branch" done fi fi echo "Done."