Listing Which GitHub Pull Requests are in a Project
Let's say that you want to list the pull requests that are in a given GitHub Project board.
Unfortunately, there's no handy way that is provided as part of the API, so we need to get a little creative.
First, you'll need to generate a personal access token with at least the public_repo
scope.
For instance, we'll use Wiremock 2.29.0 as an example.
Next, we'll need to discover this project boards' project ID for the API:
curl \
-H "Authorization: Bearer ..." \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/wiremock/wiremock/projects
[
{
"owner_url": "https://api.github.com/repos/wiremock/wiremock",
"url": "https://api.github.com/projects/12649878",
"html_url": "https://github.com/wiremock/wiremock/projects/4",
"columns_url": "https://api.github.com/projects/12649878/columns",
"id": 12649878,
"node_id": "MDc6UHJvamVjdDEyNjQ5ODc4",
"name": "WireMock 2.29.0",
"body": "New features + fixes for the v2.29.0 release.",
"number": 4,
"state": "open",
"creator": {
...
},
"created_at": "2021-06-10T14:56:59Z",
"updated_at": "2021-06-30T16:18:09Z"
}
]
Now we have the id
, we can start to list all the cards on the project.
We do this by listing all the columns on the project, then each of the cards on the columns - unfortunately it's a little wasteful, and on larger boards could be quite slow.
We then take advantage of the fact that if an Issue/PR is tagged against a project, the card's contents is just the URL of the Issue/PR, so we can filter for anything with this present.
Next, we will want to make sure that the provided URL is actually a PR, not an Issue, so we query the PR API to validate that it is a PR.
For instance, using the Ruby GitHub Gem, the code would look like the following:
require 'github_api'
board_id = ARGV[0]
github = Github.new oauth_token: ENV['TOKEN']
github.projects.columns.list(board_id) do |col|
pulls = github.projects.cards.list(col.id).filter_map do |card|
next unless card.content_url
next unless card.content_url.include? '/issues/'
parts = card.content_url.split '/'
# need to filter for things that are actually PRs, as they have the same `/issues/` URL as an Issue URL
begin
pr = github.pull_requests.get parts[4], parts[5], parts[-1]
pr.html_url
rescue Github::Error::NotFound
# almost certainly was an Issue, not a PR, so we can ignore it
next
end
end
next if pulls.empty?
jj pulls
end
We then can run this with:
env TOKEN=... ruby list-project.rb 12649878
And it'll dump out the HTML URLs of the PRs that are part of that project!
[
"https://github.com/wiremock/wiremock/pull/1378",
"https://github.com/wiremock/wiremock/pull/1376"
]
You can hopefully see other opportunities, like filtering based on the column that a project is in, so we can query for i.e. PRs that in the "done" column, or to list all the Projects a PR can be found in.