- Published on
How to Resolve All GitHub PR Comments at Once Using the API
- Authors
- Name
- Ashik Nesin
- @AshikNesin
Sometimes you might need to bulk resolve all the comments in a single PR.
For example, today I had to merge a PR to main which had lots of false positive gitleaks comments. GitHub had a merge condition requiring all comments to be resolved before I could merge the PR to main. (obviously, I didn't close all the comments one by one 😜)
GitHub doesn't have support for bulk resolving comments in their UI, but we can do it via their API pretty easily.
Prerequisite
You'll need a GitHub token with appropriate permissions. You can use either:
- A classic PAT with
repo
permission, or - A fine-grained PAT with
Pull requests
permission
You can create these tokens in your GitHub settings.
Once you have the token, we can use the GitHub API to resolve all the comments at once.
Here is how to do it in Node.js:
// Replace with your details
const REPO = 'owner/repo';
const PR_NUMBER = 1;
const TOKEN = process.env.GITHUB_TOKEN;
if (!TOKEN) {
console.error('Error: GITHUB_TOKEN not set');
process.exit(1);
}
// Helper function for GraphQL requests
const gqlRequest = async (query, variables = {}) => {
const res = await fetch('https://api.github.com/graphql', {
method: 'POST',
headers: {
'Authorization': `bearer ${TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ query, variables }),
});
const json = await res.json();
if (!res.ok || json.errors)
throw new Error(json.errors?.[0]?.message || `API error: ${res.status}`);
return json.data;
};
// Main function
async function resolveAllComments() {
try {
// Get PR node ID
console.log(`Getting PR #${PR_NUMBER} data...`);
const [owner, repo] = REPO.split('/');
const { repository } = await gqlRequest(`
query($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $number) { id }
}
}
`, { owner, repo, number: PR_NUMBER });
const prId = repository?.pullRequest?.id;
if (!prId) throw new Error(`PR #${PR_NUMBER} not found in ${REPO}`);
// Get unresolved threads
const { node } = await gqlRequest(`
query($id: ID!) {
node(id: $id) {
... on PullRequest {
reviewThreads(first: 100) {
nodes { id, isResolved }
}
}
}
}
`, { id: prId });
const unresolvedThreads = node.reviewThreads.nodes
.filter(t => !t.isResolved)
.map(t => t.id);
console.log(`Found ${unresolvedThreads.length} unresolved thread(s)`);
// Resolve each thread
for (const threadId of unresolvedThreads) {
await gqlRequest(`
mutation($id: ID!) {
resolveReviewThread(input: {threadId: $id}) {
thread { id }
}
}
`, { id: threadId });
console.log(`Resolved thread ${threadId}`);
}
console.log('✅ All comments resolved successfully!');
} catch (error) {
console.error(`❌ Error: ${error.message}`);
process.exit(1);
}
}
resolveAllComments();
Happy resolving comments!