Skip to content

refactor: migrate cherry-pick PR creation from hub to gh CLI#1024

Merged
myakove merged 3 commits intomainfrom
refactor/issue-1023-hub-to-gh-cli
Mar 12, 2026
Merged

refactor: migrate cherry-pick PR creation from hub to gh CLI#1024
myakove merged 3 commits intomainfrom
refactor/issue-1023-hub-to-gh-cli

Conversation

@myakove
Copy link
Copy Markdown
Collaborator

@myakove myakove commented Mar 12, 2026

Summary

Replace the deprecated hub CLI (v2.14.2, archived project) with the official gh CLI for creating cherry-pick pull requests.

Closes #1023

Changes

Dockerfile

  • Added gh to dnf install packages
  • Removed manual hub tarball download and installation

webhook_server/libs/handlers/runner_handler.py

  • Replaced hub pull-request command with gh pr create
  • Flag mapping: -b--base, -h--head, -l--label, -a--assignee, -m--title/--body
  • Added --repo flag for explicit repository targeting
  • Proper shlex.quote() on all user-provided values
  • Uses GH_TOKEN env var for authentication

webhook_server/tests/test_runner_handler.py

  • Updated cherry-pick test assertions for gh CLI flags

Notes

Summary by CodeRabbit

  • Chores
    • Switched PR creation to the GitHub CLI (gh pr create), added PR title/body metadata, and adjusted auth to use GH_TOKEN; updated image build to include gh tools. Updated logging and secret redaction around PR creation.
  • Tests
    • Updated tests to validate the new gh command format, the --assignee flag, and revised PR message content.

Replace deprecated hub CLI (v2.14.2, archived) with official gh CLI
for creating cherry-pick pull requests.

Changes:
- Dockerfile: replace hub installation with gh CLI v2.67.0
- runner_handler.py: replace `hub pull-request` with `gh pr create`
- tests: update cherry-pick test assertions for gh CLI flags

Signed-off-by: Meni Yakove <myakove@gmail.com>
@myakove-bot
Copy link
Copy Markdown
Collaborator

Report bugs in Issues

Welcome! 🎉

This pull request will be automatically processed with the following features:

🔄 Automatic Actions

  • Reviewer Assignment: Reviewers are automatically assigned based on the OWNERS file in the repository root
  • Size Labeling: PR size labels (XS, S, M, L, XL, XXL) are automatically applied based on changes
  • Issue Creation: Disabled for this repository
  • Pre-commit Checks: pre-commit runs automatically if .pre-commit-config.yaml exists
  • Branch Labeling: Branch-specific labels are applied to track the target branch
  • Auto-verification: Auto-verified users have their PRs automatically marked as verified
  • Labels: All label categories are enabled (default configuration)

📋 Available Commands

PR Status Management

  • /wip - Mark PR as work in progress (adds WIP: prefix to title)
  • /wip cancel - Remove work in progress status
  • /hold - Block PR merging (approvers only)
  • /hold cancel - Unblock PR merging
  • /verified - Mark PR as verified
  • /verified cancel - Remove verification status
  • /reprocess - Trigger complete PR workflow reprocessing (useful if webhook failed or configuration changed)
  • /regenerate-welcome - Regenerate this welcome message

Review & Approval

  • /lgtm - Approve changes (looks good to me)
  • /approve - Approve PR (approvers only)
  • /automerge - Enable automatic merging when all requirements are met (maintainers and approvers only)
  • /assign-reviewers - Assign reviewers based on OWNERS file
  • /assign-reviewer @username - Assign specific reviewer
  • /check-can-merge - Check if PR meets merge requirements

Testing & Validation

  • /retest tox - Run Python test suite with tox
  • /retest build-container - Rebuild and test container image
  • /retest python-module-install - Test Python package installation
  • /retest pre-commit - Run pre-commit hooks and checks
  • /retest conventional-title - Validate commit message format
  • /retest all - Run all available tests

Container Operations

  • /build-and-push-container - Build and push container image (tagged with PR number)
    • Supports additional build arguments: /build-and-push-container --build-arg KEY=value

Cherry-pick Operations

  • /cherry-pick <branch> - Schedule cherry-pick to target branch when PR is merged
    • Multiple branches: /cherry-pick branch1 branch2 branch3

Label Management

  • /<label-name> - Add a label to the PR
  • /<label-name> cancel - Remove a label from the PR

✅ Merge Requirements

This PR will be automatically approved when the following conditions are met:

  1. Approval: /approve from at least one approver
  2. LGTM Count: Minimum 1 /lgtm from reviewers
  3. Status Checks: All required status checks must pass
  4. No Blockers: No wip, hold, has-conflicts labels and PR must be mergeable (no conflicts)
  5. Verified: PR must be marked as verified

📊 Review Process

Approvers and Reviewers

Approvers:

  • myakove
  • rnetser

Reviewers:

  • myakove
  • rnetser
Available Labels
  • hold
  • verified
  • wip
  • lgtm
  • approve
  • automerge

💡 Tips

  • WIP Status: Use /wip when your PR is not ready for review
  • Verification: The verified label is automatically removed on each new commit
  • Cherry-picking: Cherry-pick labels are processed when the PR is merged
  • Container Builds: Container images are automatically tagged with the PR number
  • Permission Levels: Some commands require approver permissions
  • Auto-verified Users: Certain users have automatic verification and merge privileges

For more information, please refer to the project documentation or contact the maintainers.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 12, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d574f9a4-0005-4dfe-a3f4-88e2c4e327ff

📥 Commits

Reviewing files that changed from the base of the PR and between beb4924 and 1fce322.

📒 Files selected for processing (1)
  • webhook_server/libs/handlers/runner_handler.py

Walkthrough

Replaces deprecated hub PR creation with GitHub's gh CLI: Dockerfile now installs gh, runner_handler.py builds and runs gh pr create (uses GH_TOKEN/GITHUB_TOKEN, --assignee, --title, --body, --label), and tests updated to assert the new gh command form. (37 words)

Changes

Cohort / File(s) Summary
Build Configuration
Dockerfile
Removed hub install/tarball steps; added gh package to the initial RUN installation step; removed separate hub setup and related chmod/download lines.
Cherry-pick Handler
webhook_server/libs/handlers/runner_handler.py
Replaced hub pull-request usage with gh pr create; switched flags (-b--base, -h--head, -l--label, -a--assignee, -m--title/--body); constructs pr_title/pr_body, uses GH_TOKEN env, runs gh after git ops, and redacts secrets in logs.
Handler Tests
webhook_server/tests/test_runner_handler.py
Updated tests to look for --assignee (and author) in the constructed command, renamed hub_commandgh_command, and adjusted assertions to match new gh pr create command structure.

Sequence Diagram(s)

sequenceDiagram
    participant Runner as Runner Handler
    participant Git as Local Git (worktree)
    participant GH as gh CLI
    participant GitHub as GitHub API

    Runner->>Git: create worktree, cherry-pick, commit, push branch
    Runner->>GH: run `gh pr create --base ... --head ... --title ... --body ... [--assignee ...]` (via GH_TOKEN)
    GH->>GitHub: call GitHub API to create PR (labels, assignee, title, body)
    GitHub-->>GH: return PR URL/response
    GH-->>Runner: stdout (PR URL)
    Runner->>Runner: redact secrets in logs, record PR URL
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

size/L, commented-coderabbitai[bot]

Suggested reviewers

  • rnetser
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main objective: migrating cherry-pick PR creation from the deprecated hub CLI to the official gh CLI, which aligns with the primary change across all modified files.
Linked Issues check ✅ Passed All coding requirements from issue #1023 are met: hub replaced with gh pr create in runner_handler.py, Dockerfile updated to install gh and remove hub, flag mappings implemented correctly (--base, --head, --label, --assignee, --title, --body), GH_TOKEN authentication configured, and tests updated for gh CLI usage.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the hub-to-gh migration. The commit message mentions additional error handling (early return on worktree failure and PR creation failure comment), which represents a minor scope expansion but aligns with defensive improvements to the cherry-pick flow being refactored.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/issue-1023-hub-to-gh-cli

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@qodo-code-review
Copy link
Copy Markdown

ⓘ You are approaching your monthly quota for Qodo. Upgrade your plan

Review Summary by Qodo

Migrate cherry-pick PR creation from hub to gh CLI

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Replace deprecated hub CLI with official gh CLI for cherry-pick PR creation
• Update Dockerfile to install gh instead of hub tarball
• Refactor command construction with proper flag mapping and quoting
• Update test assertions to validate gh CLI command structure
Diagram
flowchart LR
  A["hub CLI<br/>v2.14.2<br/>deprecated"] -->|"replace with"| B["gh CLI<br/>v2.67.0<br/>official"]
  C["Dockerfile<br/>hub tarball"] -->|"simplify to"| D["dnf install gh"]
  E["runner_handler.py<br/>hub pull-request"] -->|"migrate to"| F["gh pr create<br/>with proper flags"]
  G["test assertions<br/>hub flags"] -->|"update to"| H["gh flags<br/>validation"]
Loading

Grey Divider

File Changes

1. webhook_server/libs/handlers/runner_handler.py ✨ Enhancement +13/-7

Migrate cherry-pick command from hub to gh CLI

• Replaced hub pull-request command with gh pr create for cherry-pick PR creation
• Updated flag mapping: -b to --base, -h to --head, -l to --label, -a to --assignee,
 -m to --title/--body
• Added --repo flag with explicit repository targeting using repo_full_name
• Applied shlex.quote() to all user-provided values for proper escaping
• Changed authentication from GITHUB_TOKEN to GH_TOKEN environment variable
• Extracted PR title and body into separate variables for clarity

webhook_server/libs/handlers/runner_handler.py


2. webhook_server/tests/test_runner_handler.py 🧪 Tests +8/-8

Update cherry-pick test assertions for gh CLI

• Updated test_cherry_pick_assigns_pr_author to validate --assignee flag instead of -a
• Updated test_cherry_pick_requested_by_uses_pr_owner to check for gh CLI flags and command
 structure
• Simplified assertions to verify presence of key command components rather than exact flag syntax
• Changed variable naming from hub_command to gh_command for clarity

webhook_server/tests/test_runner_handler.py


3. Dockerfile ⚙️ Configuration changes +2/-3

Replace hub tarball with gh package installation

• Added gh package to dnf install command for official GitHub CLI
• Removed manual hub tarball download and installation from GitHub releases
• Simplified build process by using package manager instead of manual binary extraction

Dockerfile


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Mar 12, 2026

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (1)

Grey Divider


Action required

1. GH_TOKEN prefix breaks execution📎 Requirement gap ⛯ Reliability
Description
The new gh pr create invocation prefixes the command with GH_TOKEN=..., but run_command() uses
asyncio.create_subprocess_exec (no shell) so this will be treated as the executable name and the
PR creation/authentication will fail. This risks breaking the non-interactive cherry-pick PR
creation flow due to missing/incorrect authentication.
Code

webhook_server/libs/handlers/runner_handler.py[R729-735]

+                    f"GH_TOKEN={github_token} gh pr create --repo {shlex.quote(repo_full_name)}"
+                    f" --base {shlex.quote(target_branch)}"
+                    f" --head {shlex.quote(new_branch_name)}"
+                    f" --label {shlex.quote(CHERRY_PICKED_LABEL)}"
+                    f"{assignee_flag}"
+                    f" --title {shlex.quote(pr_title)}"
+                    f" --body {shlex.quote(pr_body)}",
Evidence
Compliance requires gh pr create to work non-interactively using GH_TOKEN/GITHUB_TOKEN. The PR
constructs a command string starting with GH_TOKEN=..., but the command runner splits the string
and executes it directly without a shell, so the env-var assignment syntax is not applied and will
likely fail to execute/authenticate.

Verify gh CLI authentication works in the cherry-pick PR creation flow
webhook_server/libs/handlers/runner_handler.py[729-735]
webhook_server/utils/helpers.py[272-326]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`GH_TOKEN=... gh pr create ...` is being executed via `asyncio.create_subprocess_exec` with `shlex.split`, so the `GH_TOKEN=...` prefix is treated as the executable name rather than an environment variable assignment. This breaks non-interactive authentication for `gh pr create`.
## Issue Context
`run_command()` explicitly does not use `shell=True`, so shell-style environment assignments must be provided via the `env` argument (or the command must be explicitly wrapped with `/bin/sh -c ...`).
## Fix Focus Areas
- webhook_server/libs/handlers/runner_handler.py[729-735]
- webhook_server/utils/helpers.py[272-326]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment thread webhook_server/libs/handlers/runner_handler.py Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@webhook_server/libs/handlers/runner_handler.py`:
- Around line 729-735: The command string currently prefixes
GH_TOKEN={github_token} which exposes github_token in process listings; update
the code that builds and calls the command (the invocation that uses
github_token, repo_full_name, target_branch, new_branch_name,
CHERRY_PICKED_LABEL, assignee_flag, pr_title, pr_body) to stop injecting
GH_TOKEN into the command string and instead pass the token via an environment
dict to run_command (or add an env parameter to run_command if it doesn't exist)
so GH_TOKEN is set in the child process environment securely rather than as a
command-line argument.
🪄 Autofix (Beta)

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a06a0e2a-8bfc-4aff-8a68-093f8ab8550e

📥 Commits

Reviewing files that changed from the base of the PR and between deebc27 and f284e73.

📒 Files selected for processing (3)
  • Dockerfile
  • webhook_server/libs/handlers/runner_handler.py
  • webhook_server/tests/test_runner_handler.py

Comment thread webhook_server/libs/handlers/runner_handler.py Outdated
coderabbitai[bot]
coderabbitai Bot previously approved these changes Mar 12, 2026
The `run_command()` function uses `asyncio.create_subprocess_exec` (no
shell), so `GH_TOKEN=... gh pr create` treated `GH_TOKEN=...` as the
executable name. Fix by passing the token via the `env` kwarg to
`run_command()`, which forwards it to `create_subprocess_exec`.

Each subprocess gets its own isolated env copy, so parallel execution
with different tokens per repo is safe.

Signed-off-by: Meni Yakove <myakove@gmail.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
webhook_server/libs/handlers/runner_handler.py (1)

746-750: ⚠️ Potential issue | 🔴 Critical

CRITICAL: return immediately after worktree setup fails.

Line 750 still enters the git loop after Lines 746-748 already marked the check failed. That can turn a repository-preparation error into a misleading cherry-pick failure and overwrite the real root cause. Fail fast here.

Suggested fix
                 if not success:
                     output["text"] = self.check_run_handler.get_check_run_text(out=out, err=err)
                     await self.check_run_handler.set_check_failure(name=CHERRY_PICKED_LABEL, output=output)
+                    return
 
                 for cmd in git_commands:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@webhook_server/libs/handlers/runner_handler.py` around lines 746 - 750, The
code currently continues into the git_commands loop even when worktree setup
fails (success is False) and after calling
self.check_run_handler.set_check_failure, which masks the real error; modify the
control flow in the method containing this block (runner handler function in
runner_handler.py) so that when success is False you immediately return (or
otherwise exit) after populating output and awaiting
self.check_run_handler.set_check_failure(name=CHERRY_PICKED_LABEL,
output=output), preventing execution of the subsequent for cmd in git_commands
loop and ensuring the real repository-preparation failure is reported.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@webhook_server/libs/handlers/runner_handler.py`:
- Around line 797-813: When gh pr create fails (the rc==False branch handled
with self.check_run_handler.get_check_run_text and set_check_failure), post an
actionable comment back on the source PR that includes the cherry-pick branch
name and the exact gh pr command to run (redacting tokens the same way
_redact_secrets is used), plus the redacted stdout/stderr and a short manual
recovery instruction; use the existing check-run helper on
self.check_run_handler (e.g., use its comment/issue comment method) to add this
message before returning, and keep the existing set_check_failure and
logger.error behavior.

---

Outside diff comments:
In `@webhook_server/libs/handlers/runner_handler.py`:
- Around line 746-750: The code currently continues into the git_commands loop
even when worktree setup fails (success is False) and after calling
self.check_run_handler.set_check_failure, which masks the real error; modify the
control flow in the method containing this block (runner handler function in
runner_handler.py) so that when success is False you immediately return (or
otherwise exit) after populating output and awaiting
self.check_run_handler.set_check_failure(name=CHERRY_PICKED_LABEL,
output=output), preventing execution of the subsequent for cmd in git_commands
loop and ensuring the real repository-preparation failure is reported.
🪄 Autofix (Beta)

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ca29e3b5-5006-4bf1-b303-1fb89df431b6

📥 Commits

Reviewing files that changed from the base of the PR and between f284e73 and beb4924.

📒 Files selected for processing (1)
  • webhook_server/libs/handlers/runner_handler.py

Comment thread webhook_server/libs/handlers/runner_handler.py
coderabbitai[bot]
coderabbitai Bot previously approved these changes Mar 12, 2026
…R creation failure

- Add `return` after worktree setup failure to prevent fall-through
  into git commands loop (pre-existing bug)
- Add PR comment with manual recovery instructions when `gh pr create`
  fails but branch was already pushed

Signed-off-by: Meni Yakove <myakove@gmail.com>
@myakove
Copy link
Copy Markdown
Collaborator Author

myakove commented Mar 12, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 12, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@rnetser
Copy link
Copy Markdown
Collaborator

rnetser commented Mar 12, 2026

/approve
/lgtm

Comment thread Dockerfile
@myakove
Copy link
Copy Markdown
Collaborator Author

myakove commented Mar 12, 2026

/verified

@myakove myakove enabled auto-merge (squash) March 12, 2026 10:34
@myakove myakove merged commit de61dd4 into main Mar 12, 2026
9 checks passed
@myakove myakove deleted the refactor/issue-1023-hub-to-gh-cli branch March 12, 2026 10:35
@myakove-bot
Copy link
Copy Markdown
Collaborator

New container for ghcr.io/myk-org/github-webhook-server:latest published

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor: migrate cherry-pick PR creation from hub to gh CLI

3 participants