Skip to content

Keep upstream files on false rename/delete; add no-vendor go modules hook - #100

Open
RadekManak wants to merge 2 commits into
openshift-eng:mainfrom
RadekManak:fix-false-rename-deletes
Open

Keep upstream files on false rename/delete; add no-vendor go modules hook#100
RadekManak wants to merge 2 commits into
openshift-eng:mainfrom
RadekManak:fix-false-rename-deletes

Conversation

@RadekManak

@RadekManak RadekManak commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Stop auto-deleting unrelated upstream files when cherry-picking large downstream deletes (e.g. vendor/).
  • Add _BUILTIN_/update_go_modules_no_vendor.sh for vendorless repos (tidy/sync only).

Cause

Cherry-picking a mass delete (commonly rm -r vendor) onto a newer upstream tip, git rename detection can treat unrelated new upstream files as renames of deleted vendor paths. Rebasebot then auto-resolved those UD/AU-style conflicts with git rm.

sequenceDiagram
  participant U as Upstream tip
  participant D as Downstream vendor delete
  participant G as git cherry-pick
  participant R as rebasebot resolve

  U->>G: HEAD has new e2e label files
  D->>G: pick deletes many vendor paths
  G->>G: rename detection pairs vendor blob ↔ new file
  G->>R: UD/AU conflict on e2e path
  Note over R: before: always git rm
  R-->>U: upstream source deleted from rebase branch
Loading

Consequence

Real upstream packages disappeared from the rebase branch. Post-rebase go mod tidy (or builds) failed on missing in-repo imports—even though the picked commit never listed those paths. Vendorless downstreams were especially exposed.

Fix

  • Raise cherry-pick rename similarity to find-renames=70 (keep high merge.renameLimit).
  • For delete-shaped conflicts (UD/DU/AU/UA/DD): git rm only if the path is in diff-tree --no-renames --name-only -r <picked-sha>; otherwise restore from HEAD and stage.
  • If resolution leaves no net change vs HEAD, cherry-pick --skip.
  • New builtin _BUILTIN_/update_go_modules_no_vendor.sh (tidy/sync, no vendor) for hermetic/vendorless consumers.

Result

False rename/delete carries keep upstream files; intentional deletes still apply; empty vendor picks skip cleanly. Vendorless repos can tidy modules without recreating vendor/. Verified on an mcp-lifecycle-operator dry-run rebase.

Summary by CodeRabbit

  • New Features

    • Added a hook to update Go dependencies after rebases for repositories without vendored modules.
    • Added support for synchronizing workspace modules or tidying individual modules, with changes committed automatically.
  • Bug Fixes

    • Improved cherry-pick conflict handling, including rename detection and accurate file deletion.
    • Prevented unnecessary commits when conflict resolution produces no changes.
  • Documentation

    • Documented how to update Go modules without a vendor/ directory.
  • Tests

    • Added coverage for Go module updates and rename/delete conflict scenarios.

Raise cherry-pick rename similarity to find-renames=70 and only git-rm
delete-shaped conflicts when the path is in the picked commit's no-rename
diff-tree; otherwise restore from HEAD. Skip empty resolutions.
Provide _BUILTIN_/update_go_modules_no_vendor.sh for vendorless
downstream repos: tidy/sync only, with README and tests.
@openshift-ci
openshift-ci Bot requested a review from nrb August 6, 2026 11:20
@openshift-ci

openshift-ci Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: RadekManak

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci
openshift-ci Bot requested a review from theobarberbany August 6, 2026 11:20
@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Aug 6, 2026
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Walkthrough

The PR updates cherry-pick rename handling and conflict recovery. It adds a post-rebase hook for Go repositories without a vendor/ directory, with module, workspace, and failure tests.

Changes

Cherry-pick conflict handling

Layer / File(s) Summary
Cherry-pick strategy and path tracking
rebasebot/bot.py
Cherry-pick probing and execution use -Xtheirs with a 70% rename-detection threshold. Git paths are decoded, and touched paths are collected without rename detection.
Conflict resolution and regression coverage
rebasebot/bot.py, tests/test_conflict_policy.py
Conflict recovery deletes only paths touched by the picked commit, preserves false rename/delete results, skips empty commits, and covers ASCII and non-ASCII paths.

No-vendor Go module hook

Layer / File(s) Summary
Hook workflow and documentation
rebasebot/builtin-hooks/update_go_modules_no_vendor.sh, README.md
The hook restores module files, runs go work sync or go mod tidy, and commits changes without creating a vendor tree.
Hook behavior tests
tests/test_bot.py
Tests cover module updates, workspace synchronization, commit behavior, invalid go.mod handling, and the absence of a vendor directory.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant RebaseHook
  participant SourceBranch
  participant GoToolchain
  participant GitRepository
  RebaseHook->>SourceBranch: restore Go module files
  RebaseHook->>GoToolchain: run workspace sync or module tidy
  GoToolchain-->>RebaseHook: return command result
  RebaseHook->>GitRepository: stage and commit changes
Loading

Suggested reviewers: mpryc

🚥 Pre-merge checks | ✅ 11
✅ Passed checks (11 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes both main changes: false rename/delete conflict handling and the no-vendor Go modules hook.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
No-Weak-Crypto ✅ Passed The PR adds Git conflict handling, Go module commands, tests, and documentation; no MD5, SHA1, DES, RC4, Blowfish, ECB, custom crypto, or secret comparisons are introduced.
Container-Privileges ✅ Passed The PR changes no container/Kubernetes manifest and adds no privilege settings; pre-existing container builds drop from root to default or UID 1001 before runtime.
No-Sensitive-Data-In-Logs ✅ Passed PR-added logs contain commit SHAs, conflict paths, and generic hook status; the hook uses Git username/email only for commit metadata and does not print credentials, tokens, or PII.
No-Hardcoded-Secrets ✅ Passed The complete PR diff adds no API keys, tokens, passwords, private keys, credential-bearing URLs, or secret-named literal assignments; credential values remain environment/path references.
No-Injection-Vectors ✅ Passed The PR adds no SQL concatenation, eval/exec, pickle or unsafe YAML loads, shell=True, or frontend HTML sink; shell inputs are quoted and test os.system calls use constants.
Ai-Attribution ✅ Passed The two PR commits contain no AI-tool references or attribution trailers; the Claude Co-Authored-By trailer is in the base history, outside this PR.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@rebasebot/bot.py`:
- Around line 404-417: Update _unescape_git_path to encode quoted Git path
content as UTF-8 instead of ASCII before unicode_escape decoding, preserving
literal non-ASCII characters when core.quotePath=false. Add a regression test
covering a quoted path containing non-ASCII characters and verify
_picked_commit_paths completes without raising.

In `@rebasebot/builtin-hooks/update_go_modules_no_vendor.sh`:
- Around line 14-16: Update the hook’s staging and commit guard to scope changes
to the affected go.mod, go.sum, go.work, and go.work.sum paths instead of the
full worktree. Check the scoped index after staging and commit only when those
files have changes, preserving unrelated modifications and avoiding empty
UPSTREAM commits. Add a regression test covering an unrelated worktree change.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift-eng/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 39994a29-de0b-4846-b5bf-08135192c49d

📥 Commits

Reviewing files that changed from the base of the PR and between 49cb18c and e0bdf52.

📒 Files selected for processing (5)
  • README.md
  • rebasebot/bot.py
  • rebasebot/builtin-hooks/update_go_modules_no_vendor.sh
  • tests/test_bot.py
  • tests/test_conflict_policy.py

Comment thread rebasebot/bot.py
Comment on lines +404 to +417
def _unescape_git_path(path: str) -> str:
"""Decode a git C-quoted path from --name-only / status --porcelain output."""
if path.startswith('"') and path.endswith('"'):
path = path[1:-1]
path = path.encode("ascii").decode("unicode_escape").encode("latin1").decode(git.compat.defenc)
return path


def _picked_commit_paths(gitwd: git.Repo, sha: str) -> set[str]:
"""Return paths touched by sha with rename detection disabled."""
output = gitwd.git.diff_tree("--no-renames", "--no-commit-id", "--name-only", "-r", sha)
return {_unescape_git_path(line) for line in output.splitlines() if line}


Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- relevant source ---'
sed -n '380,430p' rebasebot/bot.py
sed -n '680,730p' rebasebot/bot.py
printf '%s\n' '--- usages and tests ---'
rg -n --hidden --glob '!node_modules' '_unescape_git_path|_picked_commit_paths|quotePath|diff_tree|name-only|status --porcelain' .
printf '%s\n' '--- tracked files near tests ---'
git ls-files | rg '(^|/)(test|tests|spec|.*test.*|.*spec.*)' | head -100
printf '%s\n' '--- file metadata ---'
wc -l rebasebot/bot.py

Repository: openshift-eng/rebasebot

Length of output: 5584


🏁 Script executed:

#!/bin/bash
set -eu
sed -n '395,420p' rebasebot/bot.py
sed -n '690,722p' rebasebot/bot.py
rg -n --hidden --glob '!node_modules' '_unescape_git_path|_picked_commit_paths|quotePath|diff_tree|name-only|status --porcelain' .
python3 - <<'PY'
for value in ['"café file.txt"', r'"caf\303\251 file.txt"', r'"caf\351 file.txt"']:
    print('input:', repr(value))
    try:
        result = value[1:-1].encode('ascii').decode('unicode_escape').encode('latin1').decode('utf-8')
        print('ascii conversion result:', repr(result))
    except Exception as exc:
        print('ascii conversion error:', type(exc).__name__, str(exc))
    try:
        result = value[1:-1].encode('utf-8').decode('unicode_escape').encode('latin1').decode('utf-8')
        print('utf8 conversion result:', repr(result))
    except Exception as exc:
        print('utf8 conversion error:', type(exc).__name__, str(exc))
PY

Repository: openshift-eng/rebasebot

Length of output: 4090


Parse quoted Git paths without an ASCII-only conversion.

When core.quotePath=false, Git can emit quoted paths with literal non-ASCII characters. _unescape_git_path then raises UnicodeEncodeError and stops automatic conflict resolution. Use UTF-8 for the conversion and add a regression test for this configuration.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rebasebot/bot.py` around lines 404 - 417, Update _unescape_git_path to encode
quoted Git path content as UTF-8 instead of ASCII before unicode_escape
decoding, preserving literal non-ASCII characters when core.quotePath=false. Add
a regression test covering a quoted path containing non-ASCII characters and
verify _picked_commit_paths completes without raising.

Comment on lines +14 to +16
if [[ -n $(git status --porcelain) ]]; then
git add -A
git commit "${author_flag[@]}" -q -m "UPSTREAM: <drop>: Updating go modules after an upstream rebase"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Stage only files owned by this hook.

git status --porcelain and git add -A use the full worktree. If unrelated files are modified or untracked, this hook commits them in the UPSTREAM commit. This can also create a commit when go mod tidy or go work sync made no change.

Stage only the affected go.mod, go.sum, go.work, and go.work.sum paths. Check the scoped index before committing. Add a regression test with an unrelated worktree change.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rebasebot/builtin-hooks/update_go_modules_no_vendor.sh` around lines 14 - 16,
Update the hook’s staging and commit guard to scope changes to the affected
go.mod, go.sum, go.work, and go.work.sum paths instead of the full worktree.
Check the scoped index after staging and commit only when those files have
changes, preserving unrelated modifications and avoiding empty UPSTREAM commits.
Add a regression test covering an unrelated worktree change.

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

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant