SBPro b28662d3b4 Release 2.0.0 — explicit monorepo_url, drop first-target-host inference
Breaking change. The monorepo's gitea host was previously inferred from the
first target's subrepo_url, silently coupling the two and breaking on any
multi-host setup (monorepo on host A, target on host B). v2.0.0 replaces the
inference with a required josh.monorepo_url field that mirrors subrepo_url —
same parsing, same SSH/HTTPS auth options, same shape.

- schema_version: 2 is now required; v1 configs are rejected with a clear migration error
- josh.monorepo_url is required; josh.monorepo_auth is optional (default https)
- mono_auth_url() in lib/auth.sh mirrors subrepo_auth_url()
- MONOREPO_API derives from monorepo_url's host instead of .[0].gitea_host;
  env-var override preserved as escape hatch
- initial_import() and force-push call mono_auth_url() instead of building URLs inline
- ADR-012 documents the rationale; CHANGELOG includes migration snippet

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 06:31:21 +03:00
2026-04-04 01:43:47 +03:00
"#"
2026-02-12 09:20:55 +03:00
"#"
2026-02-12 09:20:55 +03:00

josh-sync

Bidirectional monorepo ↔ subrepo sync via josh-proxy. Supports multiple sync targets from a single config.

Quick Start

1. Add config

Create .josh-sync.yml in your monorepo root:

schema_version: 2

josh:
  proxy_url: "https://josh.example.com"
  monorepo_path: "org/monorepo"
  monorepo_url: "git@gitea.example.com:org/monorepo.git"
  monorepo_auth: "ssh"               # optional, default "https"

targets:
  - name: "billing"
    subfolder: "services/billing"
    subrepo_url: "git@gitea.example.com:ext/billing.git"
    subrepo_auth: "ssh"
    branches:
      main: main
    exclude:                          # files excluded from subrepo (optional)
      - ".monorepo/"

bot:
  name: "josh-sync-bot"
  email: "josh-sync-bot@example.com"
  trailer: "Josh-Sync-Origin"

2. Add CI workflows

Copy from examples/ and customize paths/branches:

# .gitea/workflows/josh-sync-forward.yml
- uses: https://your-gitea.example.com/org/josh-sync@v1
  with:
    direction: forward
  env:
    SYNC_BOT_USER: ${{ secrets.SYNC_BOT_USER }}
    SYNC_BOT_TOKEN: ${{ secrets.SYNC_BOT_TOKEN }}
    SUBREPO_SSH_KEY: ${{ secrets.SUBREPO_SSH_KEY }}

3. Local dev (Nix)

Add josh-sync as a flake input, then:

{ inputs, ... }: {
  imports = [ inputs.josh-sync.devenvModules.default ];
}

Run josh-sync preflight to validate your setup.

Documentation

Versioning

josh-sync follows semver:

Bump Meaning Action required
Patch (1.x.y) Bug fixes only Safe to upgrade
Minor (1.y.0) New optional config fields, new commands, new action inputs Safe to upgrade; new features are opt-in
Major (y.0.0) Removed or renamed config fields, CLI flags, action inputs, env vars, or state format Read the Breaking Changes section in the changelog before upgrading

CI workflows pin to a floating major tag (e.g. @v1). A breaking change bumps the major version and moves the tag — @v1 workflows keep working until you explicitly update to @v2.

CLI

josh-sync sync [--forward|--reverse] [--force] [--target NAME[,NAME]] [--branch BRANCH]
josh-sync preflight
josh-sync import <target>
josh-sync reset <target>
josh-sync onboard <target> [--restart]
josh-sync migrate-pr <target> [PR#...] [--all]
josh-sync status
josh-sync state show <target> [branch]
josh-sync state reset <target> [branch]

How It Works

  • Forward sync (mono → subrepo): pushes directly if clean, creates conflict PR if not. Uses --force-with-lease for safety.
  • Reverse sync (subrepo → mono): creates a PR by default. Add --force to bypass the PR and push directly to the mono branch (destructive).
  • File exclusion: exclude patterns are embedded inline in the josh-proxy URL. Excluded files exist only in the monorepo.
  • Filter reconciliation: Changing the exclude list auto-creates a merge commit that connects old and new histories — no force-push needed.
  • Loop prevention: Josh-Sync-Origin: git trailer filters out bot commits.
  • State tracking: orphan branch josh-sync-state stores JSON per target/branch.

Dependencies

bash >=4, git, curl, jq, yq (mikefarah/yq v4+), openssh, rsync

The Nix flake bundles all dependencies automatically.

License

MIT

Description
No description provided
Readme MIT 617 KiB
Languages
Shell 97.6%
Nix 1.5%
Makefile 0.9%