From fd6ee1ba686bef6284ea349e096589277386ed65 Mon Sep 17 00:00:00 2001 From: Li Guan Date: Wed, 20 May 2026 16:59:18 +0800 Subject: [PATCH 1/5] feat: add processing for issue comment events to manage PR review labels. Signed-off-by: Li Guan --- Services/GitHubService.cs | 7 +++++++ Services/GitHubWebhookProcessor.cs | 33 ++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/Services/GitHubService.cs b/Services/GitHubService.cs index 5cdfdb6..90bbcad 100644 --- a/Services/GitHubService.cs +++ b/Services/GitHubService.cs @@ -139,4 +139,11 @@ public async Task> GetTeamMembersAsync( var members = await _client.Organization.Team.GetAllMembers(teamSlug.Id); return members.Select(m => m.Login.ToLowerInvariant()).ToHashSet(); } + + // Add more GitHub API methods as needed. + public async Task GetPullRequestAsync(string owner, string repo, int prNumber) + { + await EnsureAuthenticatedAsync(); + return await _client.PullRequest.Get(owner, repo, prNumber); + } } diff --git a/Services/GitHubWebhookProcessor.cs b/Services/GitHubWebhookProcessor.cs index 4a5959a..7ae9027 100644 --- a/Services/GitHubWebhookProcessor.cs +++ b/Services/GitHubWebhookProcessor.cs @@ -2,6 +2,7 @@ using Octokit.Webhooks.Events; using Octokit.Webhooks.Events.PullRequest; using Octokit.Webhooks.Events.PullRequestReview; +using Octokit.Webhooks.Events.IssueComment; namespace abaci_bot.Services; @@ -103,6 +104,38 @@ protected override async ValueTask ProcessPullRequestReviewWebhookAsync( } } + // When a new comment is created on the PR, if the commenter is a captain, we can also add "Workflow: In Review" label. + protected override async ValueTask ProcessIssueCommentWebhookAsync( + WebhookHeaders headers, + IssueCommentEvent issueCommentEvent, + IssueCommentAction action, + CancellationToken cancellationToken = default) + { + if (action == IssueCommentAction.Created) + { + if (issueCommentEvent.Issue.PullRequest != null) + { + var prNumber = (int)issueCommentEvent.Issue.Number; + var owner = issueCommentEvent.Repository.Owner.Login; + var repo = issueCommentEvent.Repository.Name; + var captains = await _github.GetTeamMembersAsync(owner, _config["GitHubApp:TeamName"]!); + string sender = issueCommentEvent.Sender.Login.ToLowerInvariant(); + var pullRequest = await _github.GetPullRequestAsync(owner, repo, prNumber); + var prTitle = issueCommentEvent.Issue.Title; + + // Only when the commenter is a captain, the PR is not in draft, + // and the title doesn't start with "WIP", we consider it as "In Review" and add the label. + if (captains.Contains(sender) && + !pullRequest.Draft && + !prTitle.StartsWith("WIP", StringComparison.OrdinalIgnoreCase)) + { + await _github.RemoveLabelAsync(owner, repo, prNumber, "Workflow: Ready For Review"); + await _github.AddLabelsAsync(owner, repo, prNumber, "Workflow: In Review"); + } + } + } + } + private async Task AnalyzeUserAndLabelPR(string owner, string repo, int prNumber, string? userEmail) { var domain = ExtractEmailDomain(userEmail); From 9e624bf93b1360f91ffbba448e1c878ec1caa90a Mon Sep 17 00:00:00 2001 From: Li Guan Date: Wed, 20 May 2026 17:24:42 +0800 Subject: [PATCH 2/5] fix: add condition to exclude script files from label addition. Signed-off-by: Li Guan --- Services/GitHubWebhookProcessor.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Services/GitHubWebhookProcessor.cs b/Services/GitHubWebhookProcessor.cs index 7ae9027..e383903 100644 --- a/Services/GitHubWebhookProcessor.cs +++ b/Services/GitHubWebhookProcessor.cs @@ -206,9 +206,11 @@ private async Task AnalyzeFilesAndLabelPR(string owner, string repo, int prNumbe } } - // TODO: What if, LTS. - labelsToAdd.Add("Target: Rolling"); - + if (file.FileName.StartsWith("SPECS/")) + { + // TODO: What if, LTS. + labelsToAdd.Add("Target: Rolling"); + } } if (labelsToAdd.Any()) From 731b3b2c6808c8ad919448ce74f37dfc2bd432b9 Mon Sep 17 00:00:00 2001 From: Li Guan Date: Wed, 20 May 2026 17:45:51 +0800 Subject: [PATCH 3/5] fix: prevent adding Workflow: Ready For Review label if Workflow: In Review label exists. Signed-off-by: Li Guan --- Services/GitHubWebhookProcessor.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Services/GitHubWebhookProcessor.cs b/Services/GitHubWebhookProcessor.cs index e383903..5403372 100644 --- a/Services/GitHubWebhookProcessor.cs +++ b/Services/GitHubWebhookProcessor.cs @@ -28,6 +28,7 @@ protected override async ValueTask ProcessPullRequestWebhookAsync( var repo = pullRequestEvent.Repository.Name; var headSha = pullRequestEvent.PullRequest.Head.Sha; var isDraft = pullRequestEvent.PullRequest.Draft; + var currentLabels = pullRequestEvent.PullRequest.Labels.Select(l => l.Name).ToList(); // Handle PR when opened or synchronized (new commit) if (action == PullRequestAction.Opened || @@ -63,7 +64,10 @@ protected override async ValueTask ProcessPullRequestWebhookAsync( { // For non-draft PR, add "Workflow: Ready For Review" label and remove "Workflow: In Dev" label if exists. await _github.RemoveLabelAsync(owner, repo, prNumber, "Workflow: In Dev"); - await _github.AddLabelsAsync(owner, repo, prNumber, "Workflow: Ready For Review"); + if (!currentLabels.Contains("Workflow: In Review")) + { + await _github.AddLabelsAsync(owner, repo, prNumber, "Workflow: Ready For Review"); + } } } From 77e4c7375bca4d0bf56e810493216a6ab47a3b23 Mon Sep 17 00:00:00 2001 From: Li Guan Date: Wed, 20 May 2026 21:19:07 +0800 Subject: [PATCH 4/5] docs: update README to clarify GitHub App permissions and webhook events configuration Signed-off-by: Li Guan --- README.md | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f37e511..39c3948 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,30 @@ Then edit `appsettings.json` and fill in your actual values: | `GitHubApp.TeamName` | Team slug used for review workflow (for example: `captains`). Review labels are updated only when review is submitted by a member of this team. | | `Kestrel.Endpoints.Http.Url` | The address and port the server listens on (default: `http://0.0.0.0:3456`) | -### 2. Run +### 2. Configure GitHub App permissions and webhook events + +Your GitHub App must be configured with the following permissions: + +**Organization permissions** + +- Members: **Read-only** + +**Repository permissions** + +- Pull requests: **Read and write** +- Issues: **Read and write** +- Contents: **Read-only** + +Your GitHub App must also subscribe to these webhook events: + +- Issue comments +- Issues +- Pull request review comments +- Pull request review threads +- Pull request reviews +- Pull requests + +### 3. Run #### Option A: Run directly @@ -72,7 +95,7 @@ docker run -d \ ghcr.io/openruyi/abaci-bot:latest ``` -### 3. Build Docker Image Locally (Optional) +### 4. Build Docker Image Locally (Optional) If you want to build the image yourself: From 03d0a59252c97656c719b45f90b72575da1a2812 Mon Sep 17 00:00:00 2001 From: Li Guan Date: Wed, 20 May 2026 22:24:20 +0800 Subject: [PATCH 5/5] fix: include PR title check to handle WIP status for draft PR labeling. Signed-off-by: Li Guan --- Services/GitHubWebhookProcessor.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Services/GitHubWebhookProcessor.cs b/Services/GitHubWebhookProcessor.cs index 5403372..370ffad 100644 --- a/Services/GitHubWebhookProcessor.cs +++ b/Services/GitHubWebhookProcessor.cs @@ -29,6 +29,7 @@ protected override async ValueTask ProcessPullRequestWebhookAsync( var headSha = pullRequestEvent.PullRequest.Head.Sha; var isDraft = pullRequestEvent.PullRequest.Draft; var currentLabels = pullRequestEvent.PullRequest.Labels.Select(l => l.Name).ToList(); + string prTitle = pullRequestEvent.PullRequest.Title; // Handle PR when opened or synchronized (new commit) if (action == PullRequestAction.Opened || @@ -53,7 +54,7 @@ protected override async ValueTask ProcessPullRequestWebhookAsync( // Then, let's analyze the content of the PR and add labels accordingly. await AnalyzeFilesAndLabelPR(owner, repo, prNumber, headSha); - if (isDraft) + if (isDraft || prTitle.StartsWith("WIP", StringComparison.OrdinalIgnoreCase)) { // For draft PR, add "Workflow: In Dev" label to indicate it's still in development, // and remove "Workflow: Ready For Review" label if exists.