#!/usr/bin/env bash # Upload the FormScout source tree to the Build Small Hackathon Space, as a PR. # # Usage: # ./scripts/hackathon_upload.sh # message from last git commit # ./scripts/hackathon_upload.sh "feat: my change" # custom message # # Pushes (PR) to: # spaces/build-small-hackathon/small-functional-movement-screening # # The Space already exists, so this script only uploads — it does not create the # repo. Like hf_upload.sh, `hf upload` ignores .hfignore, so we parse it into # --exclude globs ourselves. Above LARGE_THRESHOLD files it falls back to # `hf upload-large-folder` (resumable, but commits to main directly — no PR). set -euo pipefail cd "$(dirname "$0")/.." HACKATHON_OWNER="${FORMSCOUT_HF_HACKATHON_OWNER:-build-small-hackathon}" REPO_NAME="small-functional-movement-screening" SPACE_REPO="spaces/$HACKATHON_OWNER/$REPO_NAME" MSG="${1:-$(git log -1 --pretty=%s)}" LARGE_THRESHOLD="${FORMSCOUT_HF_LARGE_THRESHOLD:-500}" # Belt-and-suspenders extras on top of .hfignore. `.cache/` is the resume # state upload-large-folder writes into the folder being uploaded. PATTERNS=( "*.pdf" "**/node_modules/**" ".cache/**" ) # Parse .hfignore into fnmatch-style globs. fnmatch's `*` crosses `/`, but a # bare name like `.DS_Store` or `dir/` only matches at the root, so emit both # the rooted and `**/`-prefixed forms. while IFS= read -r line; do line="${line%%#*}" line="${line#"${line%%[![:space:]]*}"}" line="${line%"${line##*[![:space:]]}"}" [[ -z "$line" ]] && continue if [[ "$line" == */ ]]; then PATTERNS+=("${line}**" "**/${line}**") else PATTERNS+=("$line" "**/$line") fi done < .hfignore EXCLUDES=() for p in "${PATTERNS[@]}"; do EXCLUDES+=(--exclude="$p") done # Count what would actually be uploaded, using the same filter the hub client # applies, so the mode decision matches reality. N_FILES=$(python3 - "${PATTERNS[@]}" <<'EOF' import sys from pathlib import Path from huggingface_hub.utils import filter_repo_objects patterns = sys.argv[1:] files = ( str(p) for p in Path(".").rglob("*") if p.is_file() and p.parts[0] != ".git" ) print(len(list(filter_repo_objects(files, ignore_patterns=patterns)))) EOF ) echo "── $N_FILES files to upload after .hfignore filtering" if (( N_FILES == 0 )); then echo "✗ nothing to upload — check .hfignore" >&2 exit 1 fi if (( N_FILES > LARGE_THRESHOLD )); then echo "── $SPACE_REPO: $N_FILES files > $LARGE_THRESHOLD, using upload-large-folder" echo " (resumable; commits directly to main — no PR, no custom message)" hf upload-large-folder "$SPACE_REPO" . "${EXCLUDES[@]}" else echo "── uploading (PR) to: $SPACE_REPO" hf upload "$SPACE_REPO" . . "${EXCLUDES[@]}" --create-pr --commit-message="$MSG" fi echo "✓ done — PR opened on $SPACE_REPO (review & merge in the HF UI)"