Skip to content

Build PR CLI with per-repo workflow enforcement #6

Description

@jordanpartridge

Context

Repeated failures using gh CLI + jq for PR operations:

  • 3 failed jq attempts to answer "who reviewed my PRs today" (null handling, escaping)
  • Merged PSTrax PR with --merge instead of required --squash - no guardrails
  • Basic queries ("my open PRs", "what merged today") require fragile shell gymnastics

The domain layer already exists: conduit-ui/pr has 27 Saloon request classes, DTOs, QueryBuilder, GitHubPrService, PullRequest entity with chainable actions. This repo is empty. We need the CLI layer.

Approach

Laravel Zero CLI app consuming conduit-ui/pr + conduit-ui/connector. Per-repo workflow config enforces merge strategy, required reviews, and base branch. No new Saloon requests needed.

Workflow Config (config/workflows.php)

return [
    'github_user' => env('GITHUB_USER', 'jordanpartridge'),
    'defaults' => [
        'merge_strategy' => 'merge',
        'base_branch' => 'main',
        'delete_branch' => true,
        'required_reviews' => 0,
    ],
    'repos' => [
        'PSTrax/pstrax-laravel' => [
            'merge_strategy' => 'squash',
            'base_branch' => 'development',
            'required_reviews' => 1,
        ],
        'conduit-ui/*' => [
            'merge_strategy' => 'merge',
            'base_branch' => 'main',
        ],
    ],
    'monitored_repos' => [
        'PSTrax/pstrax-laravel',
        'conduit-ui/connector',
        'conduit-ui/pr',
        'conduit-ui/knowledge',
        'jordanpartridge/agentctl',
        'jordanpartridge/triage-agent',
    ],
];

Commands

Command Purpose
pr list List PRs with --repo --state --author --label filtering
pr show <number> PR details, diff stats, reviews, checks
pr merge <number> Merge with per-repo strategy enforcement + guards
pr reviews "Who reviewed my PRs today?" / "What reviews did I give?"
pr my My open PRs across monitored repos
pr merged Recently merged PRs with date filtering
pr review <number> Submit approval/request-changes/comment

Critical: pr merge Guards

pr merge {number} {--repo=} {--strategy=} {--force} {--dry-run}
  1. Fetch PR via PrServiceInterface::find()
  2. Resolve workflow via WorkflowResolver::forRepo() (glob match)
  3. Run guards (unless --force):
    • PR is open and mergeable
    • Required approvals met
    • CI checks passed
  4. Display config + guard results, confirm with user
  5. Execute merge with enforced strategy

Project Structure

pr-cli/
├── pr                                  # Binary entrypoint
├── composer.json                       # conduit-ui/pr + laravel-zero/framework
├── config/
│   ├── app.php
│   ├── workflows.php                   # Per-repo config
│   └── pr.php                          # Token config
├── app/
│   ├── Providers/AppServiceProvider.php
│   ├── Config/WorkflowResolver.php     # Glob-match repo to workflow
│   ├── Concerns/
│   │   ├── ResolvesRepository.php      # --repo or detect from git remote
│   │   └── EnforcesWorkflow.php        # Merge guard checks
│   ├── Commands/                       # 7 commands listed above
│   └── Output/PullRequestRenderer.php
└── tests/
    ├── Unit/WorkflowResolverTest.php
    └── Feature/MergeCommandTest.php

Implementation Order

  1. Scaffold - composer.json (VCS repos for packages not on Packagist), bootstrap, configs
  2. WorkflowResolver + ResolvesRepository trait
  3. ListCommand - simplest, proves the stack
  4. MergeCommand + EnforcesWorkflow - the pain-point command
  5. ReviewsCommand - the "who reviewed my PRs" query
  6. Remaining commands (MyCommand, MergedCommand, ShowCommand, ReviewCommand)
  7. Tests - WorkflowResolver unit, MergeCommand feature (guard enforcement)
  8. Package - box.json, pint.json, symlink to ~/.local/bin/pr

Acceptance Criteria

  • pr list --repo=conduit-ui/connector returns typed, formatted results
  • pr merge enforces squash for PSTrax repos by default
  • pr merge blocks when required reviews not met (unless --force)
  • pr reviews --since=today answers "who reviewed my PRs" reliably
  • pr my shows open PRs across monitored repos
  • All tests pass, Pint clean

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent-readyReady for agent to implement

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions