Skip to content

Add generic Gathering system for flexible event/meetup management #182

Add generic Gathering system for flexible event/meetup management

Add generic Gathering system for flexible event/meetup management #182

name: Check Unresolved PR Conversations
on:
pull_request_review:
types: [submitted, dismissed]
pull_request_target:
types: [synchronize, opened, reopened]
permissions:
pull-requests: write
jobs:
check-unresolved-conversations:
runs-on: ubuntu-latest
name: Check for unresolved review conversations
steps:
- name: Check unresolved conversations and notify contributor
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const repo = context.repo;
const prNumber = context.payload.pull_request
? context.payload.pull_request.number
: context.payload.review.pull_request_url.split('/').pop();
// Fetch unresolved review threads via GraphQL
const query = `
query($owner: String!, $repo: String!, $pr_number: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $pr_number) {
reviewThreads(first: 100) {
nodes {
isResolved
isOutdated
}
}
}
}
}
`;
const result = await github.graphql(query, {
owner: repo.owner,
repo: repo.repo,
pr_number: parseInt(prNumber),
});
const threads = result.repository.pullRequest.reviewThreads.nodes;
const unresolvedThreads = threads.filter(t => !t.isResolved && !t.isOutdated);
const unresolvedCount = unresolvedThreads.length;
console.log(`PR #${prNumber}: ${unresolvedCount} unresolved conversation(s) found.`);
// Fetch existing bot comments
const { data: comments } = await github.rest.issues.listComments({
owner: repo.owner,
repo: repo.repo,
issue_number: parseInt(prNumber),
});
const botLogin = 'github-actions[bot]';
const markerText = '<!-- check-unresolved-conversations -->';
const existingComment = comments.find(
c => c.user.login === botLogin && c.body.includes(markerText)
);
// Fetch existing bot reviews
const { data: allReviews } = await github.rest.pulls.listReviews({
owner: repo.owner,
repo: repo.repo,
pull_number: parseInt(prNumber),
});
const botChangesRequestedReviews = allReviews.filter(
r => r.user.login === botLogin && r.state === 'CHANGES_REQUESTED'
);
if (unresolvedCount > 0) {
const conversationWord = unresolvedCount === 1 ? 'conversation' : 'conversations';
const message = `${markerText}
## 💬 Unresolved Review Conversations
Hi @${context.payload.pull_request
? context.payload.pull_request.user.login
: (await github.rest.pulls.get({
owner: repo.owner,
repo: repo.repo,
pull_number: parseInt(prNumber),
})).data.user.login}! 👋
This pull request currently has **${unresolvedCount} unresolved review ${conversationWord}**.
Please address all review feedback and push a new commit to resolve them before this PR can be merged.
**Steps to resolve:**
1. Review each comment thread in the "Files changed" tab.
2. Make the necessary changes to your code.
3. Reply to each conversation to explain your changes or ask for clarification.
4. Click **"Resolve conversation"** once the feedback has been addressed.
5. Push a new commit with your changes.
Once all conversations are resolved, this notice will be removed automatically. Thank you! 🙏`;
if (existingComment) {
await github.rest.issues.updateComment({
owner: repo.owner,
repo: repo.repo,
comment_id: existingComment.id,
body: message,
});
console.log(`Updated existing comment on PR #${prNumber}`);
} else {
await github.rest.issues.createComment({
owner: repo.owner,
repo: repo.repo,
issue_number: parseInt(prNumber),
body: message,
});
console.log(`Posted unresolved conversations comment on PR #${prNumber}`);
}
// Submit a REQUEST_CHANGES review if one is not already pending
if (botChangesRequestedReviews.length === 0) {
await github.rest.pulls.createReview({
owner: repo.owner,
repo: repo.repo,
pull_number: parseInt(prNumber),
event: 'REQUEST_CHANGES',
body: `This PR has ${unresolvedCount} unresolved review ${conversationWord}. Please resolve them before this PR can be merged.`,
});
console.log(`Submitted REQUEST_CHANGES review on PR #${prNumber}`);
}
} else {
// All conversations resolved — remove the warning comment if it exists
if (existingComment) {
await github.rest.issues.deleteComment({
owner: repo.owner,
repo: repo.repo,
comment_id: existingComment.id,
});
console.log(`Deleted resolved conversations comment on PR #${prNumber}`);
} else {
console.log(`No unresolved conversations on PR #${prNumber}. Nothing to do.`);
}
// Dismiss any pending REQUEST_CHANGES reviews by the bot
for (const review of botChangesRequestedReviews) {
await github.rest.pulls.dismissReview({
owner: repo.owner,
repo: repo.repo,
pull_number: parseInt(prNumber),
review_id: review.id,
message: 'All review conversations have been resolved.',
});
console.log(`Dismissed REQUEST_CHANGES review ${review.id} on PR #${prNumber}`);
}
}