···11+# Manual Testing Against a Remote PDS
22+33+Step-by-step guide for testing `git-remote-pds` against a real Bluesky PDS.
44+55+## Prerequisites
66+77+1. Build the binary:
88+99+```bash
1010+cd pds-git-remote
1111+cargo build
1212+```
1313+1414+2. Add the binary to your PATH:
1515+1616+```bash
1717+export PATH="$(cargo metadata --format-version 1 --no-deps \
1818+ | python3 -c 'import sys,json; print(json.load(sys.stdin)["target_directory"])')/debug:${PATH}"
1919+```
2020+2121+3. Confirm the PDS is reachable:
2222+2323+```bash
2424+curl https://YOUR-PDS-URL/xrpc/_health
2525+# Should return: {"version":"..."}
2626+```
2727+2828+## 1. Login
2929+3030+```bash
3131+git-remote-pds auth login --pds-url https://YOUR-PDS-URL --handle YOUR-HANDLE
3232+# Enter your password when prompted (or set PDS_PASSWORD env var)
3333+```
3434+3535+Verify stored credentials:
3636+3737+```bash
3838+git-remote-pds auth status
3939+```
4040+4141+## 2. Create a Test Repo
4242+4343+```bash
4444+mkdir /tmp/pds-manual-test && cd /tmp/pds-manual-test
4545+git init
4646+git checkout -b main
4747+4848+echo "hello world" > README.md
4949+mkdir src
5050+echo 'fn main() { println!("test"); }' > src/main.rs
5151+git add .
5252+git commit -m "initial commit"
5353+```
5454+5555+## 3. Push to PDS
5656+5757+```bash
5858+git remote add pds "pds://YOUR-HANDLE/manual-test-$(date +%s)"
5959+git push pds main
6060+```
6161+6262+The remote URL format is `pds://HANDLE/REPO-NAME`. Using a timestamp suffix
6363+avoids collisions with previous test runs.
6464+6565+## 4. Clone from PDS
6666+6767+In a separate directory, clone from the same remote URL you pushed to:
6868+6969+```bash
7070+cd /tmp
7171+git clone "pds://YOUR-HANDLE/REPO-NAME" pds-manual-clone
7272+```
7373+7474+Replace `REPO-NAME` with the full name from step 3 (including the timestamp).
7575+7676+Verify files match:
7777+7878+```bash
7979+diff /tmp/pds-manual-test/README.md /tmp/pds-manual-clone/README.md
8080+diff /tmp/pds-manual-test/src/main.rs /tmp/pds-manual-clone/src/main.rs
8181+```
8282+8383+## 5. Incremental Push + Fetch
8484+8585+Add another commit to the original repo:
8686+8787+```bash
8888+cd /tmp/pds-manual-test
8989+echo "new file" > file2.txt
9090+git add .
9191+git commit -m "second commit"
9292+git push pds main
9393+```
9494+9595+Fetch into the clone:
9696+9797+```bash
9898+cd /tmp/pds-manual-clone
9999+git fetch origin
100100+git merge --ff-only origin/main
101101+```
102102+103103+Verify the new file arrived:
104104+105105+```bash
106106+diff /tmp/pds-manual-test/file2.txt /tmp/pds-manual-clone/file2.txt
107107+```
108108+109109+## 6. Cleanup
110110+111111+Remove local test directories:
112112+113113+```bash
114114+rm -rf /tmp/pds-manual-test /tmp/pds-manual-clone
115115+```
116116+117117+Records left on the PDS are harmless — each test run uses a unique repo name.
118118+119119+To log out:
120120+121121+```bash
122122+git-remote-pds auth logout --handle YOUR-HANDLE
123123+```
124124+125125+## Automated Alternative
126126+127127+The `run.sh` script in this directory automates all the above steps:
128128+129129+```bash
130130+PDS_URL=https://YOUR-PDS-URL \
131131+PDS_HANDLE=YOUR-HANDLE \
132132+PDS_PASSWORD=your-password \
133133+bash pds-git-remote/scripts/remote-test/run.sh
134134+```
+134
scripts/remote-test/run.sh
···11+#!/usr/bin/env bash
22+# Tests git-remote-pds against a remote PDS.
33+#
44+# Unlike run-e2e.sh, this does NOT start/stop/reset the PDS — it assumes
55+# the PDS is already running at PDS_URL with the given account.
66+#
77+# Usage:
88+# PDS_URL=https://my-pds.example.com PDS_HANDLE=alice.my-pds.example.com PDS_PASSWORD=secret ./run.sh
99+#
1010+# Environment variables:
1111+# PDS_URL — full URL of the PDS (required)
1212+# PDS_HANDLE — AT Protocol handle (required)
1313+# PDS_PASSWORD — account password (required)
1414+set -euo pipefail
1515+1616+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
1717+CRATE_DIR="$(cd "${SCRIPT_DIR}/../.." && pwd)"
1818+1919+# ── check required env vars ──────────────────────────────────────────
2020+for var in PDS_URL PDS_HANDLE PDS_PASSWORD; do
2121+ if [ -z "${!var:-}" ]; then
2222+ echo "ERROR: ${var} is not set"
2323+ echo "Usage: PDS_URL=https://... PDS_HANDLE=alice.example PDS_PASSWORD=secret $0"
2424+ exit 1
2525+ fi
2626+done
2727+2828+echo "PDS_URL = ${PDS_URL}"
2929+echo "PDS_HANDLE = ${PDS_HANDLE}"
3030+echo ""
3131+3232+# ── unique rkey to avoid collisions across runs ──────────────────────
3333+RKEY="test-$(date +%s%N)"
3434+REPO_NAME="${RKEY}"
3535+3636+# ── temp dirs, cleaned up on exit ────────────────────────────────────
3737+TMPDIR_BASE="$(mktemp -d)"
3838+cleanup() {
3939+ echo ""
4040+ echo "Cleaning up temp dirs..."
4141+ rm -rf "${TMPDIR_BASE}"
4242+}
4343+trap cleanup EXIT
4444+4545+PUSH_REPO="${TMPDIR_BASE}/push-repo"
4646+CLONE_REPO="${TMPDIR_BASE}/clone-repo"
4747+FETCH_REPO="${TMPDIR_BASE}/fetch-repo"
4848+4949+# ── build the binary ─────────────────────────────────────────────────
5050+echo "=== Building git-remote-pds ==="
5151+cargo build -p pds-git-remote --quiet
5252+BINARY="$(cargo metadata --format-version 1 --no-deps \
5353+ | python3 -c 'import sys,json; print(json.load(sys.stdin)["target_directory"])')/debug/git-remote-pds"
5454+5555+if [ ! -x "${BINARY}" ]; then
5656+ echo "ERROR: binary not found at ${BINARY}"
5757+ exit 1
5858+fi
5959+echo "Binary: ${BINARY}"
6060+echo ""
6161+6262+# put the binary on PATH so git can find it as a remote helper
6363+export PATH="$(dirname "${BINARY}"):${PATH}"
6464+6565+# ── verify PDS is reachable ──────────────────────────────────────────
6666+echo "=== Checking PDS health ==="
6767+HEALTH=$(curl -sf "${PDS_URL}/xrpc/_health" 2>&1) || {
6868+ echo "ERROR: PDS not reachable at ${PDS_URL}/xrpc/_health"
6969+ echo "Response: ${HEALTH}"
7070+ exit 1
7171+}
7272+echo "PDS health: ${HEALTH}"
7373+echo ""
7474+7575+# ── verify login works ───────────────────────────────────────────────
7676+echo "=== Verifying login ==="
7777+echo "${PDS_PASSWORD}" | "${BINARY}" auth login \
7878+ --pds-url "${PDS_URL}" --handle "${PDS_HANDLE}"
7979+echo "Login OK"
8080+echo ""
8181+8282+# ── test push ────────────────────────────────────────────────────────
8383+echo "=== Test: initial push ==="
8484+mkdir -p "${PUSH_REPO}"
8585+cd "${PUSH_REPO}"
8686+git init --quiet
8787+git checkout -b main
8888+8989+echo "hello from remote test" > file.txt
9090+mkdir -p subdir
9191+echo "nested content" > subdir/nested.txt
9292+git add .
9393+git commit --quiet -m "initial commit"
9494+9595+REMOTE_URL="pds://${PDS_HANDLE}/${REPO_NAME}"
9696+git remote add pds "${REMOTE_URL}"
9797+git push pds main
9898+9999+echo "Push OK"
100100+echo ""
101101+102102+# ── test clone ───────────────────────────────────────────────────────
103103+echo "=== Test: clone ==="
104104+cd "${TMPDIR_BASE}"
105105+git clone "${REMOTE_URL}" clone-repo
106106+107107+# verify files match
108108+diff "${PUSH_REPO}/file.txt" "${CLONE_REPO}/file.txt"
109109+diff "${PUSH_REPO}/subdir/nested.txt" "${CLONE_REPO}/subdir/nested.txt"
110110+echo "Clone OK — files match"
111111+echo ""
112112+113113+# ── test incremental push + fetch ────────────────────────────────────
114114+echo "=== Test: incremental push ==="
115115+cd "${PUSH_REPO}"
116116+echo "second commit content" > file2.txt
117117+git add .
118118+git commit --quiet -m "second commit"
119119+git push pds main
120120+121121+echo "Incremental push OK"
122122+echo ""
123123+124124+echo "=== Test: fetch into clone ==="
125125+cd "${CLONE_REPO}"
126126+git fetch origin
127127+git merge --ff-only origin/main
128128+129129+diff "${PUSH_REPO}/file2.txt" "${CLONE_REPO}/file2.txt"
130130+echo "Fetch OK — incremental content matches"
131131+echo ""
132132+133133+# ── done ─────────────────────────────────────────────────────────────
134134+echo "=== All remote tests passed ==="