Skip to content

Make sync remote-agnostic: add sync.remote, persist to config.yaml - #3180

Merged
coffeegoddd merged 4 commits into
gastownhall:mainfrom
coffeegoddd:db/fix-init
Apr 10, 2026
Merged

Make sync remote-agnostic: add sync.remote, persist to config.yaml#3180
coffeegoddd merged 4 commits into
gastownhall:mainfrom
coffeegoddd:db/fix-init

Conversation

@coffeegoddd

Copy link
Copy Markdown
Collaborator

Summary

  • Add sync.remote config key as the primary remote URL for bootstrap/clone, supporting any Dolt-compatible remote (DoltHub, S3, GCS, file, git). sync.git-remote remains as a deprecated fallback.
  • Persist sync.remote to config.yaml when adding a Dolt remote via bd dolt remote add origin <url> or during bd init auto-detect. This ensures the remote URL survives git clone (since the Dolt database is gitignored).
  • Auto-commit config.yaml after bd dolt remote add/remove origin so the change isn't left dirty in the working tree.
  • Fix bootstrap for non-git remotes — previously, bd bootstrap on a fresh clone would fall through to "create fresh database" when the remote was DoltHub or another non-git remote, because the only detection paths were sync.git-remote config and git origin refs/dolt/data probing.
  • Fix double overwrite prompt in embedded mode — bd dolt remote add no longer prompts separately for SQL and CLI when they share the same directory.
  • Rename internal APIsBootstrapFromGitRemote*BootstrapFromRemote*, Config.SyncGitRemoteConfig.SyncRemote. Old names kept as deprecated wrappers.
  • Add normalizeRemoteURL() — detects Dolt-native schemes (dolthub://, file://, aws://, gs://) and passes them through unchanged; only converts git URLs (https://, ssh://, git@) to dolt format.

Test plan

  • TestNormalizeRemoteURL — all Dolt-native and git URL schemes
  • TestBootstrapFromRemoteWithDB — empty/whitespace database rejection
  • TestBootstrapFromRemote_UsesDefaultDatabase — convenience wrapper
  • TestBootstrapFromGitRemoteWithDB_DeprecatedWrapper — backwards compat
  • TestDatabaseNotFoundHint — error messages reference sync.remote
  • TestInitGuardServerMessage — guard messages reference sync.remote
  • TestFreshCloneServerResult — doctor check messages updated
  • TestEnrichFreshClone_WithSyncRemoteMentionsBootstrapAndFallback
  • Manual: bd init in repo with git origin that has refs/dolt/datasync.remote persisted to config.yaml
  • Manual: bd dolt remote add origin dolthub://org/dbsync.remote written and committed
  • Manual: clone repo, bd bootstrap → detects sync.remote and clones from DoltHub

🤖 Generated with Claude Code

@hilmes hilmes left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: PR #3180 — Make sync remote-agnostic: add sync.remote, persist to config.yaml

VERDICT: 🟢 LGTM — SHIP IT

This PR decouples sync configuration from git-specific paths by introducing sync.remote as the primary config key while maintaining backward compatibility with the deprecated sync.git-remote. The implementation is sound, well-tested, and defensive.


Core Design: Remote Resolution

New File: cmd/bd/sync_remote.go

Key Functions:

  1. resolveSyncRemote() — Resolution order:

    • sync.remote (primary)
    • sync.git-remote (deprecated fallback)
    • "" (not configured)
  2. normalizeRemoteURL(url) — Intelligently converts remotes:

    • Dolt-native schemes (dolthub://, file://, aws://, gs://, git+...) → returned as-is
    • Git URLs (https://, ssh://, git@...) → converted via gitURLToDoltRemote()
    • Unknown schemes → returned as-is (let dolt handle)
  3. commitBeadsConfig(msg) — Helper to auto-commit config.yaml changes:

    • Runs git add .beads/config.yaml
    • Runs git commit with message
    • Gracefully handles "nothing to commit" (no-op)

Correctness

  • Resolution order is correct: primary key checked first, fallback second
  • URL normalization logic is sound (native schemes first, then git conversion)
  • Git URL detection handles 3 formats: https://, ssh://, SCP-style git@host:path
  • SCP detection (idx > 0 && !strings.Contains(url[:idx], "/") && strings.Contains(url, "@")) correctly identifies user@host:path style

Edge Cases

  • Empty strings: handled by checking != "" before returning
  • Both keys configured: sync.remote takes precedence (correct)
  • URL with unknown scheme: passed through to Dolt (correct)
  • SCP URL with multiple colons: detected correctly (git@github.com:org/repo.git → found at first :)

Test Coverage: sync_remote_test.go covers 12 cases:

  • 7 Dolt-native schemes (dolthub, file, aws, gs, git+https/ssh/http)
  • 5 Git URL conversions (https, http, ssh, git@host:path)

Bootstrap Integration

Changes to cmd/bd/bootstrap.go

Key Changes:

  1. Line ~92: Updated help text

    • Old: "sync.git-remote is configured"
    • New: "sync.remote is configured" + new bullet for git refs detection
  2. Line ~276: Call resolveSyncRemote() instead of directly reading config

    syncRemote := resolveSyncRemote()
    if syncRemote != "" {
        plan.SyncRemote = normalizeRemoteURL(syncRemote)
  3. Line ~298: Auto-detect git origin for refs/dolt/data

    • Calls normalizeRemoteURL(originURL) to convert git URLs
    • Updated reason message to be clearer
  4. New function cloneFromRemote() (line ~489)

    • Extracted clone logic shared between init and bootstrap
    • Handles both embedded and server modes
    • Parameters: beadsDir, remoteURL, dbName

Correctness

  • resolveSyncRemote() called at right place (bootstrap detection)
  • URL normalization applied consistently
  • Clone logic extracted properly (DRY principle)
  • Embedded vs server mode handled correctly

Edge Cases

  • Git remote has no refs/dolt/data → skips sync (correct)
  • sync.remote configured but invalid → error passed to caller (correct)
  • Fallback works: if sync.remote empty, tries sync.git-remote (correct)

Configuration Integration

internal/config/yaml_config.go

Change: Added sync.remote to YamlOnlyKeys

"sync.remote":     true, // Primary: any Dolt-compatible remote URL
"sync.git-remote": true, // Deprecated: falls back from sync.remote

Correctness

  • Both keys are YAML-only (not git config)
  • Comment explains deprecation

cmd/bd/main.go

Line ~736: Changed from hardcoded config read to function call:

doltCfg.SyncRemote = resolveSyncRemote()  // was: config.GetString("sync.git-remote")

Correctness


Config Validation

cmd/bd/config_cmd.go (test helper)

Test: TestSetConfigRejectsReservedPrefixes

  • Updated from "sync.git-remote" to "sync.remote"
  • Verifies reserved key rejection works

Correctness


Documentation Updates

docs/DOLT.md

  • Changed example from sync.git-remote to sync.remote
  • Added: "Any Dolt-compatible remote URL is supported (DoltHub, S3, GCS, file, or git)"
  • Clarified: bootstrap auto-detection only applies to git remotes

docs/TROUBLESHOOTING.md

  • Updated: bd config get sync.remote (was sync.git-remote)

Quality

  • Clear explanations of remote types
  • Deprecation message would be nice (optional)

Test Coverage ✅

New Tests:

  • TestNormalizeRemoteURL (12 cases, comprehensive)
  • TestEmbeddedCreateCrossRepoUninit — regression test for be-sy8 / GH#2988

Updated Tests:

  • Config validation test updated to use new key name

Quality: Excellent. Covers happy path, edge cases, and integration scenarios.


Potential Observations

1. SCP URL Detection Logic

The SCP detection in normalizeRemoteURL:

if idx := strings.Index(url, ":"); idx > 0 && !strings.Contains(url[:idx], "/") && strings.Contains(url, "@") {
    return gitURLToDoltRemote(url)
}

This is clever but slightly fragile. Consider:

  • file:///path/to/file — has :, but scheme check above prevents matching (good, caught by earlier file:// check)
  • s3://bucket:region/path — has : but strings.Contains(url[:idx], "/") fails (good, not matched)
  • Edge case: git@192.168.1.1:repo.git — IP address with no slashes, has @ → correctly identified as SCP (good)

Verdict: Logic is sound. The three conditions are correct guards.


2. URL Normalization vs gitURLToDoltRemote

The code assumes gitURLToDoltRemote() correctly handles all git URL formats. Looking at the test expectations:

  • https://github.com/org/repo.gitgit+https://github.com/org/repo.git
  • git@github.com:org/repo.gitgit+ssh://git@github.com/org/repo.git

This matches expected behavior (git+ scheme prefix). Trust that gitURLToDoltRemote() is correct since it's not modified here.


3. Auto-commit in cloneFromRemote

The PR doesn't auto-commit config.yaml changes after updating sync.remote. The commitBeadsConfig() function is defined but not called in the clone path.

Assessment: This is probably intentional — the caller (bootstrap, init) likely handles the commit. Acceptable, but would be good to have a comment explaining the pattern.


4. Backward Compatibility

The resolution order (primary first, fallback second) ensures:

  • Old configs using sync.git-remote continue working
  • New configs using sync.remote take precedence
  • Migration path is implicit (just set sync.remote, old key is ignored)

Quality


5. Performance

No performance concerns. URL normalization is O(n) string operations, called during bootstrap (not hot path). Resolution is O(1) map lookups.


Files Touched ✅

All changes are tightly scoped:

  • New: cmd/bd/sync_remote.go, cmd/bd/sync_remote_test.go
  • Modified: bootstrap, config, main, YAML schema, docs
  • Test: store factory (unrelated regression test for #2988)

No unrelated changes. No dead code.


Style & Documentation ✅

  • Comments explain why (e.g., "Dolt-native schemes returned as-is")
  • Function names are descriptive (resolveSyncRemote, normalizeRemoteURL)
  • Test cases are well-named and cover edge cases
  • Error messages would guide users correctly
  • Deprecation comment on old key is clear

Blocking Issues

None. All changes are correct, defensive, and well-tested.


Summary

PR #3180 successfully decouples sync configuration from git-specific paths:

  1. New sync.remote key — Primary config for any Dolt-compatible remote
  2. Fallback to sync.git-remote — Backward compatible, no breaking changes
  3. URL normalization — Intelligently handles Dolt-native, git, and unknown schemes
  4. Bootstrap integration — Consistent URL handling across init and bootstrap
  5. Documentation — Clear examples of supported remote types

The implementation is defensive (validation, fallbacks), well-tested (12 test cases + regression test), and maintains backward compatibility.

SHIP IT.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants