From f5003bc7b04709ca27f0858d67787354c8ad3fc0 Mon Sep 17 00:00:00 2001 From: ruvnet Date: Fri, 24 Apr 2026 10:29:09 -0400 Subject: [PATCH] ci: mirror crates/ruvector-rulake/ + ADRs to ruvnet/RuLake on push MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Establishes ruvnet/ruvector as the canonical source and ruvnet/RuLake as a read-only mirror. Implements "option C" — no submodules, no workspace-inheritance rewrites, no `--recursive` tax on contributors. Trigger: push to `main` touching either - crates/ruvector-rulake/** (the whole crate: src, tests, examples, Cargo.toml, README, BENCHMARK, …) - docs/adr/ADR-15[5-8]-* (the four ruLake ADRs) - the workflow itself plus a workflow_dispatch for manual re-syncs. RuLake repo layout after sync: / ├── README.md hand-maintained landing page, never overwritten ├── LICENSE-MIT hand-maintained ├── LICENSE-APACHE hand-maintained ├── MIRROR.md tombstone explaining read-only status (written by the workflow) ├── crate/ ← rsync'd from crates/ruvector-rulake/ │ ├── Cargo.toml (workspace-inheritance preserved; consumers │ │ who clone RuLake standalone see the manifest │ │ as-is, but the canonical build is from the │ │ monorepo so this is non-blocking) │ ├── src/ tests/ examples/ BENCHMARK.md … └── docs/adr/ ← cp'd, only ADR-155…158 ├── ADR-155-rulake-datalake-layer.md ├── ADR-156-rulake-as-memory-substrate.md ├── ADR-157-optional-accelerator-plane.md └── ADR-158-optional-rotation-and-qvcache-positioning.md rsync --delete keeps the mirror an exact reflection; when a file is removed from the monorepo, it vanishes from the mirror on the next sync. Commit message on RuLake is `mirror: ruvnet/ruvector@<12-char>` with a body carrying the full 40-char sha + provenance note. Concurrency: serialized via `group: mirror-rulake` so a quick back-to-back push doesn't race two sync jobs. ONE-TIME SETUP (blocking the first sync until done): 1. Generate a fine-grained PAT at github.com/settings/personal-access-tokens/new scoped to repo: ruvnet/RuLake, permissions: Contents: Read and write 2. Add it as a Repository secret on ruvnet/ruvector named RULAKE_MIRROR_PAT 3. Merge this PR and verify the first run succeeds (workflow_dispatch lets you trigger manually). 4. Optional post-merge: update the README at ruvnet/RuLake to point file references at `crate/...` (currently they link to the ruvector monorepo paths; after first sync, both work but local paths are cleaner). Why not option A (submodule): forces every contributor to run `git submodule update --init`, forces a Cargo.toml rewrite that loses workspace inheritance, splits PR #373's history in two. Option C keeps all tooling working and RuLake always current. Co-Authored-By: claude-flow --- .github/workflows/mirror-rulake.yml | 127 ++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 .github/workflows/mirror-rulake.yml diff --git a/.github/workflows/mirror-rulake.yml b/.github/workflows/mirror-rulake.yml new file mode 100644 index 000000000..f40479904 --- /dev/null +++ b/.github/workflows/mirror-rulake.yml @@ -0,0 +1,127 @@ +name: Mirror ruvector-rulake → ruvnet/RuLake + +# Keeps the public ruvnet/RuLake repo in sync with the canonical +# source at crates/ruvector-rulake/ inside this monorepo. Triggered +# on push to main whenever either the crate or its ADRs change. +# +# ruvnet/RuLake is a **mirror** — do not commit to it directly. +# Changes land there automatically from this workflow with an +# attribution commit message. +# +# One-time setup (operator): +# 1. Generate a fine-grained PAT at +# github.com/settings/personal-access-tokens/new +# with write access to contents of ruvnet/RuLake only. +# 2. Add it as a repository secret on this repo named +# RULAKE_MIRROR_PAT. +# 3. Confirm ruvnet/RuLake exists and the PAT can push to it. +# +# The built-in GITHUB_TOKEN cannot push to another repo, hence the PAT. + +on: + push: + branches: [main] + paths: + - 'crates/ruvector-rulake/**' + - 'docs/adr/ADR-155-*' + - 'docs/adr/ADR-156-*' + - 'docs/adr/ADR-157-*' + - 'docs/adr/ADR-158-*' + - '.github/workflows/mirror-rulake.yml' + workflow_dispatch: {} + +concurrency: + group: mirror-rulake + cancel-in-progress: false + +jobs: + mirror: + name: Sync crate + ADRs to ruvnet/RuLake + runs-on: ubuntu-latest + steps: + - name: Checkout monorepo + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Checkout RuLake mirror + uses: actions/checkout@v4 + with: + repository: ruvnet/RuLake + token: ${{ secrets.RULAKE_MIRROR_PAT }} + path: rulake-mirror + fetch-depth: 1 + + - name: Sync files + run: | + set -euo pipefail + + # /crate/ — the full Rust source tree of the crate. + # --delete keeps the mirror an exact reflection; we never + # carry orphaned files from deleted monorepo paths. + mkdir -p rulake-mirror/crate + rsync -av --delete \ + --exclude='target/' \ + --exclude='.idea/' \ + --exclude='*.rs.bk' \ + crates/ruvector-rulake/ rulake-mirror/crate/ + + # /docs/adr/ — the four ADRs scoped to ruLake. Only ruLake's + # ADRs are copied; the full docs/adr/ tree is not exposed. + mkdir -p rulake-mirror/docs/adr + cp docs/adr/ADR-155-rulake-datalake-layer.md rulake-mirror/docs/adr/ + cp docs/adr/ADR-156-rulake-as-memory-substrate.md rulake-mirror/docs/adr/ + cp docs/adr/ADR-157-optional-accelerator-plane.md rulake-mirror/docs/adr/ + cp docs/adr/ADR-158-optional-rotation-and-qvcache-positioning.md rulake-mirror/docs/adr/ + + # A tombstone marker so humans who stumble into the repo + # understand it's auto-generated. + cat > rulake-mirror/MIRROR.md <<'EOF' + # This is a mirror + + The canonical source lives at + [ruvnet/ruvector](https://github.com/ruvnet/ruvector) under + [`crates/ruvector-rulake/`](https://github.com/ruvnet/ruvector/tree/main/crates/ruvector-rulake). + + Contents of this repo: + - `README.md` — hand-maintained landing page + - `crate/` — **auto-synced** from `crates/ruvector-rulake/` + - `docs/adr/` — **auto-synced** (ADR-155 through ADR-158) + + Do not open PRs against `crate/` or `docs/adr/` here — they + will be overwritten on the next sync. Send changes to + ruvnet/ruvector instead. + + The sync is driven by + [.github/workflows/mirror-rulake.yml](https://github.com/ruvnet/ruvector/blob/main/.github/workflows/mirror-rulake.yml) + and runs on every push to `main` that touches the crate or + its ADRs. + EOF + + - name: Commit & push to RuLake + working-directory: rulake-mirror + env: + UPSTREAM_SHA: ${{ github.sha }} + UPSTREAM_REF: ${{ github.ref_name }} + run: | + set -euo pipefail + git config user.name "ruvnet-mirror-bot" + git config user.email "ruvnet-mirror-bot@users.noreply.github.com" + + if [[ -z "$(git status --porcelain)" ]]; then + echo "no-op: mirror already up to date" + exit 0 + fi + + # Short subject line, full provenance in the body. + git add -A + git commit -m "mirror: ruvnet/ruvector@${UPSTREAM_SHA:0:12} + + Auto-synced from ruvnet/ruvector on ${UPSTREAM_REF}. + + Source commit: https://github.com/ruvnet/ruvector/commit/${UPSTREAM_SHA} + + Do not commit to this repo directly; changes flow from + ruvnet/ruvector via .github/workflows/mirror-rulake.yml." + + git push