-
Notifications
You must be signed in to change notification settings - Fork 8
Add Get, Update, and Comment commands for pull requests #546
Description
Context
The GitHub PowerShell module is used to automate repository management tasks, including workflows that create and manage pull requests. For example, in PSModule/GoogleFonts, an automated workflow updates font data and opens a PR. When a new Auto-Update PR is created, older Auto-Update PRs should be commented on (explaining they are superseded) and then closed.
Currently, no commands exist in the module for interacting with pull requests. The only workaround is shelling out to the gh CLI, which breaks consistency with the rest of the module and loses the typed object pipeline experience.
Request
The module needs commands to list, retrieve, update, and comment on pull requests. Specifically, the following capabilities are missing:
- List pull requests — filter by state, head branch, base branch, sort order
- Get a specific pull request — retrieve details by PR number
- Update a pull request — change title, body, state (open/closed), base branch, or maintainer modification flag
- Add a comment to a pull request — post an issue comment on a PR (since pull requests are issues in the GitHub API, this uses the issue comments endpoint)
What is expected
Get-GitHubPullRequestreturns pull request objects with typed properties (state, head/base branch, author, labels, draft status, merge state, etc.)Update-GitHubPullRequestallows changing state toclosed(or reopening), updating title/body/base, withSupportsShouldProcessAdd-GitHubPullRequestCommentposts a comment to a pull request and returns the comment object- All commands follow existing module conventions: pipeline input, context resolution, typed output classes
Acceptance criteria
- Pull requests can be listed for a repository with optional filtering by state, head branch, and base branch
- A specific pull request can be retrieved by number
- A pull request can be closed (or reopened) by updating its state
- A comment can be added to a pull request
- All returned objects are strongly typed with a
GitHubPullRequestclass (andGitHubIssueCommentclass for comments) - Commands integrate with the existing
Contextresolution pattern
Use case
# List open PRs with a specific head branch
$oldPRs = Get-GitHubPullRequest -Owner 'PSModule' -Repository 'GoogleFonts' -State 'Open' -Head 'auto-update'
# Comment on each superseded PR and close it
foreach ($pr in $oldPRs) {
$pr | Add-GitHubPullRequestComment -Body 'Superseded by a newer Auto-Update PR.'
$pr | Update-GitHubPullRequest -State 'Closed'
}Technical decisions
Function grouping: Pull request functions go under src/functions/public/Pull-Requests/ (public) and src/functions/private/Pull-Requests/ (private), following the convention of grouping by object type. Comment functions go under src/functions/private/Issues/ since the API endpoint is the issues comments endpoint.
API approach: Use REST API (not GraphQL) for all pull request endpoints. The Pulls REST API provides straightforward endpoints and the Pull Request response object has many fields that don't map easily to a single GraphQL query. This matches the pattern used by Get-GitHubBranchList and Remove-GitHubRepository.
Public function names and their parameter sets:
| Public function | Parameter sets | Maps to |
|---|---|---|
Get-GitHubPullRequest |
'List pull requests' (default), 'Get a pull request' |
Private Get-GitHubPullRequestList, Get-GitHubPullRequestByNumber |
Update-GitHubPullRequest |
Single parameter set (no name needed) | Private Update-GitHubPullRequestByNumber |
Add-GitHubPullRequestComment |
Single parameter set (no name needed) | Private New-GitHubIssueComment |
Private function names (one API call = one function):
| Private function | REST endpoint |
|---|---|
Get-GitHubPullRequestList |
GET /repos/{owner}/{repo}/pulls |
Get-GitHubPullRequestByNumber |
GET /repos/{owner}/{repo}/pulls/{pull_number} |
Update-GitHubPullRequestByNumber |
PATCH /repos/{owner}/{repo}/pulls/{pull_number} |
New-GitHubIssueComment |
POST /repos/{owner}/{repo}/issues/{issue_number}/comments |
Class design:
GitHubPullRequestextendsGitHubNode(providesIDandNodeID). Key properties:Number,State,Title,Body,Locked,ActiveLockReason,Draft,Head(branch ref info),Base(branch ref info),User(GitHubOwner),Labels,Milestone,Assignees,RequestedReviewers,RequestedTeams,CreatedAt,UpdatedAt,ClosedAt,MergedAt,MergeCommitSha,Merged,Mergeable,MergeableState,RebaseMergeable,MergedBy,Comments,ReviewComments,Commits,Additions,Deletions,ChangedFiles,MaintainerCanModify,AuthorAssociation,AutoMerge,Url,HtmlUrl,DiffUrlGitHubIssueCommentextendsGitHubNode. Key properties:Body,User(GitHubOwner),CreatedAt,UpdatedAt,AuthorAssociation,HtmlUrl,IssueUrl- Types files:
GitHubPullRequest.Types.ps1xml(aliasPullRequest→Number),GitHubIssueComment.Types.ps1xml
Parameter naming:
Ownerwith aliasesOrganization,User(standard)Repository(notRepo, with[Alias('Repo')]if needed)Numberfor the pull request number (notID— sinceIDis the database ID per module conventions, and the PR number is not the database ID)Statewith[ValidateSet('Open', 'Closed', 'All')]for filteringHeadandBaseas[string]for branch filtering on listSortwith[ValidateSet('Created', 'Updated', 'Popularity', 'LongRunning')]Directionwith[ValidateSet('Asc', 'Desc')]
ShouldProcess:
Get-GitHubPullRequest— noSupportsShouldProcess(read-only)Update-GitHubPullRequest—[CmdletBinding(SupportsShouldProcess)](modifies state)Add-GitHubPullRequestComment—[CmdletBinding(SupportsShouldProcess)](creates content)
Comment function placement: The private function New-GitHubIssueComment lives under src/functions/private/Issues/ because it calls the issues API endpoint. The public function Add-GitHubPullRequestComment lives under src/functions/public/Pull-Requests/ because the user-facing context is pull requests. This private function can later be reused by a hypothetical Add-GitHubIssueComment public function.
Endpoints intentionally not covered in this issue:
POST /repos/{owner}/{repo}/pulls— Create a pull request (New-GitHubPullRequest) — separate issueGET /repos/{owner}/{repo}/pulls/{pull_number}/commits— List PR commits — separate issueGET /repos/{owner}/{repo}/pulls/{pull_number}/files— List PR files — separate issueGET /repos/{owner}/{repo}/pulls/{pull_number}/merge— Check if merged — separate issuePUT /repos/{owner}/{repo}/pulls/{pull_number}/merge— Merge a PR (Merge-GitHubPullRequest) — separate issuePUT /repos/{owner}/{repo}/pulls/{pull_number}/update-branch— Update PR branch — separate issue
Test approach: Unit tests with mocked API responses using Pester. One test per parameter set per function, plus edge cases (empty list, not found, etc.).
Implementation plan
Classes
- Add
GitHubPullRequestclass insrc/classes/public/PullRequests/GitHubPullRequest.ps1extendingGitHubNode, with constructor mapping from REST API response fields to PascalCase properties - Add
GitHubIssueCommentclass insrc/classes/public/Issues/GitHubIssueComment.ps1extendingGitHubNode, with constructor mapping from REST API response fields - Add
src/types/GitHubPullRequest.Types.ps1xmlwith alias propertyPullRequest→Number - Add
src/types/GitHubIssueComment.Types.ps1xmlwith alias propertyIssueComment→ID
Private functions
- Add
Get-GitHubPullRequestListinsrc/functions/private/Pull-Requests/Get-GitHubPullRequestList.ps1— callsGET /repos/{owner}/{repo}/pullswith optionalState,Head,Base,Sort,Directionquery parameters - Add
Get-GitHubPullRequestByNumberinsrc/functions/private/Pull-Requests/Get-GitHubPullRequestByNumber.ps1— callsGET /repos/{owner}/{repo}/pulls/{pull_number} - Add
Update-GitHubPullRequestByNumberinsrc/functions/private/Pull-Requests/Update-GitHubPullRequestByNumber.ps1— callsPATCH /repos/{owner}/{repo}/pulls/{pull_number}with body containing optionaltitle,body,state,base,maintainer_can_modify - Add
New-GitHubIssueCommentinsrc/functions/private/Issues/New-GitHubIssueComment.ps1— callsPOST /repos/{owner}/{repo}/issues/{issue_number}/commentswith body containingbody
Public functions
- Add
Get-GitHubPullRequestinsrc/functions/public/Pull-Requests/Get-GitHubPullRequest.ps1— with parameter sets'List pull requests'(default) and'Get a pull request', pipeline support viaValueFromPipelineByPropertyName, context resolution, and switch routing to private functions - Add
Update-GitHubPullRequestinsrc/functions/public/Pull-Requests/Update-GitHubPullRequest.ps1— withSupportsShouldProcess, pipeline support, parameters forTitle,Body,State,Base,MaintainerCanModify - Add
Add-GitHubPullRequestCommentinsrc/functions/public/Pull-Requests/Add-GitHubPullRequestComment.ps1— withSupportsShouldProcess, pipeline support, calls privateNew-GitHubIssueComment
Tests
- Add tests for
Get-GitHubPullRequest— list (with filters), get by number, empty results - Add tests for
Update-GitHubPullRequest— update state, update title/body, ShouldProcess behavior - Add tests for
Add-GitHubPullRequestComment— add comment, ShouldProcess behavior
Documentation
- Add examples in function help blocks showing common scenarios (list open PRs, close a PR, comment on a PR)
- Update endpoint coverage tracking file if one exists
Metadata
Metadata
Labels
Type
Projects
Status