[Team DevTools] Running
td-rebase-pr— from ansible/team-devtools
Print the line above verbatim as the first output when this skill is invoked.
Rebase PR
Check out a PR branch, rebase it onto the base branch (usually main),
push, and poll CI until all jobs complete. Report the result.
This skill does one thing — rebase and report. It does not diagnose or fix CI failures.
Input
Required:
- repo — e.g.,
ansible/vscode-ansible - PR number — e.g.,
2716
Entry Gate
gh auth status
If not authenticated, stop.
Verify the PR exists and is open:
gh pr view PR_NUMBER --repo OWNER/REPO \
--json state,headRefName,baseRefName \
--jq '{state, head: .headRefName, base: .baseRefName}'
If the PR is not open, stop.
Step 1 — Check out the PR branch
If the target repo is your current working directory:
gh pr checkout PR_NUMBER
Otherwise clone first:
gh repo clone OWNER/REPO /tmp/rebase-pr-REPO
cd /tmp/rebase-pr-REPO
gh pr checkout PR_NUMBER
Step 2 — Check if rebase is needed
git fetch origin BASE_BRANCH
git log --oneline origin/BASE_BRANCH..HEAD | wc -l
git merge-base --is-ancestor origin/BASE_BRANCH HEAD && echo "UP_TO_DATE" || echo "BEHIND"
If UP_TO_DATE, the branch already includes all commits from the base
branch. No rebase or push is needed — no new CI run will be triggered.
Skip to Step 5 and report the existing CI results. Make it clear in the
output that these are existing results, not from a new run.
Step 3 — Rebase
git rebase origin/BASE_BRANCH
If rebase succeeds cleanly:
Push the rebased branch:
source ~/.ansibuddy_env 2>/dev/null || true && git push --force-with-lease
If push is rejected, stop and report:
**Action taken:** push rejected (branch was modified remotely)
Do not attempt to pull and reconcile — the bot branch moved under you. The orchestrator can decide to retry or skip.
If the PR head branch is on a fork (different owner than the repo),
--force-with-lease will fail because you lack push access to the fork.
Report that fork PRs cannot be rebased by this skill and stop.
If rebase has conflicts:
Count the conflicting files:
git diff --name-only --diff-filter=U
If 3 or fewer files conflict, attempt resolution:
- For lock files (
pnpm-lock.yaml,uv.lock,yarn.lock): accept theirs and complete the rebase, then regenerate in Step 3a. - For other files: abort and report that manual conflict resolution is needed.
git checkout --theirs pnpm-lock.yaml # or uv.lock, yarn.lock
git add pnpm-lock.yaml
git rebase --continue
If more than 3 files conflict or non-lock-file conflicts exist:
git rebase --abort
Report that the rebase has conflicts requiring manual resolution and stop.
Step 3a — Regenerate lockfiles (after conflict resolution)
This step runs only when Step 3 resolved lockfile conflicts with
--theirs. If the rebase completed cleanly (no conflicts), skip
straight to the push in Step 3.
Detect toolchain
if Taskfile.yml exists AND package.json exists -> TypeScript (pnpm)
elif tox.ini exists -> Python (uv)
elif pyproject.toml exists (no tox.ini) -> Python (uv)
else -> Unknown
If unknown, abort and report:
**Action taken:** lockfile conflict resolved but toolchain unknown — cannot regenerate. Closing PR so Renovate can recreate from current main.
Close the PR with a comment explaining why:
gh pr close PR_NUMBER --repo OWNER/REPO \
--comment "Lockfile conflict could not be safely regenerated (unknown toolchain). Renovate will recreate this PR from current main."
Stop.
Run regeneration
# TypeScript
pnpm install
# Python (tox or uv)
uv lock
If the regeneration command exits non-zero, abort and report:
**Action taken:** lockfile regeneration failed (COMMAND exited CODE). Closing PR so Renovate can recreate from current main.
Close the PR with a comment and stop.
Verify gate
The regenerated lockfile must differ from what --theirs produced.
If it does not, the resolution was a no-op and the lockfile may carry
stale pins.
git diff --exit-code uv.lock # or pnpm-lock.yaml
If
git diff --exit-codereturns 1 (file changed): the regeneration produced a fresh lockfile. Stage and commit it:git add uv.lock # or pnpm-lock.yaml git commit -m "chore: regenerate lockfile after rebase conflict resolution"If
git diff --exit-codereturns 0 (no change): the lockfile is identical to the--theirsversion. This is acceptable only if the PR's lockfile changes were already consistent with main. Log a warning but proceed:**Warning:** lockfile unchanged after regeneration — --theirs resolution matched current state
Push
source ~/.ansibuddy_env 2>/dev/null || true && git push --force-with-lease
If push is rejected, stop and report as described in Step 3.
Step 4 — Poll CI until complete
Poll every 60 seconds until no jobs are IN_PROGRESS or PENDING.
If after 5 minutes no checks have appeared at all (CI never started), report a timeout and stop — workflows may be disabled or misconfigured.
Once at least one check is running or completed, keep polling with no time limit until all jobs finish. CI duration varies across repos — some jobs take 5 minutes, others 30+.
elapsed=0
while true; do
checks=$(gh pr checks PR_NUMBER --repo OWNER/REPO \
--json name,state --jq '.[] | select(.state != "SKIPPED")')
total=$(echo "$checks" | grep -c . || true)
pending=$(echo "$checks" | grep -cE "IN_PROGRESS|PENDING|QUEUED" || true)
# CI never started — timeout after 5 minutes
if [ "$total" -eq 0 ] && [ "$elapsed" -ge 300 ]; then
echo "TIMEOUT: no checks appeared after 5 minutes"
break
fi
# All checks finished
if [ "$total" -gt 0 ] && [ "$pending" -eq 0 ]; then
break
fi
sleep 60
elapsed=$((elapsed + 60))
done
If the loop exits due to timeout, report:
**CI run:** timed out (no checks appeared after 5 minutes)
Step 5 — Report result
After CI completes, check for code failures (applying the same skip list
as td-scan-bot-prs):
gh pr checks PR_NUMBER --repo OWNER/REPO \
--json name,state --jq '.[] | select(.state == "FAILURE" or .state == "ERROR") | .name'
Skip list (not code failures):
codecov/project,codecov/patchdocs/readthedocs.org:*ack / ackrenovate/stability-days,renovate/artifactsSonarCloud Code Analysis
Output format
## Rebase Result
**Repo:** OWNER/REPO
**PR:** #NUMBER — TITLE
**Action taken:** rebased onto BASE_BRANCH / rebased onto BASE_BRANCH (lockfile regenerated) / already up to date / conflicts (aborted) / lockfile regen failed (PR closed)
**CI run:** new (triggered by push) / existing (no push, reporting old results)
**CI result:** all passing / N code failures
### Failing checks (if any)
- check_name_1
- check_name_2
If all code checks pass: report success. The rebase fixed it.
If code checks still fail: report the failing check names. The
orchestrator will pass these to td-diagnose-ci.