#!/usr/bin/env bash # Sync buildable source + Proxmox scripts to the public Gitea repo. # Allowlist: .publishinclude | Skips: Docker, .gitignore, *.bat, tests, docs, CI, junk # # Usage: # export GITEA_TOKEN='' # ./proxmox/sync-public.sh --gitea-url https://gitea.example.com --owner org --repo myoffice_public --push set -euo pipefail script_dir="$(cd "$(dirname "$0")" && pwd)" repo_root="$(cd "$script_dir/.." && pwd)" cd "$repo_root" gitea_url="${GITEA_URL:-}" owner="${GITEA_OWNER:-}" repo="${GITEA_REPO:-myoffice-public}" branch="${BRANCH:-master}" token="${GITEA_TOKEN:-}" work_dir="${WORK_DIR:-}" do_push=false include_file="$repo_root/.publishinclude" usage() { echo "Usage: $0 --gitea-url URL --owner OWNER [--repo REPO] [--branch BRANCH] [--push]" >&2 exit 1 } while [[ $# -gt 0 ]]; do case "$1" in --gitea-url) gitea_url="$2"; shift 2 ;; --owner) owner="$2"; shift 2 ;; --repo) repo="$2"; shift 2 ;; --branch) branch="$2"; shift 2 ;; --work-dir) work_dir="$2"; shift 2 ;; --push) do_push=true; shift ;; -h|--help) usage ;; *) echo "Unknown argument: $1" >&2; usage ;; esac done [[ -n "$gitea_url" && -n "$owner" ]] || usage [[ -f "$include_file" ]] || { echo "Missing $include_file" >&2; exit 1; } gitea_url="${gitea_url%/}" [[ -n "$work_dir" ]] || work_dir="${TMPDIR:-/tmp}/myoffice-public-sync" # Relative path should not be copied into public tree. should_skip_rel() { local f="$1" local base base="$(basename "$f")" # User / policy excludes [[ "$f" == Docker || "$f" == Docker/* ]] && return 0 [[ "$base" == .gitignore ]] && return 0 [[ "$base" == *.bat ]] && return 0 # Not required to build or install CT [[ "$f" == MyOffice.Tests || "$f" == MyOffice.Tests/* ]] && return 0 [[ "$f" == docs || "$f" == docs/* ]] && return 0 [[ "$f" == .gitea || "$f" == .gitea/* ]] && return 0 [[ "$base" == .dockerignore ]] && return 0 [[ "$base" == gulpfile.js ]] && return 0 [[ "$base" == build.ps1 ]] && return 0 [[ "$base" == linux_deploy.sh ]] && return 0 [[ "$f" == proxmox/README.public.md ]] && return 0 # Build junk / secrets / Docker-only appsettings [[ "$base" == node_modules || "$f" == */node_modules/* ]] && return 0 [[ "$base" == bin || "$f" == */bin/* ]] && return 0 [[ "$base" == obj || "$f" == */obj/* ]] && return 0 [[ "$base" == .angular || "$f" == */.angular/* ]] && return 0 [[ "$base" == _Published || "$f" == _Published/* ]] && return 0 [[ "$base" == myoffice-publish.tar.gz ]] && return 0 [[ "$base" == .env || "$base" == env.local || "$base" == .env.* ]] && return 0 [[ "$base" == appsettings.Docker.json ]] && return 0 [[ "$base" == appsettings.shared.Docker.json ]] && return 0 [[ "$base" == environment.docker.ts ]] && return 0 [[ "$base" == *.user || "$base" == *.suo ]] && return 0 # SPA unit-test harness (not used by ng build --configuration proxmox) [[ "$base" == karma.conf.js ]] && return 0 [[ "$base" == *.spec.ts ]] && return 0 return 1 } if [[ -n "$token" ]]; then host_part="${gitea_url#https://}" host_part="${host_part#http://}" scheme=https [[ "$gitea_url" == http://* ]] && scheme=http remote="${scheme}://oauth2:${token}@${host_part}/${owner}/${repo}.git" else remote="${gitea_url}/${owner}/${repo}.git" echo "No token — using remote as-is (SSH URL recommended): $remote" fi echo "-----------------------------------------------" echo "Sync allowlist (.publishinclude) -> $owner/$repo ($branch)" echo "WorkDir: $work_dir" echo "-----------------------------------------------" rm -rf "$work_dir" mkdir -p "$work_dir" if ! git clone --depth 1 --branch "$branch" "$remote" "$work_dir" 2>/dev/null; then echo "Clone failed or empty repo — initializing new git repo..." git -C "$work_dir" init -b "$branch" 2>/dev/null || { git -C "$work_dir" init git -C "$work_dir" checkout -b "$branch" 2>/dev/null || true } git -C "$work_dir" remote remove origin 2>/dev/null || true git -C "$work_dir" remote add origin "$remote" fi find "$work_dir" -mindepth 1 -maxdepth 1 ! -name '.git' -exec rm -rf {} + copied=0 skipped=0 copy_tracked_under() { local prefix="$1" # '' for file, or 'Dir/' while IFS= read -r -d '' f; do if [[ -n "$prefix" ]]; then [[ "$f" == "$prefix"* ]] || continue else [[ "$f" == "$2" ]] || continue fi if should_skip_rel "$f"; then skipped=$((skipped + 1)) continue fi src="$repo_root/$f" [[ -e "$src" ]] || continue dest="$work_dir/$f" mkdir -p "$(dirname "$dest")" cp -a "$src" "$dest" copied=$((copied + 1)) done < <(git -C "$repo_root" ls-files -z) } while IFS= read -r line || [[ -n "$line" ]]; do line="${line%%#*}" line="$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')" [[ -z "$line" ]] && continue src="$repo_root/$line" if [[ "$line" == */ ]]; then dir="${line%/}" if [[ ! -d "$repo_root/$dir" ]]; then echo "Skip missing dir: $dir" continue fi copy_tracked_under "${dir}/" echo "Synced $dir/" else if [[ ! -e "$src" ]]; then echo "Skip missing file: $line" continue fi if should_skip_rel "$line"; then skipped=$((skipped + 1)) echo "Skip excluded: $line" continue fi # Only copy if tracked (or exists — LICENSE etc.) dest="$work_dir/$line" mkdir -p "$(dirname "$dest")" cp -a "$src" "$dest" copied=$((copied + 1)) echo "Synced $line" fi done < "$include_file" echo "Copied $copied files (skipped $skipped)." repo_raw_base="${gitea_url}/${owner}/${repo}/raw/branch/${branch}" readme_template="$script_dir/README.public.md" [[ -f "$readme_template" ]] || { echo "Missing $readme_template" >&2; exit 1; } sed \ -e "s|__GITEA_URL__|${gitea_url}|g" \ -e "s|__GITEA_OWNER__|${owner}|g" \ -e "s|__GITEA_REPO__|${repo}|g" \ -e "s|__GITEA_BRANCH__|${branch}|g" \ -e "s|__REPO_RAW_BASE__|${repo_raw_base}|g" \ "$readme_template" >"$work_dir/README.md" echo "Wrote public README.md" # Public consumers need a minimal .gitignore so git status stays clean after npm/dotnet restore cat >"$work_dir/.gitignore" <<'EOF' **/bin/ **/obj/ **/node_modules/ **/.angular/ _Published/ myoffice-publish.tar.gz *.user .env env.local MyOffice.SPA/src/environments/environment.ts MyOffice.Shared/appsettings.shared.Development.json MyOffice.Shared/appsettings.shared.Production.json EOF git -C "$work_dir" add -A if [[ -z "$(git -C "$work_dir" status --porcelain)" ]]; then echo "No changes to commit." else git -C "$work_dir" -c user.email='myoffice-sync@local' -c user.name='myoffice-sync' \ commit -m "sync build tree from private myoffice" echo "Committed public snapshot." fi if [[ "$do_push" == true ]]; then echo "Pushing to origin $branch..." git -C "$work_dir" push -u origin "HEAD:$branch" echo "Pushed." else echo "Dry run (no push). Re-run with --push to publish." echo "Work tree left at: $work_dir" fi echo "" echo "Proxmox one-liner:" echo " bash -c \"\$(curl -fsSL ${repo_raw_base}/proxmox/myoffice.sh)\"" echo ""