diff --git a/lib/sync.sh b/lib/sync.sh index 5476807..0328280 100644 --- a/lib/sync.sh +++ b/lib/sync.sh @@ -131,7 +131,7 @@ ${BOT_TRAILER}: forward/${mono_branch}/$(date -u +%Y-%m-%dT%H:%M:%SZ)" >&2 # ─── Reverse Sync: Subrepo → Monorepo ────────────────────────────── # # Always creates a PR on the monorepo — never pushes directly. -# Returns: skip | pr-created | josh-rejected +# Returns: skip | pr-created reverse_sync() { local mono_branch="$SYNC_BRANCH_MONO" @@ -170,43 +170,56 @@ reverse_sync() { log "INFO" "New human commits to sync:" echo "$human_commits" >&2 - # 4. Merge subrepo changes onto the latest josh-filtered monorepo view - # This ensures the staging branch is based on the latest monorepo main, - # not on the common ancestor between subrepo and monorepo histories. - local subrepo_head - subrepo_head=$(git rev-parse HEAD) + # 4. Clone monorepo directly (not through josh — we need a real branch from main) + local mono_auth_url api_host_path subfolder + api_host_path=$(echo "$MONOREPO_API" | sed 's|https://||; s|/api/v1/repos/|/|') + mono_auth_url="https://${BOT_USER}:${GITEA_TOKEN}@${api_host_path}.git" + subfolder=$(echo "$JOSH_SYNC_TARGETS" | jq -r --arg n "$JOSH_SYNC_TARGET_NAME" \ + '.[] | select(.name == $n) | .subfolder') - git checkout -B sync-push "mono-filtered/${mono_branch}" >&2 - git merge --no-ff "$subrepo_head" \ - -m "Sync from subrepo $(date -u +%Y-%m-%dT%H:%M:%SZ) + git clone "$mono_auth_url" \ + --branch "$mono_branch" --single-branch \ + "${work_dir}/monorepo" || die "Failed to clone monorepo" -${BOT_TRAILER}: reverse/${subrepo_branch}/$(date -u +%Y-%m-%dT%H:%M:%SZ)" >&2 \ - || die "Merge conflict during reverse sync — manual intervention needed" + cd "${work_dir}/monorepo" || exit + git config user.name "$BOT_NAME" + git config user.email "$BOT_EMAIL" - # 5. Push merged branch through josh to a staging branch local ts ts=$(date +%Y%m%d-%H%M%S) local staging_branch="auto-sync/subrepo-${subrepo_branch}-${ts}" + git checkout -B "$staging_branch" >&2 - if git push -o "base=${mono_branch}" "$(josh_auth_url)" "HEAD:refs/heads/${staging_branch}"; then - log "INFO" "Pushed to staging branch via josh: ${staging_branch}" + # 5. Rsync subrepo content into subfolder (--delete handles removals) + mkdir -p "$subfolder" + rsync -a --delete --exclude='.git' "${work_dir}/subrepo/" "${subfolder}/" + git add "$subfolder" - # 6. Create PR on monorepo (NEVER direct push) - local pr_body - pr_body="## Subrepo changes\n\nNew commits from subrepo \`${subrepo_branch}\`:\n\n\`\`\`\n${human_commits}\n\`\`\`\n\n**Review checklist:**\n- [ ] Changes scoped to synced subfolder\n- [ ] No leaked credentials or environment-specific config\n- [ ] CI passes" - - create_pr "${MONOREPO_API}" "${GITEA_TOKEN}" \ - "$mono_branch" "$staging_branch" \ - "[Subrepo Sync] ${subrepo_branch} → ${mono_branch}" \ - "$pr_body" \ - || die "Failed to create PR on monorepo (check GITEA_TOKEN)" - - log "INFO" "Reverse sync PR created on monorepo" - echo "pr-created" - else - log "ERROR" "Josh rejected push — check josh-proxy logs" - echo "josh-rejected" + if git diff --cached --quiet; then + log "INFO" "No tree changes after rsync — skip" + echo "skip" + return fi + + git commit -m "Sync from subrepo/${subrepo_branch} $(date -u +%Y-%m-%dT%H:%M:%SZ) + +${BOT_TRAILER}: reverse/${subrepo_branch}/$(date -u +%Y-%m-%dT%H:%M:%SZ)" >&2 + + # 6. Push branch and create PR on monorepo (NEVER direct push to main) + git push origin "$staging_branch" || die "Failed to push staging branch" + log "INFO" "Pushed staging branch: ${staging_branch}" + + local pr_body + pr_body="## Subrepo changes\n\nNew commits from subrepo \`${subrepo_branch}\`:\n\n\`\`\`\n${human_commits}\n\`\`\`\n\n**Review checklist:**\n- [ ] Changes scoped to synced subfolder\n- [ ] No leaked credentials or environment-specific config\n- [ ] CI passes" + + create_pr "${MONOREPO_API}" "${GITEA_TOKEN}" \ + "$mono_branch" "$staging_branch" \ + "[Subrepo Sync] ${subrepo_branch} → ${mono_branch}" \ + "$pr_body" \ + || die "Failed to create PR on monorepo (check GITEA_TOKEN)" + + log "INFO" "Reverse sync PR created on monorepo" + echo "pr-created" } # ─── Initial Import: Subrepo → Monorepo (first time) ───────────────