Skip to content

Conversation

@luqven
Copy link
Owner

@luqven luqven commented Dec 29, 2025

Summary

  • Parallelizes CI check and mergeable status fetches using futures::join_all
  • Reduces gh-stack status time from ~8s to ~3.3s for a 7-PR stack
  • Uses PrCheckData struct to separate non-async data collection from async fetches

Performance

Command Before After
status (7 PRs) ~8s ~3.3s
status --no-checks ~2.2s ~2.2s

Changes

  • Add PrCheckData struct for intermediate data collection
  • Add fetch_pr_status() helper that fetches CI and mergeable in parallel
  • Refactor build_status_entries() to batch all status fetches

Part of smart-log stack

This PR builds on #41 (batch PR fetch) and completes the performance optimization work.

Stacked PR Chain: smart-log

PR Title Merges Into
#35 feat: add stack discovery API -
#36 feat: add rate limit retry logic #35
#37 feat: add identifier detection and prompts #36
#38 feat: add gh CLI helpers #37
#39 feat: make log and status identifier optional with branch inference #38
#40 docs: update log and status documentation for smart defaults #39
#41 perf: optimize stack discovery with batch fetch #40
#42 👉perf: parallelize status check fetches #41

Add src/api/stack.rs module for discovering PR stacks by walking
the base/head branch chain. This enables gh-stack to find related
PRs without requiring identifier patterns in titles.

New functions:
- fetch_pr_by_head: Find PR by head branch name
- fetch_prs_by_base: Find all PRs targeting a base branch
- fetch_all_open_prs: Get all open PRs in a repo
- discover_stack: Walk up/down to find full connected stack
- discover_all_stacks: Group all PRs into separate stacks

Includes 9 unit tests with mockito for API calls.
Add automatic retry with exponential backoff for GitHub API rate limits.

New functionality in src/api/mod.rs:
- RateLimitError struct with reset time info and Display impl
- parse_rate_limit_headers() to extract X-RateLimit-* headers
- is_rate_limited() to detect 429 and 403 with rate limit headers
- send_with_retry() for automatic retry with exponential backoff

Retries up to 3 times with 1s, 2s, 4s delays before returning
a RateLimitError with helpful message showing when to retry.

Includes 6 new tests for retry logic.
Add src/identifier.rs module for trunk branch detection and
interactive stack selection prompts.

New types and functions:
- StackSummary: Display info for a stack (branch, PR count, numbers)
- is_trunk_branch(): Check if branch is a trunk (main, master, etc.)
- detect_trunk_branch(): Get default branch from git remote
- TrunkAction: Enum for user choices when on trunk
- prompt_trunk_action(): Interactive menu for trunk branch
- prompt_select_stack(): Let user pick from stack list
- prompt_identifier(): Manual identifier entry

Includes 12 unit tests for trunk detection and summary formatting.
Add src/gh_cli.rs module for GitHub CLI detection and installation
hints to help users create PRs when none exist for a branch.

New functions:
- is_gh_installed(): Check if gh CLI is available
- is_gh_authenticated(): Check if gh is logged in
- install_instructions(): Platform-specific install commands
- suggest_create_pr(): Print gh pr create command with hints
- prompt_create_pr(): Interactive PR creation prompt

The module handles non-TTY environments gracefully and provides
helpful messages when gh is not installed or not authenticated.

Includes 3 unit tests.
Enable gh-stack log to work without an explicit identifier by
inferring the stack from the current branch's PR chain.

New CLI arguments for log command:
- --branch, -b: Infer stack from specified branch
- --all, -a: List all stacks and select interactively
- --ci: Non-interactive mode for CI environments
- --trunk: Override trunk branch detection

Behavior changes:
- Running 'gh-stack log' without args infers from current branch
- On trunk branch: prompts to enter identifier or select stack
- No PR found: suggests gh pr create command
- CI mode requires explicit identifier or --branch flag

The identifier argument is now optional but still fully supported
for backwards compatibility.
Apply the same smart default behavior from log to status command:

New CLI arguments for status command:
- --branch, -b: Infer stack from specified branch
- --all, -a: List all stacks and select interactively
- --ci: Non-interactive mode for CI environments
- --trunk: Override trunk branch detection

The identifier argument is now optional. Running 'gh-stack status'
without args infers the stack from the current branch's PR chain.

JSON output mode handles errors gracefully with error field in response.
Update docs/log.md to document the new smart default behavior:

- Stack discovery from current branch
- New flags: --branch, --all, --ci, --trunk
- CI usage examples
- On trunk branch behavior
- No PR found behavior with gh pr create suggestion

Also add reference to status command in 'See also' section.
Update docs/status.md to document the new smart default behavior:

- Stack discovery from current branch
- New flags: --branch, --all, --ci, --trunk
- CI usage examples
- Updated options table with new flags
- Reorganized examples section
Replace sequential API calls with batch-fetch strategy:
- Fetch all open PRs in one paginated request (up to 1000 PRs)
- Walk the PR chain in-memory using PrIndex lookup structure
- Reduces API calls from O(N) to O(1) for stack discovery

Changes:
- Add pagination support to fetch_all_open_prs (MAX_PAGES=10)
- Add PrIndex struct for fast in-memory head/base lookups
- Refactor discover_stack to use batch fetch + in-memory walk
- Extract discover_stack_from_index for pure in-memory operation
- Extract group_into_stacks for reuse between functions

Performance improvement:
- Before: ~12 sequential API calls for 6-PR stack (~6+ seconds)
- After: 1-2 API calls for any stack size (~2 seconds)

Enterprise support:
- Pagination handles repos with 100+ open PRs
- Capped at 1000 PRs (10 pages) for safety

Adds 11 new tests for PrIndex, batch fetch, and pagination.
Use futures::join_all to fetch CI checks and mergeable status
for all PRs in parallel instead of sequentially.

- Add PrCheckData struct to collect PR data in non-async pass
- Add fetch_pr_status helper to fetch CI and mergeable in parallel
- Refactor build_status_entries to batch fetch all status checks

Performance: ~3.3s for 7-PR stack (down from ~8s sequential)
Replace gh CLI with native Rust implementations:
- Add browser.rs for cross-platform browser opening and URL generation
- Add api/create.rs for GitHub API PR creation
- Add --create-pr flag for API-based PR creation
- Poll for PR after browser-based creation (30s timeout)
- Support GitHub Enterprise via remote URL parsing
- Add first_commit_message() and get_remote_url() helpers to tree.rs

New features:
- Interactive mode opens browser to create PR, then polls for it
- --create-pr flag creates PR via API with prompts for title/body
- CI mode prints PR creation URL

Removes: src/gh_cli.rs (no longer needed)
@luqven luqven changed the base branch from smart-log/7-perf-optimization to master December 30, 2025 00:58
@luqven luqven merged commit b4d9c08 into master Dec 30, 2025
@luqven luqven deleted the smart-log/8-parallel-status-checks branch December 30, 2025 00:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants