From 2d364d5a034121ac612afe46938f090ec2f5391b Mon Sep 17 00:00:00 2001 From: James Suplizio Date: Thu, 29 Feb 2024 14:36:36 -0800 Subject: [PATCH] Update the way Service Labels are matched (#7794) --- .../Static/IssueCommentProcessingTests.cs | 20 +- .../Static/IssueProcessingTests.cs | 152 +++--- .../PullRequestCommentProcessingTests.cs | 4 +- .../Static/PullRequestProcessingTests.cs | 10 +- .../Static/ScheduledEventProcessingTests.cs | 4 +- .../InitialIssueTriage_CODEOWNERS | 13 + .../ServiceAttention_has_CODEOWNERS | 6 + ...eAttention_has_CODEOWNERS_SingleLabelMatch | 34 ++ ..._labeled_already_has_ServiceAttention.json | 275 ---------- ...elConstants.cs => TriageLabelConstants.cs} | 7 +- .../EventProcessing/IssueCommentProcessing.cs | 22 +- .../EventProcessing/IssueProcessing.cs | 471 ++++++++++-------- .../PullRequestCommentProcessing.cs | 8 +- .../EventProcessing/PullRequestProcessing.cs | 8 +- .../ScheduledEventProcessing.cs | 18 +- .../Utils/CodeOwnerUtils.cs | 95 ++-- 16 files changed, 457 insertions(+), 690 deletions(-) create mode 100644 tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Tests.FakeCodeowners/ServiceAttention_has_CODEOWNERS_SingleLabelMatch delete mode 100644 tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Tests.JsonEventPayloads/ServiceAttention_issue_labeled_already_has_ServiceAttention.json rename tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/Constants/{LabelConstants.cs => TriageLabelConstants.cs} (79%) diff --git a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Static/IssueCommentProcessingTests.cs b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Static/IssueCommentProcessingTests.cs index 3e03e8296f6..8779dee9e7a 100644 --- a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Static/IssueCommentProcessingTests.cs +++ b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Static/IssueCommentProcessingTests.cs @@ -43,9 +43,9 @@ public async Task TestAuthorFeedback(string rule, string payloadFile, RuleState // There should be 2 updates, one label being added and one Assert.AreEqual(2, totalUpdates, $"The number of updates should have been 3 but was instead, {totalUpdates}"); // Verify that NeedsTeamAttention was added - Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(LabelConstants.NeedsTeamAttention), $"Labels to Add list does not contain {LabelConstants.NeedsTeamAttention}."); + Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(TriageLabelConstants.NeedsTeamAttention), $"Labels to Add list does not contain {TriageLabelConstants.NeedsTeamAttention}."); // Verify that NeedsAuthorFeedback was removed - Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(LabelConstants.NeedsAuthorFeedback), $"Lables to Remove list does not contain {LabelConstants.NeedsAuthorFeedback}."); + Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(TriageLabelConstants.NeedsAuthorFeedback), $"Lables to Remove list does not contain {TriageLabelConstants.NeedsAuthorFeedback}."); } else { @@ -81,7 +81,7 @@ public async Task TestResetIssueActivity(string rule, string payloadFile, RuleSt Assert.AreEqual(1, totalUpdates, $"The number of updates should have been 1 but was instead, {totalUpdates}"); // Verify that NoRecentActivity is in the remove list - Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(LabelConstants.NoRecentActivity), $"Labels to remove list does not contain {LabelConstants.NoRecentActivity}."); + Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(TriageLabelConstants.NoRecentActivity), $"Labels to remove list does not contain {TriageLabelConstants.NoRecentActivity}."); } else { @@ -123,11 +123,11 @@ public async Task TestReopenIssue(string rule, string payloadFile, RuleState rul Assert.AreEqual(issueUpdate.State, ItemState.Open, $"Issue's State should be {ItemState.Open} but was {issueUpdate.State}"); // Verify that the NeedsTeamAttention label was added - Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(LabelConstants.NeedsTeamAttention), $"Labels to add should contain {LabelConstants.NeedsTeamAttention} and does not."); + Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(TriageLabelConstants.NeedsTeamAttention), $"Labels to add should contain {TriageLabelConstants.NeedsTeamAttention} and does not."); // Verify that NeedsAuthorFeedback and NoRecentActivity labels were removed - Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(LabelConstants.NeedsAuthorFeedback), $"Lables to remove should contain {LabelConstants.NeedsAuthorFeedback} and does not."); - Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(LabelConstants.NoRecentActivity), $"Lables to remove should contain {LabelConstants.NoRecentActivity} and does not."); + Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(TriageLabelConstants.NeedsAuthorFeedback), $"Lables to remove should contain {TriageLabelConstants.NeedsAuthorFeedback} and does not."); + Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(TriageLabelConstants.NoRecentActivity), $"Lables to remove should contain {TriageLabelConstants.NoRecentActivity} and does not."); } else { @@ -216,9 +216,9 @@ public async Task TestIssueAddressedCommands_SameUser(string rule, string payloa // Verify the IssueUpdate's State = ItemState.Open Assert.AreEqual(issueUpdate.State, ItemState.Open, $"IssueUpdate's state should be ItemState.Open and was not."); // IssueAddressed label has been removed - Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(LabelConstants.IssueAddressed), $"Labels to remove should contain {LabelConstants.IssueAddressed} and does not."); + Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(TriageLabelConstants.IssueAddressed), $"Labels to remove should contain {TriageLabelConstants.IssueAddressed} and does not."); // NeedsTeamAttention has been added - Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(LabelConstants.NeedsTeamAttention), $"Labels to add should contain {LabelConstants.NeedsTeamAttention} and does not."); + Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(TriageLabelConstants.NeedsTeamAttention), $"Labels to add should contain {TriageLabelConstants.NeedsTeamAttention} and does not."); } else { @@ -260,9 +260,9 @@ public async Task TestIssueAddressedCommands_DifferentUser(string rule, string p // Verify the IssueUpdate's State = ItemState.Open Assert.AreEqual(issueUpdate.State, ItemState.Open, $"IssueUpdate's state should be ItemState.Open and was not."); // IssueAddressed label has been removed - Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(LabelConstants.IssueAddressed), $"Labels to remove should contain {LabelConstants.IssueAddressed} and does not."); + Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(TriageLabelConstants.IssueAddressed), $"Labels to remove should contain {TriageLabelConstants.IssueAddressed} and does not."); // NeedsTeamAttention has been added - Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(LabelConstants.NeedsTeamAttention), $"Labels to add should contain {LabelConstants.NeedsTeamAttention} and does not."); + Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(TriageLabelConstants.NeedsTeamAttention), $"Labels to add should contain {TriageLabelConstants.NeedsTeamAttention} and does not."); } else { diff --git a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Static/IssueProcessingTests.cs b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Static/IssueProcessingTests.cs index eb0fc23dea8..5319127f7d2 100644 --- a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Static/IssueProcessingTests.cs +++ b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Static/IssueProcessingTests.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using Azure.Sdk.Tools.CodeownersUtils.Parsing; using Azure.Sdk.Tools.GitHubEventProcessor.Constants; using Azure.Sdk.Tools.GitHubEventProcessor.EventProcessing; using Azure.Sdk.Tools.GitHubEventProcessor.GitHubPayload; @@ -254,6 +255,38 @@ public class IssueProcessingTests : ProcessingTestBase true, // Has CODEOWNERS entry true, true)] + // Scenario: The AI label has a matching CODEOWNERS entry that matches both labels returned. + // One of of AzureSdkOwners will have assignment permissions. + // Expected: The labels are added to the issue + // One of the AzureSdkOWners with permission is assigned to the issue + // A comment is added @ mentioning all of the AzureSdkOwners + // A second comment is added thanking the creator, tagging and routing to the team + // NeedsTeamTriage is added to the issue + [TestCase(RulesConstants.InitialIssueTriage, + "Tests.JsonEventPayloads/InitialIssueTriage_issue_opened_no_labels_no_assignee.json", + RuleState.On, + RuleState.On, + "Client, FakeLabel4", // labels returned from the AI Label service + "FakeUser6", // owners with permission to be assigned to issues + true, // Has CODEOWNERS entry + true, + true)] + // Scenario: The AI label has a matching CODEOWNERS entry that matches only the Category label + // One of of AzureSdkOwners will have assignment permissions. + // Expected: The labels are added to the issue + // One of the AzureSdkOWners with permission is assigned to the issue + // A comment is added @ mentioning all of the AzureSdkOwners + // A second comment is added thanking the creator, tagging and routing to the team + // NeedsTeamTriage is added to the issue + [TestCase(RulesConstants.InitialIssueTriage, + "Tests.JsonEventPayloads/InitialIssueTriage_issue_opened_no_labels_no_assignee.json", + RuleState.On, + RuleState.On, + "Client, FakeLabel6", // labels returned from the AI Label service, there is no FakeLabel6 only Client will match + "FakeUser1", // owners with permission to be assigned to issues + true, // Has CODEOWNERS entry + true, + true)] public async Task TestInitialIssueTriage(string rule, string payloadFile, RuleState ruleState, @@ -309,20 +342,20 @@ public async Task TestInitialIssueTriage(string rule, // then customer-reported and question labels should be added to the issue. if (!isMemberOfOrg && !hasWriteOrAdmin) { - Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(LabelConstants.CustomerReported), $"Labels to add should contain {LabelConstants.CustomerReported} which it should when the user is not part of the org and doesn't have write/admin collaborator permissions."); - Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(LabelConstants.Question), $"Labels to add should contain {LabelConstants.Question} which it should when the user is not part of the org and doesn't have write/admin collaborator permissions."); + Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(TriageLabelConstants.CustomerReported), $"Labels to add should contain {TriageLabelConstants.CustomerReported} which it should when the user is not part of the org and doesn't have write/admin collaborator permissions."); + Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(TriageLabelConstants.Question), $"Labels to add should contain {TriageLabelConstants.Question} which it should when the user is not part of the org and doesn't have write/admin collaborator permissions."); } else { - Assert.False(mockGitHubEventClient.GetLabelsToAdd().Contains(LabelConstants.CustomerReported), $"Labels to add contains {LabelConstants.CustomerReported} and shouldn't when the user is part of the org or has write/admin collaborator permissions."); - Assert.False(mockGitHubEventClient.GetLabelsToAdd().Contains(LabelConstants.Question), $"Labels to add contains {LabelConstants.Question} and shouldn't when the user is part of the org or has write/admin collaborator permissions."); + Assert.False(mockGitHubEventClient.GetLabelsToAdd().Contains(TriageLabelConstants.CustomerReported), $"Labels to add contains {TriageLabelConstants.CustomerReported} and shouldn't when the user is part of the org or has write/admin collaborator permissions."); + Assert.False(mockGitHubEventClient.GetLabelsToAdd().Contains(TriageLabelConstants.Question), $"Labels to add contains {TriageLabelConstants.Question} and shouldn't when the user is part of the org or has write/admin collaborator permissions."); } // If there are no labels being returned from the AI Label service, the only processing is whether or not the creator // is a member of the Azure org or has Write or Admin permissions if (expectedLabels.Count == 0) { - Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(LabelConstants.NeedsTriage), $"Labels to add should contain {LabelConstants.NeedsTriage} when the AI Label service has no suggested labels."); + Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(TriageLabelConstants.NeedsTriage), $"Labels to add should contain {TriageLabelConstants.NeedsTriage} when the AI Label service has no suggested labels."); } // else the AI Label Service returned labels to add else @@ -341,7 +374,7 @@ public async Task TestInitialIssueTriage(string rule, // line otherwise the block is malformed and will get thrown away. if (!hasCodeownersEntry) { - Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(LabelConstants.NeedsTeamTriage), $"With no CODEOWNERS entry {LabelConstants.NeedsTeamTriage} should have been added to the issue."); + Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(TriageLabelConstants.NeedsTeamTriage), $"With no CODEOWNERS entry {TriageLabelConstants.NeedsTeamTriage} should have been added to the issue."); } // There is a CODEOWNERS entry for the ServiceLabel returned from the AI Label service else @@ -358,18 +391,18 @@ public async Task TestInitialIssueTriage(string rule, bool ownerFromOwnersWithPermList = mockGitHubEventClient.OwnersWithAssignPermission.Contains(githubIssueAssignment.Assignees[0], StringComparer.OrdinalIgnoreCase); Assert.True(ownerFromOwnersWithPermList, $"The owner assigned to the issue, {githubIssueAssignment.Assignees[0]}, was not in the list of owners with assign permission, {string.Join(",", mockGitHubEventClient.OwnersWithAssignPermission)}"); - Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(LabelConstants.NeedsTeamAttention), $"With a valid AzureSdkOwner to assign to the issue the {LabelConstants.NeedsTeamAttention} should have been added to the issue."); + Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(TriageLabelConstants.NeedsTeamAttention), $"With a valid AzureSdkOwner to assign to the issue the {TriageLabelConstants.NeedsTeamAttention} should have been added to the issue."); // If there is more than one AzureSdkOwner, a comment will also be created to @ mention all of the owners // and a second comment will be created thanking the issue creator for their feedback. - var azureSdkOwners = CodeOwnerUtils.GetAzureSdkOwnersForServiceLabels(expectedLabels); + CodeownersEntry codeownersEntry = CodeOwnerUtils.GetCodeownersEntryForLabelList(expectedLabels); // With a single AzureSdkOwner there should only be one comment thanking the creator for feedback and tagging and routing the issue - if (azureSdkOwners.Count == 1) + if (codeownersEntry.AzureSdkOwners.Count == 1) { Assert.AreEqual(1, mockGitHubEventClient.GetComments().Count, $"With only one AzureSdkOwner there should only be one comment thanking the creator, tagging and routing but {mockGitHubEventClient.GetComments().Count} comments were created."); } // With more than one AzureSdkOWner there should be two comments. The first is an @ metion and the second is the same one thanking the creator - else if (azureSdkOwners.Count > 1) + else if (codeownersEntry.AzureSdkOwners.Count > 1) { Assert.AreEqual(2, mockGitHubEventClient.GetComments().Count, $"With multiple AzureSdkOwners there should only be two comments. One @ mentioning everyone on the list and the other thanking the creator, tagging and routing but {mockGitHubEventClient.GetComments().Count} comments were created."); } @@ -385,13 +418,13 @@ public async Task TestInitialIssueTriage(string rule, { if (serviceAttentionRuleState == RuleState.Off) { - Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(LabelConstants.NeedsTeamTriage), $"With no valid AzureSdkOwners and the ServiceAttention rule being disabled, {LabelConstants.NeedsTeamTriage} should have been added to the issue."); + Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(TriageLabelConstants.NeedsTeamTriage), $"With no valid AzureSdkOwners and the ServiceAttention rule being disabled, {TriageLabelConstants.NeedsTeamTriage} should have been added to the issue."); } // else, the ServiceAttention rule will which creates a comment that ends with @ mentioning the service owners // and NeedsTeamAttention is added to the issue else { - Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(LabelConstants.NeedsTeamAttention), $"With no valid AzureSdkOwners but valid ServiceOwners and ServiceAttention rule being enabled, {LabelConstants.NeedsTeamAttention} should have been added to the issue."); + Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(TriageLabelConstants.NeedsTeamAttention), $"With no valid AzureSdkOwners but valid ServiceOwners and ServiceAttention rule being enabled, {TriageLabelConstants.NeedsTeamAttention} should have been added to the issue."); Assert.AreEqual(1, mockGitHubEventClient.GetComments().Count, $"With no AzureSdkOwners and the ServiceAttention rule being enabled, there should only be one comment created by the ServiceAttention rule but {mockGitHubEventClient.GetComments().Count} comments were created."); } } @@ -436,14 +469,14 @@ public async Task TestManualIssueTriage(string rule, string payloadFile, RuleSta // If the label being added is NeedsTriage, there should be no updates if (labelAddedIsNeedsTriage) { - Assert.AreEqual(0, totalUpdates, $"The label being added was {LabelConstants.NeedsTriage} and should not have produced any updates."); + Assert.AreEqual(0, totalUpdates, $"The label being added was {TriageLabelConstants.NeedsTriage} and should not have produced any updates."); } else { // There should be one update, an IssueUpdate with the NoRecentActivity label removed Assert.AreEqual(1, totalUpdates, $"The number of updates should have been 1 but was instead, {totalUpdates}"); // Verify that NeedsTriage was removed - Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(LabelConstants.NeedsTriage), $"Labels to remove should contain {LabelConstants.NeedsTriage} and does not."); + Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(TriageLabelConstants.NeedsTriage), $"Labels to remove should contain {TriageLabelConstants.NeedsTriage} and does not."); } } else @@ -467,27 +500,20 @@ public async Task TestManualIssueTriage(string rule, string payloadFile, RuleSta /// Determines whether to load the codeowners with parties to mention or the one without [Category("static")] [NonParallelizable] - [TestCase(RulesConstants.ServiceAttention, "Tests.JsonEventPayloads/ServiceAttention_issue_labeled.json", RuleState.Off, true)] - [TestCase(RulesConstants.ServiceAttention, "Tests.JsonEventPayloads/ServiceAttention_issue_labeled.json", RuleState.On, true)] - [TestCase(RulesConstants.ServiceAttention, "Tests.JsonEventPayloads/ServiceAttention_issue_labeled.json", RuleState.On, false)] - public async Task TestServiceAttention(string rule, string payloadFile, RuleState ruleState, bool hasPartiesToMentionForServiceAttention) + [TestCase(RulesConstants.ServiceAttention, "Tests.JsonEventPayloads/ServiceAttention_issue_labeled.json", "Tests.FakeCodeowners/ServiceAttention_has_CODEOWNERS", RuleState.Off, null)] + [TestCase(RulesConstants.ServiceAttention, "Tests.JsonEventPayloads/ServiceAttention_issue_labeled.json", "Tests.FakeCodeowners/ServiceAttention_has_CODEOWNERS", RuleState.On, "@FakeUser4 @FakeUser9")] + [TestCase(RulesConstants.ServiceAttention, "Tests.JsonEventPayloads/ServiceAttention_issue_labeled.json", "Tests.FakeCodeowners/ServiceAttention_has_CODEOWNERS_SingleLabelMatch", RuleState.On, "@FakeUser9")] + [TestCase(RulesConstants.ServiceAttention, "Tests.JsonEventPayloads/ServiceAttention_issue_labeled.json", "Tests.FakeCodeowners/ServiceAttention_does_not_have_CODEOWNERS", RuleState.On, null)] + public async Task TestServiceAttention(string rule, string payloadFile, string codeownersFile, RuleState ruleState, string expectedNames) { var mockGitHubEventClient = new MockGitHubEventClient(OrgConstants.ProductHeaderName); mockGitHubEventClient.RulesConfiguration.Rules[rule] = ruleState; var rawJson = TestHelpers.GetTestEventPayload(payloadFile); var issueEventPayload = SimpleJsonSerializer.Deserialize(rawJson); - // Set the path to the fake CODEOWNERS file to be used for testing - if (hasPartiesToMentionForServiceAttention) - { - CodeOwnerUtils.ResetCodeOwnerEntries(); - CodeOwnerUtils.codeOwnersFilePathOverride = "Tests.FakeCodeowners/ServiceAttention_has_CODEOWNERS"; - } - else - { - CodeOwnerUtils.ResetCodeOwnerEntries(); - CodeOwnerUtils.codeOwnersFilePathOverride = "Tests.FakeCodeowners/ServiceAttention_does_not_have_CODEOWNERS"; - } + CodeOwnerUtils.ResetCodeOwnerEntries(); + CodeOwnerUtils.codeOwnersFilePathOverride = codeownersFile; + IssueProcessing.ServiceAttention(mockGitHubEventClient, issueEventPayload); // Verify the RuleCheck @@ -496,9 +522,8 @@ public async Task TestServiceAttention(string rule, string payloadFile, RuleStat var totalUpdates = await mockGitHubEventClient.ProcessPendingUpdates(issueEventPayload.Repository.Id, issueEventPayload.Issue.Number); if (RuleState.On == ruleState) { - if (hasPartiesToMentionForServiceAttention) + if (null != expectedNames) { - string expectedNames = "@FakeUser1 @FakeUser11 @FakeUser14 @FakeUser24 @FakeUser4 @FakeUser9"; // "Thanks for the feedback! We are routing this to the appropriate team for follow-up. cc @FakeUser1 @FakeUser11 @FakeUser4 @FakeUser14 @FakeUser24 @FakeUser9." // There should be one update, a comment Assert.AreEqual(1, totalUpdates, $"The number of updates should have been 1 but was instead, {totalUpdates}"); @@ -519,43 +544,6 @@ public async Task TestServiceAttention(string rule, string payloadFile, RuleStat } } - /// - /// This is for testing an update to the Service Attention rule. If Service Attention is already on the rule and the rule - /// is labled, then that label's people are @ mentioned. - /// Trigger: issue labeled - /// Conditions: Issue is open - /// "Service Attention" is already on the issue - /// The label has a CODEOWNERS entry with ServiceOwners - /// Resulting Action: Add issue comment "Thanks for the feedback! We are routing this to the appropriate team for follow-up. cc ${mentionees}." - /// - /// String, RulesConstants for the rule being tested - /// JSon payload file for the event being tested - /// The expected owners to be @ mentioned for the label being added. This needs to be ordered as the API getting the owners orders them. - [Category("static")] - [NonParallelizable] - [TestCase(RulesConstants.ServiceAttention, "Tests.JsonEventPayloads/ServiceAttention_issue_labeled_already_has_ServiceAttention.json", "@FakeUser14 @FakeUser24 @FakeUser4")] - public async Task TestServiceAttentionAlreadyOnIssue(string rule, string payloadFile, string expectedOwners) - { - var mockGitHubEventClient = new MockGitHubEventClient(OrgConstants.ProductHeaderName); - mockGitHubEventClient.RulesConfiguration.Rules[rule] = RuleState.On; - var rawJson = TestHelpers.GetTestEventPayload(payloadFile); - var issueEventPayload = SimpleJsonSerializer.Deserialize(rawJson); - - CodeOwnerUtils.ResetCodeOwnerEntries(); - CodeOwnerUtils.codeOwnersFilePathOverride = "Tests.FakeCodeowners/ServiceAttention_has_CODEOWNERS"; - - IssueProcessing.ServiceAttention(mockGitHubEventClient, issueEventPayload); - var totalUpdates = await mockGitHubEventClient.ProcessPendingUpdates(issueEventPayload.Repository.Id, issueEventPayload.Issue.Number); - // "Thanks for the feedback! We are routing this to the appropriate team for follow-up. cc @FakeUser1 @FakeUser11 @FakeUser4 @FakeUser14 @FakeUser24 @FakeUser9." - // There should be one update, a comment - Assert.AreEqual(1, totalUpdates, $"The number of updates should have been 1 but was instead, {totalUpdates}"); - - // Verify that a single comment was created - Assert.AreEqual(1, mockGitHubEventClient.GetComments().Count, $"{rule} should have produced a single comment."); - string comment = mockGitHubEventClient.GetComments()[0].Comment; - Assert.True(comment.Contains(expectedOwners), $"Comment should have contained expected names {expectedOwners} but did not. Full comment={comment}"); - } - /// /// Test ManualTriageAfterExternalAssignment rule enabled/disabled, with a payload that would cause updates when enabled. /// Verify all the expected updates when enabled and no updates when disabled. @@ -594,7 +582,7 @@ public async Task TestManualTriageAfterExternalAssignment(string rule, string pa // If issue already has needs-team-triage there should be no updates if (alreadyHasNeedsTeamTriage) { - Assert.AreEqual(0, totalUpdates, $"The issue already has {LabelConstants.NeedsTeamTriage} and should not have produced any updates."); + Assert.AreEqual(0, totalUpdates, $"The issue already has {TriageLabelConstants.NeedsTeamTriage} and should not have produced any updates."); } else { @@ -603,11 +591,11 @@ public async Task TestManualTriageAfterExternalAssignment(string rule, string pa // There should be one update, the label NoRecentActivity should have been added Assert.AreEqual(1, totalUpdates, $"The number of updates should have been 1 but was instead, {totalUpdates}"); // Verify that NeedsTeamTriage was added - Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(LabelConstants.NeedsTeamTriage), $"Labels to add should contain {LabelConstants.NeedsTeamTriage} and does not."); + Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(TriageLabelConstants.NeedsTeamTriage), $"Labels to add should contain {TriageLabelConstants.NeedsTeamTriage} and does not."); } else { - Assert.AreEqual(0, totalUpdates, $"The issue only 1 of {LabelConstants.ServiceAttention}. With the other still being on the issue there should have been no updates."); + Assert.AreEqual(0, totalUpdates, $"The issue only 1 of {TriageLabelConstants.ServiceAttention}. With the other still being on the issue there should have been no updates."); } } } @@ -651,7 +639,7 @@ public async Task TestResetIssueActivity(string rule, string payloadFile, RuleSt Assert.AreEqual(1, totalUpdates, $"The number of updates should have been 1 but was instead, {totalUpdates}"); // Verify that NoRecentActivity was removed - Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(LabelConstants.NoRecentActivity), $"Labels to remove should contain {LabelConstants.NoRecentActivity} and does not."); + Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(TriageLabelConstants.NoRecentActivity), $"Labels to remove should contain {TriageLabelConstants.NoRecentActivity} and does not."); } else { @@ -699,7 +687,7 @@ public async Task TestRequireAttentionForNonMilestone(string rule, string payloa Assert.AreEqual(1, totalUpdates, $"The number of updates should have been 1 but was instead, {totalUpdates}"); // Verify that NeedsTeamAttention was added - Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(LabelConstants.NeedsTeamAttention), $"Lables to add should contain {LabelConstants.NeedsTeamAttention} and does not."); + Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(TriageLabelConstants.NeedsTeamAttention), $"Lables to add should contain {TriageLabelConstants.NeedsTeamAttention} and does not."); } else { @@ -751,9 +739,9 @@ public async Task TestAuthorFeedbackNeeded(string rule, string payloadFile, Rule Assert.AreEqual(4, totalUpdates, $"The number of updates should have been 3 but was instead, {totalUpdates}"); // Verify that NeedsTriage, NeedsTeamTriage and NeedsTeamAttention were removed - Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(LabelConstants.NeedsTriage), $"Labels to remove should contain {LabelConstants.NeedsTriage} and does not."); - Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(LabelConstants.NeedsTeamTriage), $"Labels to remove should contain {LabelConstants.NeedsTeamTriage} and does not."); - Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(LabelConstants.NeedsTeamAttention), $"Labels to remove should contain {LabelConstants.NeedsTeamAttention} and does not."); + Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(TriageLabelConstants.NeedsTriage), $"Labels to remove should contain {TriageLabelConstants.NeedsTriage} and does not."); + Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(TriageLabelConstants.NeedsTeamTriage), $"Labels to remove should contain {TriageLabelConstants.NeedsTeamTriage} and does not."); + Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(TriageLabelConstants.NeedsTeamAttention), $"Labels to remove should contain {TriageLabelConstants.NeedsTeamAttention} and does not."); } // The comment should be created regardless @@ -815,15 +803,15 @@ public async Task TestIssueAddressed(string rule, string payloadFile, RuleState Assert.AreEqual(6, totalUpdates, $"The number of updates should have been 2 but was instead, {totalUpdates}"); // Verify that NeedsTriage was added to the remove list - Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(LabelConstants.NeedsTriage), $"Labels to remove should contain {LabelConstants.NeedsTriage} and does not."); + Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(TriageLabelConstants.NeedsTriage), $"Labels to remove should contain {TriageLabelConstants.NeedsTriage} and does not."); // Verify that NeedsTeamTriage was added to the remove list - Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(LabelConstants.NeedsTeamTriage), $"Labels to remove should contain {LabelConstants.NeedsTeamTriage} and does not."); + Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(TriageLabelConstants.NeedsTeamTriage), $"Labels to remove should contain {TriageLabelConstants.NeedsTeamTriage} and does not."); // Verify that NeedsTeamAttention was added to the remove list - Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(LabelConstants.NeedsTeamAttention), $"Labels to remove should contain {LabelConstants.NeedsTeamAttention} and does not."); + Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(TriageLabelConstants.NeedsTeamAttention), $"Labels to remove should contain {TriageLabelConstants.NeedsTeamAttention} and does not."); // Verify that NeedsAuthorFeedback was added to the remove list - Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(LabelConstants.NeedsAuthorFeedback), $"Labels to remove should contain {LabelConstants.NeedsAuthorFeedback} and does not."); + Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(TriageLabelConstants.NeedsAuthorFeedback), $"Labels to remove should contain {TriageLabelConstants.NeedsAuthorFeedback} and does not."); // Verify that NoRecentActivity was added to the remove list - Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(LabelConstants.NoRecentActivity), $"Labels to remove should contain {LabelConstants.NoRecentActivity} and does not."); + Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(TriageLabelConstants.NoRecentActivity), $"Labels to remove should contain {TriageLabelConstants.NoRecentActivity} and does not."); } // Regardless of whether or not there were labels to remove, a single comment should be created. Assert.AreEqual(1, mockGitHubEventClient.GetComments().Count, $"{rule} should have produced a single comment."); @@ -876,7 +864,7 @@ public async Task TestIssueAddressedReset(string rule, string payloadFile, RuleS Assert.AreEqual(1, totalUpdates, $"The number of updates should have been 1 but was instead, {totalUpdates}"); // Verify that IssueAddressed was added to the remove list - Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(LabelConstants.IssueAddressed), $"Labels to remove should contain {LabelConstants.IssueAddressed} and does not."); + Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(TriageLabelConstants.IssueAddressed), $"Labels to remove should contain {TriageLabelConstants.IssueAddressed} and does not."); } else { diff --git a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Static/PullRequestCommentProcessingTests.cs b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Static/PullRequestCommentProcessingTests.cs index 30d2eb4b54b..46ced9aa2f0 100644 --- a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Static/PullRequestCommentProcessingTests.cs +++ b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Static/PullRequestCommentProcessingTests.cs @@ -50,7 +50,7 @@ public async Task TestResetPullRequestActivity(string rule, string payloadFile, // There should be one update, the no-recent-activity label removed Assert.AreEqual(1, totalUpdates, $"The number of updates should have been 1 but was instead, {totalUpdates}"); // Verify that NeedsAuthorFeedback was removed - Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(LabelConstants.NoRecentActivity), $"Labels to remove should contain {LabelConstants.NoRecentActivity} and does not."); + Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(TriageLabelConstants.NoRecentActivity), $"Labels to remove should contain {TriageLabelConstants.NoRecentActivity} and does not."); } else { @@ -105,7 +105,7 @@ public async Task TestReopenPullRequest(string rule, string payloadFile, RuleSta // State = ItemState.Open Assert.AreEqual(issueUpdate.State, ItemState.Open, $"IssueUpdate's state should be {ItemState.Open} and was not."); // Verify that NoRecentActivity was removed - Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(LabelConstants.NoRecentActivity), $"Labels to remove should contain {LabelConstants.NoRecentActivity} and does not."); + Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(TriageLabelConstants.NoRecentActivity), $"Labels to remove should contain {TriageLabelConstants.NoRecentActivity} and does not."); } else { diff --git a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Static/PullRequestProcessingTests.cs b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Static/PullRequestProcessingTests.cs index ccd5269e8a6..59bb1a68ac3 100644 --- a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Static/PullRequestProcessingTests.cs +++ b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Static/PullRequestProcessingTests.cs @@ -96,14 +96,14 @@ public async Task TestPullRequestTriage(string rule, string payloadFile, RuleSta // then customer-reported and community-contribution labels should have been added along with a comment if (!isMemberOfOrg && !hasWriteOrAdmin) { - Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(LabelConstants.CustomerReported), $"User does not have write or admin permission, IssueUpdate should contain {LabelConstants.CustomerReported}."); - Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(LabelConstants.CommunityContribution), $"User does not have write or admin permission, IssueUpdate should contain {LabelConstants.CommunityContribution}."); + Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(TriageLabelConstants.CustomerReported), $"User does not have write or admin permission, IssueUpdate should contain {TriageLabelConstants.CustomerReported}."); + Assert.True(mockGitHubEventClient.GetLabelsToAdd().Contains(TriageLabelConstants.CommunityContribution), $"User does not have write or admin permission, IssueUpdate should contain {TriageLabelConstants.CommunityContribution}."); Assert.AreEqual(1, mockGitHubEventClient.GetComments().Count, "Without admin or write permission there should have been a comment added."); } else { - Assert.False(mockGitHubEventClient.GetLabelsToAdd().Contains(LabelConstants.CustomerReported), $"User has write or admin permission or is a member of Azure, IssueUpdate should not contain {LabelConstants.CustomerReported}."); - Assert.False(mockGitHubEventClient.GetLabelsToAdd().Contains(LabelConstants.CommunityContribution), $"User has write or admin permission or is a member of Azure, IssueUpdate should not contain {LabelConstants.CommunityContribution}."); + Assert.False(mockGitHubEventClient.GetLabelsToAdd().Contains(TriageLabelConstants.CustomerReported), $"User has write or admin permission or is a member of Azure, IssueUpdate should not contain {TriageLabelConstants.CustomerReported}."); + Assert.False(mockGitHubEventClient.GetLabelsToAdd().Contains(TriageLabelConstants.CommunityContribution), $"User has write or admin permission or is a member of Azure, IssueUpdate should not contain {TriageLabelConstants.CommunityContribution}."); Assert.AreEqual(0, mockGitHubEventClient.GetComments().Count, "User has write or admin permission or is a member of Azure, there should not have been a comment added."); } } @@ -150,7 +150,7 @@ public async Task TestResetPullRequestActivity(string rule, string payloadFile, Assert.AreEqual(1, totalUpdates, $"The number of updates should have been 1 but was instead, {totalUpdates}"); // Verify that NeedsAuthorFeedback was removed - Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(LabelConstants.NoRecentActivity), $"Labels to remove should contain {LabelConstants.NoRecentActivity} and does not."); + Assert.True(mockGitHubEventClient.GetLabelsToRemove().Contains(TriageLabelConstants.NoRecentActivity), $"Labels to remove should contain {TriageLabelConstants.NoRecentActivity} and does not."); } else { diff --git a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Static/ScheduledEventProcessingTests.cs b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Static/ScheduledEventProcessingTests.cs index b180f710e1b..c6ce83a1d87 100644 --- a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Static/ScheduledEventProcessingTests.cs +++ b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Static/ScheduledEventProcessingTests.cs @@ -186,7 +186,7 @@ public async Task TestIdentifyStalePullRequests(string rule, string payloadFile, Assert.AreEqual(expectedUpdates / 2, numComments, $"The number of comments should have been {expectedUpdates / 2} but was instead, {numComments}"); // Verify LabelConstants.NoRecentActivity was added - Assert.IsTrue(mockGitHubEventClient.GetGitHubIssuesToUpdate()[0].IssueUpdate.Labels.Contains(LabelConstants.NoRecentActivity), $"rule should have added {LabelConstants.NoRecentActivity} label and did not."); + Assert.IsTrue(mockGitHubEventClient.GetGitHubIssuesToUpdate()[0].IssueUpdate.Labels.Contains(TriageLabelConstants.NoRecentActivity), $"rule should have added {TriageLabelConstants.NoRecentActivity} label and did not."); } else { @@ -231,7 +231,7 @@ public async Task TestIdentifyStaleIssues(string rule, string payloadFile, RuleS Assert.AreEqual(expectedUpdates / 2, numComments, $"The number of comments should have been {expectedUpdates / 2} but was instead, {numComments}"); // Verify LabelConstants.NoRecentActivity was added - Assert.IsTrue(mockGitHubEventClient.GetGitHubIssuesToUpdate()[0].IssueUpdate.Labels.Contains(LabelConstants.NoRecentActivity), $"rule should have added {LabelConstants.NoRecentActivity} label and did not."); + Assert.IsTrue(mockGitHubEventClient.GetGitHubIssuesToUpdate()[0].IssueUpdate.Labels.Contains(TriageLabelConstants.NoRecentActivity), $"rule should have added {TriageLabelConstants.NoRecentActivity} label and did not."); } else { diff --git a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Tests.FakeCodeowners/InitialIssueTriage_CODEOWNERS b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Tests.FakeCodeowners/InitialIssueTriage_CODEOWNERS index a40e885d2cc..1084e0bd83f 100644 --- a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Tests.FakeCodeowners/InitialIssueTriage_CODEOWNERS +++ b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Tests.FakeCodeowners/InitialIssueTriage_CODEOWNERS @@ -6,6 +6,13 @@ # Tests.JsonEventPayloads/InitialIssueTriage_issue_opened_no_labels_no_assignee.json file. ################ +# AzureSdkOwners pulled from source path/owners, there are no ServiceOwners so the ServiceAttention rule +# should not run. The entry only having a %Client label is the fallback for the scenario where the label list +# contains %Client as well as a ServiceLabel that doesn't exist on any other entry +# The ServiceLabel has +# ServiceLabel: %Client +# AzureSdkOwners: @FakeUser1 + # This scenario is a ServiceOwners block with no AzureSdkOwners # ServiceLabel: %FakeLabel1 # ServiceOwners: @FakeUser7 @FakeUser8 @@ -39,3 +46,9 @@ # AzureSdkOwners: /files/filePath0/ @FakeUser5 @FakeUser6 +# AzureSdkOwners and ServiceOwners pulled from source path/owners. +# This scenario is to ensure the two label match. +# The ServiceLabel has +# ServiceLabel: %Client %FakeLabel4 +# AzureSdkOwners: +/files/filePath10/ @FakeUser5 @FakeUser6 diff --git a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Tests.FakeCodeowners/ServiceAttention_has_CODEOWNERS b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Tests.FakeCodeowners/ServiceAttention_has_CODEOWNERS index ff4027ac4a8..d224c5e945c 100644 --- a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Tests.FakeCodeowners/ServiceAttention_has_CODEOWNERS +++ b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Tests.FakeCodeowners/ServiceAttention_has_CODEOWNERS @@ -22,3 +22,9 @@ /files/filePath8/ @FakeUser8 # ServiceLabel: %FakeLabel9 %Service Attention /files/filePath9/ @FakeUser9 + +# ServiceLabel: %FakeLabel4 %FakeLabel9 %Service Attention +# ServiceOwners: @FakeUser4 @FakeUser9 + +# ServiceLabel: %FakeLabel10 %FakeLabel4 %Service Attention +# ServiceOwners: @FakeUser4 @FakeUser10 diff --git a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Tests.FakeCodeowners/ServiceAttention_has_CODEOWNERS_SingleLabelMatch b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Tests.FakeCodeowners/ServiceAttention_has_CODEOWNERS_SingleLabelMatch new file mode 100644 index 00000000000..bde268939fa --- /dev/null +++ b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Tests.FakeCodeowners/ServiceAttention_has_CODEOWNERS_SingleLabelMatch @@ -0,0 +1,34 @@ +################ +# FAKE Codeownrs file for testing purposes +################ + +# ServiceLabel: %FakeLabel0 %Service Attention +/files/filePath0/ @FakeUser0 +# ServiceLabel: %FakeLabel1 %Service Attention +/files/filePath1/ @FakeUser1 @FakeUser11 +# ServiceLabel: %FakeLabel2 %Service Attention +/files/filePath2/ @FakeUser2 @FakeUser12 +# ServiceLabel: %FakeLabel3 %Service Attention +/files/filePath3/ @FakeUser3 +# ServiceLabel: %FakeLabel4 %Service Attention +/files/filePath4/ @FakeUser4 @FakeUser14 @FakeUser24 +# ServiceLabel: %FakeLabel5 %Service Attention +/files/filePath5/ @FakeUser5 +# ServiceLabel: %FakeLabel6 %Service Attention +/files/filePath6/ @FakeUser6 +# ServiceLabel: %FakeLabel7 %Service Attention +/files/filePath7/ @FakeUser7 @FakeUser17 +# ServiceLabel: %FakeLabel8 %Service Attention +/files/filePath8/ @FakeUser8 +# The payload coming in has FakeLabel9, FakeLabel4 and FakeLabel1. +# Since the match looks for a ServiceLabel entry that is fully included +# in the Issue's payload, from the last->first of the entries, +# FakeLabel9 is the first match +# ServiceLabel: %FakeLabel9 %Service Attention +/files/filePath9/ @FakeUser9 + +# ServiceLabel: %FakeLabel5 %FakeLabel8 %Service Attention +# ServiceOwners: @FakeUser4 @FakeUser9 + +# ServiceLabel: %FakeLabel10 %FakeLabel4 %Service Attention +# ServiceOwners: @FakeUser4 @FakeUser10 diff --git a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Tests.JsonEventPayloads/ServiceAttention_issue_labeled_already_has_ServiceAttention.json b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Tests.JsonEventPayloads/ServiceAttention_issue_labeled_already_has_ServiceAttention.json deleted file mode 100644 index 911167bafa0..00000000000 --- a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor.Tests/Tests.JsonEventPayloads/ServiceAttention_issue_labeled_already_has_ServiceAttention.json +++ /dev/null @@ -1,275 +0,0 @@ -{ - "action": "labeled", - "issue": { - "active_lock_reason": null, - "assignee": { - "avatar_url": "https://avatars.githubusercontent.com/u/13556087?v=4", - "events_url": "https://api.github.com/users/FakeUser1/events{/privacy}", - "followers_url": "https://api.github.com/users/FakeUser1/followers", - "following_url": "https://api.github.com/users/FakeUser1/following{/other_user}", - "gists_url": "https://api.github.com/users/FakeUser1/gists{/gist_id}", - "gravatar_id": "", - "html_url": "https://github.com/FakeUser1", - "id": 13556087, - "login": "FakeUser1", - "node_id": "MDQ6VXNlcjEzNTU2MDg3", - "organizations_url": "https://api.github.com/users/FakeUser1/orgs", - "received_events_url": "https://api.github.com/users/FakeUser1/received_events", - "repos_url": "https://api.github.com/users/FakeUser1/repos", - "site_admin": false, - "starred_url": "https://api.github.com/users/FakeUser1/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/FakeUser1/subscriptions", - "type": "User", - "url": "https://api.github.com/users/FakeUser1" - }, - "assignees": [ - { - "avatar_url": "https://avatars.githubusercontent.com/u/13556087?v=4", - "events_url": "https://api.github.com/users/FakeUser1/events{/privacy}", - "followers_url": "https://api.github.com/users/FakeUser1/followers", - "following_url": "https://api.github.com/users/FakeUser1/following{/other_user}", - "gists_url": "https://api.github.com/users/FakeUser1/gists{/gist_id}", - "gravatar_id": "", - "html_url": "https://github.com/FakeUser1", - "id": 13556087, - "login": "FakeUser1", - "node_id": "MDQ6VXNlcjEzNTU2MDg3", - "organizations_url": "https://api.github.com/users/FakeUser1/orgs", - "received_events_url": "https://api.github.com/users/FakeUser1/received_events", - "repos_url": "https://api.github.com/users/FakeUser1/repos", - "site_admin": false, - "starred_url": "https://api.github.com/users/FakeUser1/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/FakeUser1/subscriptions", - "type": "User", - "url": "https://api.github.com/users/FakeUser1" - } - ], - "author_association": "OWNER", - "body": null, - "closed_at": null, - "comments": 0, - "comments_url": "https://api.github.com/repos/Azure/azure-sdk-fake/issues/14/comments", - "created_at": "2023-01-27T17:01:30Z", - "events_url": "https://api.github.com/repos/Azure/azure-sdk-fake/issues/14/events", - "html_url": "https://github.com/Azure/azure-sdk-fake/issues/14", - "id": 1560095682, - "labels": [ - { - "color": "d73a4a", - "default": true, - "description": "Something isn't working", - "id": 4273699693, - "name": "bug", - "node_id": "LA_kwDOHkcrQs7-u3tt", - "url": "https://api.github.com/repos/Azure/azure-sdk-fake/labels/bug" - }, - { - "color": "F75BB2", - "default": false, - "description": "", - "id": 5095715984, - "name": "Service Attention", - "node_id": "LA_kwDOHkcrQs8AAAABL7p0kA", - "url": "https://api.github.com/repos/Azure/azure-sdk-fake/labels/Service%20Attention" - }, - { - "color": "9C7082", - "default": false, - "description": "fake label for testing", - "id": 5095712487, - "name": "FakeLabel1", - "node_id": "LA_kwDOHkcrQs8AAAABL7pm5w", - "url": "https://api.github.com/repos/Azure/azure-sdk-fake/labels/FakeLabel1" - }, - { - "color": "9C7082", - "default": false, - "description": "fake label for testing", - "id": 5095712487, - "name": "FakeLabel9", - "node_id": "LA_kwDOHkcrQs8AAAABL7pm5w", - "url": "https://api.github.com/repos/Azure/azure-sdk-fake/labels/FakeLabel9" - } - ], - "labels_url": "https://api.github.com/repos/Azure/azure-sdk-fake/issues/14/labels{/name}", - "locked": false, - "milestone": null, - "node_id": "I_kwDOHkcrQs5c_SvC", - "number": 14, - "performed_via_github_app": null, - "reactions": { - "+1": 0, - "-1": 0, - "confused": 0, - "eyes": 0, - "heart": 0, - "hooray": 0, - "laugh": 0, - "rocket": 0, - "total_count": 0, - "url": "https://api.github.com/repos/Azure/azure-sdk-fake/issues/14/reactions" - }, - "repository_url": "https://api.github.com/repos/Azure/azure-sdk-fake", - "state": "open", - "state_reason": null, - "timeline_url": "https://api.github.com/repos/Azure/azure-sdk-fake/issues/14/timeline", - "title": "New test issue to generate event payloads", - "updated_at": "2023-01-30T16:16:54Z", - "url": "https://api.github.com/repos/Azure/azure-sdk-fake/issues/14", - "user": { - "avatar_url": "https://avatars.githubusercontent.com/u/13556087?v=4", - "events_url": "https://api.github.com/users/FakeUser1/events{/privacy}", - "followers_url": "https://api.github.com/users/FakeUser1/followers", - "following_url": "https://api.github.com/users/FakeUser1/following{/other_user}", - "gists_url": "https://api.github.com/users/FakeUser1/gists{/gist_id}", - "gravatar_id": "", - "html_url": "https://github.com/FakeUser1", - "id": 13556087, - "login": "FakeUser1", - "node_id": "MDQ6VXNlcjEzNTU2MDg3", - "organizations_url": "https://api.github.com/users/FakeUser1/orgs", - "received_events_url": "https://api.github.com/users/FakeUser1/received_events", - "repos_url": "https://api.github.com/users/FakeUser1/repos", - "site_admin": false, - "starred_url": "https://api.github.com/users/FakeUser1/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/FakeUser1/subscriptions", - "type": "User", - "url": "https://api.github.com/users/FakeUser1" - } - }, - "label": { - "color": "9C7082", - "default": false, - "description": "fake label for testing", - "id": 5095712487, - "name": "FakeLabel4", - "node_id": "LA_kwDOHkcrQs8AAAABL7pm5w", - "url": "https://api.github.com/repos/Azure/azure-sdk-fake/labels/FakeLabel4" - }, - "repository": { - "allow_forking": true, - "archive_url": "https://api.github.com/repos/Azure/azure-sdk-fake/{archive_format}{/ref}", - "archived": false, - "assignees_url": "https://api.github.com/repos/Azure/azure-sdk-fake/assignees{/user}", - "blobs_url": "https://api.github.com/repos/Azure/azure-sdk-fake/git/blobs{/sha}", - "branches_url": "https://api.github.com/repos/Azure/azure-sdk-fake/branches{/branch}", - "clone_url": "https://github.com/Azure/azure-sdk-fake.git", - "collaborators_url": "https://api.github.com/repos/Azure/azure-sdk-fake/collaborators{/collaborator}", - "comments_url": "https://api.github.com/repos/Azure/azure-sdk-fake/comments{/number}", - "commits_url": "https://api.github.com/repos/Azure/azure-sdk-fake/commits{/sha}", - "compare_url": "https://api.github.com/repos/Azure/azure-sdk-fake/compare/{base}...{head}", - "contents_url": "https://api.github.com/repos/Azure/azure-sdk-fake/contents/{+path}", - "contributors_url": "https://api.github.com/repos/Azure/azure-sdk-fake/contributors", - "created_at": "2022-06-27T16:19:29Z", - "default_branch": "main", - "deployments_url": "https://api.github.com/repos/Azure/azure-sdk-fake/deployments", - "description": "Tools repository leveraged by the Azure SDK team.", - "disabled": false, - "downloads_url": "https://api.github.com/repos/Azure/azure-sdk-fake/downloads", - "events_url": "https://api.github.com/repos/Azure/azure-sdk-fake/events", - "fork": true, - "forks": 0, - "forks_count": 0, - "forks_url": "https://api.github.com/repos/Azure/azure-sdk-fake/forks", - "full_name": "Azure/azure-sdk-fake", - "git_commits_url": "https://api.github.com/repos/Azure/azure-sdk-fake/git/commits{/sha}", - "git_refs_url": "https://api.github.com/repos/Azure/azure-sdk-fake/git/refs{/sha}", - "git_tags_url": "https://api.github.com/repos/Azure/azure-sdk-fake/git/tags{/sha}", - "git_url": "git://github.com/Azure/azure-sdk-fake.git", - "has_discussions": false, - "has_downloads": true, - "has_issues": true, - "has_pages": false, - "has_projects": true, - "has_wiki": true, - "homepage": null, - "hooks_url": "https://api.github.com/repos/Azure/azure-sdk-fake/hooks", - "html_url": "https://github.com/Azure/azure-sdk-fake", - "id": 507980610, - "is_template": false, - "issue_comment_url": "https://api.github.com/repos/Azure/azure-sdk-fake/issues/comments{/number}", - "issue_events_url": "https://api.github.com/repos/Azure/azure-sdk-fake/issues/events{/number}", - "issues_url": "https://api.github.com/repos/Azure/azure-sdk-fake/issues{/number}", - "keys_url": "https://api.github.com/repos/Azure/azure-sdk-fake/keys{/key_id}", - "labels_url": "https://api.github.com/repos/Azure/azure-sdk-fake/labels{/name}", - "language": "C#", - "languages_url": "https://api.github.com/repos/Azure/azure-sdk-fake/languages", - "license": { - "key": "mit", - "name": "MIT License", - "node_id": "MDc6TGljZW5zZTEz", - "spdx_id": "MIT", - "url": "https://api.github.com/licenses/mit" - }, - "merges_url": "https://api.github.com/repos/Azure/azure-sdk-fake/merges", - "milestones_url": "https://api.github.com/repos/Azure/azure-sdk-fake/milestones{/number}", - "mirror_url": null, - "name": "azure-sdk-fake", - "node_id": "R_kgDOHkcrQg", - "notifications_url": "https://api.github.com/repos/Azure/azure-sdk-fake/notifications{?since,all,participating}", - "open_issues": 6, - "open_issues_count": 6, - "owner": { - "avatar_url": "https://avatars.githubusercontent.com/u/13556087?v=4", - "events_url": "https://api.github.com/users/FakeUser1/events{/privacy}", - "followers_url": "https://api.github.com/users/FakeUser1/followers", - "following_url": "https://api.github.com/users/FakeUser1/following{/other_user}", - "gists_url": "https://api.github.com/users/FakeUser1/gists{/gist_id}", - "gravatar_id": "", - "html_url": "https://github.com/FakeUser1", - "id": 13556087, - "login": "FakeUser1", - "node_id": "MDQ6VXNlcjEzNTU2MDg3", - "organizations_url": "https://api.github.com/users/FakeUser1/orgs", - "received_events_url": "https://api.github.com/users/FakeUser1/received_events", - "repos_url": "https://api.github.com/users/FakeUser1/repos", - "site_admin": false, - "starred_url": "https://api.github.com/users/FakeUser1/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/FakeUser1/subscriptions", - "type": "User", - "url": "https://api.github.com/users/FakeUser1" - }, - "private": false, - "pulls_url": "https://api.github.com/repos/Azure/azure-sdk-fake/pulls{/number}", - "pushed_at": "2023-01-27T16:33:00Z", - "releases_url": "https://api.github.com/repos/Azure/azure-sdk-fake/releases{/id}", - "size": 29098, - "ssh_url": "git@github.com:Azure/azure-sdk-fake.git", - "stargazers_count": 0, - "stargazers_url": "https://api.github.com/repos/Azure/azure-sdk-fake/stargazers", - "statuses_url": "https://api.github.com/repos/Azure/azure-sdk-fake/statuses/{sha}", - "subscribers_url": "https://api.github.com/repos/Azure/azure-sdk-fake/subscribers", - "subscription_url": "https://api.github.com/repos/Azure/azure-sdk-fake/subscription", - "svn_url": "https://github.com/Azure/azure-sdk-fake", - "tags_url": "https://api.github.com/repos/Azure/azure-sdk-fake/tags", - "teams_url": "https://api.github.com/repos/Azure/azure-sdk-fake/teams", - "topics": [], - "trees_url": "https://api.github.com/repos/Azure/azure-sdk-fake/git/trees{/sha}", - "updated_at": "2023-01-23T19:54:18Z", - "url": "https://api.github.com/repos/Azure/azure-sdk-fake", - "visibility": "public", - "watchers": 0, - "watchers_count": 0, - "web_commit_signoff_required": false - }, - "sender": { - "avatar_url": "https://avatars.githubusercontent.com/u/13556087?v=4", - "events_url": "https://api.github.com/users/FakeUser1/events{/privacy}", - "followers_url": "https://api.github.com/users/FakeUser1/followers", - "following_url": "https://api.github.com/users/FakeUser1/following{/other_user}", - "gists_url": "https://api.github.com/users/FakeUser1/gists{/gist_id}", - "gravatar_id": "", - "html_url": "https://github.com/FakeUser1", - "id": 13556087, - "login": "FakeUser1", - "node_id": "MDQ6VXNlcjEzNTU2MDg3", - "organizations_url": "https://api.github.com/users/FakeUser1/orgs", - "received_events_url": "https://api.github.com/users/FakeUser1/received_events", - "repos_url": "https://api.github.com/users/FakeUser1/repos", - "site_admin": false, - "starred_url": "https://api.github.com/users/FakeUser1/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/FakeUser1/subscriptions", - "type": "User", - "url": "https://api.github.com/users/FakeUser1" - } -} diff --git a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/Constants/LabelConstants.cs b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/Constants/TriageLabelConstants.cs similarity index 79% rename from tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/Constants/LabelConstants.cs rename to tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/Constants/TriageLabelConstants.cs index f7097f415ce..f947a4f50cf 100644 --- a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/Constants/LabelConstants.cs +++ b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/Constants/TriageLabelConstants.cs @@ -6,11 +6,10 @@ namespace Azure.Sdk.Tools.GitHubEventProcessor.Constants { /// - /// These are label constants that are common to all language repositories and ones - /// that the rules use for processing. No team, or lanaguage specific labels belong - /// in here. + /// These are triage label constants and are common to all language repositories. No category labels, + /// service labels or repository specific labels belong in here. /// - public class LabelConstants + public class TriageLabelConstants { public const string CommunityContribution = "Community Contribution"; public const string CustomerReported = "customer-reported"; diff --git a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/EventProcessing/IssueCommentProcessing.cs b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/EventProcessing/IssueCommentProcessing.cs index 4e347d2cd4f..da523013b00 100644 --- a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/EventProcessing/IssueCommentProcessing.cs +++ b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/EventProcessing/IssueCommentProcessing.cs @@ -46,11 +46,11 @@ public static void AuthorFeedback(GitHubEventClient gitHubEventClient, IssueComm if (issueCommentPayload.Action == ActionConstants.Created) { if (issueCommentPayload.Issue.State == ItemState.Open && - LabelUtils.HasLabel(issueCommentPayload.Issue.Labels, LabelConstants.NeedsAuthorFeedback) && + LabelUtils.HasLabel(issueCommentPayload.Issue.Labels, TriageLabelConstants.NeedsAuthorFeedback) && issueCommentPayload.Sender.Login == issueCommentPayload.Issue.User.Login) { - gitHubEventClient.RemoveLabel(LabelConstants.NeedsAuthorFeedback); - gitHubEventClient.AddLabel(LabelConstants.NeedsTeamAttention); + gitHubEventClient.RemoveLabel(TriageLabelConstants.NeedsAuthorFeedback); + gitHubEventClient.AddLabel(TriageLabelConstants.NeedsTeamAttention); } } } @@ -95,17 +95,17 @@ public static void ReopenIssue(GitHubEventClient gitHubEventClient, IssueComment if (issueCommentPayload.Action == ActionConstants.Created) { if (issueCommentPayload.Issue.State == ItemState.Closed && - LabelUtils.HasLabel(issueCommentPayload.Issue.Labels, LabelConstants.NoRecentActivity) && - LabelUtils.HasLabel(issueCommentPayload.Issue.Labels, LabelConstants.NeedsAuthorFeedback) && + LabelUtils.HasLabel(issueCommentPayload.Issue.Labels, TriageLabelConstants.NoRecentActivity) && + LabelUtils.HasLabel(issueCommentPayload.Issue.Labels, TriageLabelConstants.NeedsAuthorFeedback) && issueCommentPayload.Sender.Login == issueCommentPayload.Issue.User.Login && issueCommentPayload.Comment.CreatedAt != issueCommentPayload.Issue.ClosedAt.Value && // Ensure both times are in UTC so timezones don't get tripped up. ClosedAt is nullable // but being that the issue is closed is part of the criteria, this will be set DateTime.UtcNow <= issueCommentPayload.Issue.ClosedAt.Value.UtcDateTime.AddDays(7)) { - gitHubEventClient.RemoveLabel(LabelConstants.NeedsAuthorFeedback); - gitHubEventClient.RemoveLabel(LabelConstants.NoRecentActivity); - gitHubEventClient.AddLabel(LabelConstants.NeedsTeamAttention); + gitHubEventClient.RemoveLabel(TriageLabelConstants.NeedsAuthorFeedback); + gitHubEventClient.RemoveLabel(TriageLabelConstants.NoRecentActivity); + gitHubEventClient.AddLabel(TriageLabelConstants.NeedsTeamAttention); gitHubEventClient.SetIssueState(issueCommentPayload.Issue, ItemState.Open); } } @@ -173,7 +173,7 @@ public static async Task IssueAddressedCommands(GitHubEventClient gitHubEventCli if (issueCommentPayload.Action == ActionConstants.Created) { if (CommentUtils.CommentContainsText(issueCommentPayload.Comment.Body, CommentConstants.Unresolve) && - LabelUtils.HasLabel(issueCommentPayload.Issue.Labels, LabelConstants.IssueAddressed)) + LabelUtils.HasLabel(issueCommentPayload.Issue.Labels, TriageLabelConstants.IssueAddressed)) { bool hasAdminOrWritePermission = await gitHubEventClient.DoesUserHaveAdminOrWritePermission(issueCommentPayload.Repository.Id, issueCommentPayload.Sender.Login); @@ -182,8 +182,8 @@ public static async Task IssueAddressedCommands(GitHubEventClient gitHubEventCli hasAdminOrWritePermission) { gitHubEventClient.SetIssueState(issueCommentPayload.Issue, ItemState.Open); - gitHubEventClient.RemoveLabel(LabelConstants.IssueAddressed); - gitHubEventClient.AddLabel(LabelConstants.NeedsTeamAttention); + gitHubEventClient.RemoveLabel(TriageLabelConstants.IssueAddressed); + gitHubEventClient.AddLabel(TriageLabelConstants.NeedsTeamAttention); } // else the user is not the original author AND they don't have admin or write permission else diff --git a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/EventProcessing/IssueProcessing.cs b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/EventProcessing/IssueProcessing.cs index d4b5848a2c7..257f5900264 100644 --- a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/EventProcessing/IssueProcessing.cs +++ b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/EventProcessing/IssueProcessing.cs @@ -15,6 +15,7 @@ using System.Security; using Azure.Sdk.Tools.CodeownersUtils.Verification; using System.Runtime.Intrinsics.X86; +using Azure.Sdk.Tools.CodeownersUtils.Parsing; namespace Azure.Sdk.Tools.GitHubEventProcessor.EventProcessing { @@ -41,45 +42,210 @@ public static async Task ProcessIssueEvent(GitHubEventClient gitHubEventClient, await gitHubEventClient.ProcessPendingUpdates(issueEventPayload.Repository.Id, issueEventPayload.Issue.Number); } - /// - /// Initial Issue Triage - /// Trigger: issue opened - /// Conditions: Issue has no labels - /// Issue has no assignee - /// Resulting Actions: - /// Query AI label service for label suggestions: - /// IF labels were predicted: - /// - Assign returned labels to the issue - /// IF service and category labels have AzureSdkOwners (in CODEOWNERS): - /// IF a single AzureSdkOwner: - /// - Assign the AzureSdkOwner issue - /// ELSE - /// - Assign a random AzureSdkOwner from the set to the issue - /// - Create the following comment, mentioning all AzureSdkOwners from the set - /// "@{person1} @{person2}...${personX}" - /// - Create the following comment - /// "Thank you for your feedback. Tagging and routing to the team member best able to assist." - /// - /// # Note: No valid AzureSdkOwners means there were no CODEOWNERS entries for the ServiceLabel OR no - /// # CODEOWNERS entries for the ServiceLabel with AzureSdkOwners OR there is a CODEOWNERS entry with - /// # AzureSdkOwners but none of them have permissions to be assigned to an issue for the repository. - /// IF there are no valid AzureSdkOwners, but there are ServiceOwners, and the ServiceAttention rule is enabled - /// - Add "Service Attention" label to the issue and apply the logic from the "Service Attention" rule - /// ELSE - /// - Add "needs-team-triage" (at this point it owners cannot be determined for this issue) - /// - /// IF "needs-team-triage" is not being added to the issue - /// - Add "needs-team-attention" label to the issue - /// - /// - /// Evaluate the user that created the issue: - /// IF the user is NOT a member of the Azure Org - /// IF the user does not have Admin or Write Collaborator permission - /// - Add "customer-reported" label - /// - Add "question" label - /// - /// Authenticated GitHubEventClient - /// IssueEventGitHubPayload deserialized from the json event payload + + // TODO-START + // When the CODEOWNERS files are updated with the AzureSdkOwners, select everything in between the TODO-START and + // TODO-END tags, in VS, and do a ctrl-k, ctrl-u to uncomment the function and delete the TODO comments. The + // in the test project, in IssueProcessingTests.cs, remove the Ignore attribute that's TestInitialIssueTriage tests + ///// + ///// Initial Issue Triage + ///// Trigger: issue opened + ///// Conditions: Issue has no labels + ///// Issue has no assignee + ///// Resulting Actions: + ///// Query AI label service for label suggestions: + ///// IF labels were predicted: + ///// - Assign returned labels to the issue + ///// IF service and category labels have AzureSdkOwners (in CODEOWNERS): + ///// IF a single AzureSdkOwner: + ///// - Assign the AzureSdkOwner issue + ///// ELSE + ///// - Assign a random AzureSdkOwner from the set to the issue + ///// - Create the following comment, mentioning all AzureSdkOwners from the set + ///// "@{person1} @{person2}...${personX}" + ///// - Create the following comment + ///// "Thank you for your feedback. Tagging and routing to the team member best able to assist." + ///// + ///// # Note: No valid AzureSdkOwners means there were no CODEOWNERS entries for the ServiceLabel OR no + ///// # CODEOWNERS entries for the ServiceLabel with AzureSdkOwners OR there is a CODEOWNERS entry with + ///// # AzureSdkOwners but none of them have permissions to be assigned to an issue for the repository. + ///// IF there are no valid AzureSdkOwners, but there are ServiceOwners, and the ServiceAttention rule is enabled + ///// - Add "Service Attention" label to the issue and apply the logic from the "Service Attention" rule + ///// ELSE + ///// - Add "needs-team-triage" (at this point it owners cannot be determined for this issue) + ///// + ///// IF "needs-team-triage" is not being added to the issue + ///// - Add "needs-team-attention" label to the issue + ///// + ///// + ///// Evaluate the user that created the issue: + ///// IF the user is NOT a member of the Azure Org + ///// IF the user does not have Admin or Write Collaborator permission + ///// - Add "customer-reported" label + ///// - Add "question" label + ///// + ///// Authenticated GitHubEventClient + ///// IssueEventGitHubPayload deserialized from the json event payload + //public static async Task InitialIssueTriage(GitHubEventClient gitHubEventClient, IssueEventGitHubPayload issueEventPayload) + //{ + // if (gitHubEventClient.RulesConfiguration.RuleEnabled(RulesConstants.InitialIssueTriage)) + // { + // if (issueEventPayload.Action == ActionConstants.Opened) + // { + // // If there are no labels and no assignees + // if ((issueEventPayload.Issue.Labels.Count == 0) && (issueEventPayload.Issue.Assignee == null)) + // { + // List labelSuggestions = await gitHubEventClient.QueryAILabelService(issueEventPayload); + // if (labelSuggestions.Count > 0) + // { + // // If labels were predicted, add them to the issue + // foreach (string label in labelSuggestions) + // { + // gitHubEventClient.AddLabel(label); + // } + + // // needs-team-attention needs to be added if it can be determined who this issue actually + // // belongs to. + // bool addNeedsTeamAttention = true; + + // CodeownersEntry codeownersEntry = CodeOwnerUtils.GetCodeownersEntryForLabelList(labelSuggestions); + // bool hasValidAssignee = false; + // if (codeownersEntry.AzureSdkOwners.Count > 0) + // { + // // If there's only a single owner, + // if (codeownersEntry.AzureSdkOwners.Count == 1) + // { + // if (await gitHubEventClient.OwnerCanBeAssignedToIssuesInRepo( + // issueEventPayload.Repository.Owner.Login, + // issueEventPayload.Repository.Name, + // codeownersEntry.AzureSdkOwners[0])) + // { + // hasValidAssignee = true; + // gitHubEventClient.AssignOwnerToIssue( + // issueEventPayload.Repository.Owner.Login, + // issueEventPayload.Repository.Name, + // codeownersEntry.AzureSdkOwners[0]); + // } + // // Output something into the logs pointing out that AzureSdkOwners has a user that cannot + // // be assigned to an issue + // else + // { + // Console.WriteLine($"{codeownersEntry.AzureSdkOwners[0]} is the only owner in the AzureSdkOwners for service label(s), {string.Join(",", labelSuggestions)}, but cannot be assigned as an issue owner in this repository."); + // } + // } + // // else there are multiple owners and a random one needs to be assigned + // else + // { + // // Create a list of AzureSdkOwners that has been randomized. The reason + // // the entire list is being randomed is because each person has to be + // // checked to see if they can be assigned to an issue in the repository. + // // and having the entire list being random simplifies processing if a given + // // owner cannot be assigned. + // var rnd = new Random(); + // var randomAzureSdkOwners = codeownersEntry.AzureSdkOwners.OrderBy(item => rnd.Next(0, codeownersEntry.AzureSdkOwners.Count)); + // foreach (string azureSdkOwner in randomAzureSdkOwners) + // { + // if (await gitHubEventClient.OwnerCanBeAssignedToIssuesInRepo( + // issueEventPayload.Repository.Owner.Login, + // issueEventPayload.Repository.Name, + // azureSdkOwner)) + // { + // hasValidAssignee = true; + // gitHubEventClient.AssignOwnerToIssue(issueEventPayload.Repository.Owner.Login, + // issueEventPayload.Repository.Name, + // azureSdkOwner); + // // As soon as there's a valid assignee, add the comment mentioning everyone + // // in the AzureSdkOwners and exit. The @ mention is only necessary if there + // // are multiple AzureSdkOwners. + // string azureSdkOwnersAtMention = CodeOwnerUtils.CreateAtMentionForOwnerList(codeownersEntry.AzureSdkOwners); + // gitHubEventClient.CreateComment(issueEventPayload.Repository.Id, + // issueEventPayload.Issue.Number, + // azureSdkOwnersAtMention); + // break; + // } + // else + // { + // Console.WriteLine($"{azureSdkOwner} is an AzureSdkOwner for service labels {string.Join(",", labelSuggestions)} but cannot be assigned as an issue owner in this repository."); + // } + // } + // } + // // If the issue had a valid assignee add the comment + // if (hasValidAssignee) + // { + // string issueComment = "Thank you for your feedback. Tagging and routing to the team member best able to assist."; + // gitHubEventClient.CreateComment(issueEventPayload.Repository.Id, + // issueEventPayload.Issue.Number, + // issueComment); + // } + // else + // { + // // Output a message indicating every owner in the AzureSdkOwners, for the AI label suggestions. The lines immediately + // // above this output will contain the messages for each user checked. + // Console.WriteLine($"AzureSdkOwners for service labels {string.Join(",", labelSuggestions)} has no owners that can be assigned to issues in this repository."); + // } + // } + + // // If there's no valid AzureSdkOwner to assign the issue to (this means that there's either + // // no AzureSdkOwners or none of them have permissions to be assigned to an issue) + // if (!hasValidAssignee) + // { + // // Check to see if there are ServiceOwners and the ServiceAttention rule is turned on. If + // // both are true then add the ServiceAttention label and run ServiceAttention processing + // if (codeownersEntry.ServiceOwners.Count > 0 + // && gitHubEventClient.RulesConfiguration.RuleEnabled(RulesConstants.ServiceAttention, + // false /* don't output log messages for this check*/)) + + // { + // gitHubEventClient.AddLabel(TriageLabelConstants.ServiceAttention); + // Common_ProcessServiceAttentionForLabels(gitHubEventClient, + // issueEventPayload.Issue, + // issueEventPayload.Repository.Id, + // labelSuggestions); + // } + // // At this point, it cannot be determined who this issue belongs to. Add + // // the needs-team-triage label instead of the needs-team-attention label + // else + // { + // gitHubEventClient.AddLabel(TriageLabelConstants.NeedsTeamTriage); + // addNeedsTeamAttention = false; + // } + // } + + // // The needs-team-attention label is only added when it can be determined + // // who this issue belongs to. + // if (addNeedsTeamAttention) + // { + // gitHubEventClient.AddLabel(TriageLabelConstants.NeedsTeamAttention); + // } + // gitHubEventClient.AddLabel(TriageLabelConstants.NeedsTeamTriage); + + // } + // // If there are no labels predicted add NeedsTriage to the issue + // else + // { + // gitHubEventClient.AddLabel(TriageLabelConstants.NeedsTriage); + // } + + // // If the user is not a member of the Azure Org AND the user does not have write or admin collaborator permission. + // // This piece is executed for every issue created that doesn't have labels or owners on it at the time of creation. + // bool isMemberOfOrg = await gitHubEventClient.IsUserMemberOfOrg(OrgConstants.Azure, issueEventPayload.Issue.User.Login); + // if (!isMemberOfOrg) + // { + // bool hasAdminOrWritePermission = await gitHubEventClient.DoesUserHaveAdminOrWritePermission(issueEventPayload.Repository.Id, issueEventPayload.Issue.User.Login); + // if (!hasAdminOrWritePermission) + // { + // gitHubEventClient.AddLabel(TriageLabelConstants.CustomerReported); + // gitHubEventClient.AddLabel(TriageLabelConstants.Question); + // } + // } + // } + // } + // } + //} + // TODO-END + + // This is the IntitialIssueTriage as it exists today. It's the old rule that needs to be replaced by the commented out + // function above. public static async Task InitialIssueTriage(GitHubEventClient gitHubEventClient, IssueEventGitHubPayload issueEventPayload) { if (gitHubEventClient.RulesConfiguration.RuleEnabled(RulesConstants.InitialIssueTriage)) @@ -92,136 +258,19 @@ public static async Task InitialIssueTriage(GitHubEventClient gitHubEventClient, List labelSuggestions = await gitHubEventClient.QueryAILabelService(issueEventPayload); if (labelSuggestions.Count > 0) { - // needs-team-attention needs to be added if it can be determined who this issue actually - // belongs to. // If labels were predicted, add them to the issue foreach (string label in labelSuggestions) { gitHubEventClient.AddLabel(label); } - // Uncomment this when CODEOWNERS are unfubar'd - //bool addNeedsTeamAttention = true; - - //var azureSdkOwners = CodeOwnerUtils.GetAzureSdkOwnersForServiceLabels(labelSuggestions); - //bool hasValidAssignee = false; - //if (azureSdkOwners.Count > 0) - //{ - // // If there's only a single owner, - // if (azureSdkOwners.Count == 1) - // { - // if (await gitHubEventClient.OwnerCanBeAssignedToIssuesInRepo( - // issueEventPayload.Repository.Owner.Login, - // issueEventPayload.Repository.Name, - // azureSdkOwners[0])) - // { - // hasValidAssignee = true; - // gitHubEventClient.AssignOwnerToIssue( - // issueEventPayload.Repository.Owner.Login, - // issueEventPayload.Repository.Name, - // azureSdkOwners[0]); - // } - // // Output something into the logs pointing out that AzureSdkOwners has a user that cannot - // // be assigned to an issue - // else - // { - // Console.WriteLine($"{azureSdkOwners[0]} is the only owner in the AzureSdkOwners for service label(s), {string.Join(",", labelSuggestions)}, but cannot be assigned as an issue owner in this repository."); - // } - // } - // // else there are multiple owners and a random one needs to be assigned - // else - // { - // // Create a list of AzureSdkOwners that has been randomized. The reason - // // the entire list is being randomed is because each person has to be - // // checked to see if they can be assigned to an issue in the repository. - // // and having the entire list being random simplifies processing if a given - // // owner cannot be assigned. - // var rnd = new Random(); - // var randomAzureSdkOwners = azureSdkOwners.OrderBy(item => rnd.Next(0, azureSdkOwners.Count)); - // foreach (string azureSdkOwner in randomAzureSdkOwners) - // { - // if (await gitHubEventClient.OwnerCanBeAssignedToIssuesInRepo( - // issueEventPayload.Repository.Owner.Login, - // issueEventPayload.Repository.Name, - // azureSdkOwner)) - // { - // hasValidAssignee = true; - // gitHubEventClient.AssignOwnerToIssue(issueEventPayload.Repository.Owner.Login, - // issueEventPayload.Repository.Name, - // azureSdkOwner); - // // As soon as there's a valid assignee, add the comment mentioning everyone - // // in the AzureSdkOwners and exit. The @ mention is only necessary if there - // // are multiple AzureSdkOwners. - // string azureSdkOwnersAtMention = CodeOwnerUtils.CreateAtMentionForOwnerList(azureSdkOwners); - // gitHubEventClient.CreateComment(issueEventPayload.Repository.Id, - // issueEventPayload.Issue.Number, - // azureSdkOwnersAtMention); - // break; - // } - // else - // { - // Console.WriteLine($"{azureSdkOwner} is an AzureSdkOwner for service labels {string.Join(",", labelSuggestions)} but cannot be assigned as an issue owner in this repository."); - // } - // } - // } - // // If the issue had a valid assignee add the comment - // if (hasValidAssignee) - // { - // string issueComment = "Thank you for your feedback. Tagging and routing to the team member best able to assist."; - // gitHubEventClient.CreateComment(issueEventPayload.Repository.Id, - // issueEventPayload.Issue.Number, - // issueComment); - // } - // else - // { - // // Output a message indicating every owner in the AzureSdkOwners, for the AI label suggestions. The lines immediately - // // above this output will contain the messages for each user checked. - // Console.WriteLine($"AzureSdkOwners for service labels {string.Join(",", labelSuggestions)} has no owners that can be assigned to issues in this repository."); - // } - //} - - //// If there's no valid AzureSdkOwner to assign the issue to (this means that there's either - //// no AzureSdkOwners or none of them have permissions to be assigned to an issue) - //if (!hasValidAssignee) - //{ - // // Get the list of ServiceOwners, if any. - // var serviceOwners = CodeOwnerUtils.GetServiceOwnersForServiceLabels(labelSuggestions); - - // // Check to see if there are ServiceOwners and the ServiceAttention rule is turned on. If - // // both are true then add the ServiceAttention label and run ServiceAttention processing - // if (serviceOwners.Count > 0 - // && gitHubEventClient.RulesConfiguration.RuleEnabled(RulesConstants.ServiceAttention, - // false /* don't output log messages for this check*/)) - - // { - // gitHubEventClient.AddLabel(LabelConstants.ServiceAttention); - // Common_ProcessServiceAttentionForLabels(gitHubEventClient, - // issueEventPayload.Issue, - // issueEventPayload.Repository.Id, - // labelSuggestions); - // } - // // At this point, it cannot be determined who this issue belongs to. Add - // // the needs-team-triage label instead of the needs-team-attention label - // else - // { - // gitHubEventClient.AddLabel(LabelConstants.NeedsTeamTriage); - // addNeedsTeamAttention = false; - // } - //} - - //// The needs-team-attention label is only added when it can be determined - //// who this issue belongs to. - //if (addNeedsTeamAttention) - //{ - // gitHubEventClient.AddLabel(LabelConstants.NeedsTeamAttention); - //} - gitHubEventClient.AddLabel(LabelConstants.NeedsTeamTriage); + gitHubEventClient.AddLabel(TriageLabelConstants.NeedsTeamTriage); } // If there are no labels predicted add NeedsTriage to the issue else { - gitHubEventClient.AddLabel(LabelConstants.NeedsTriage); + gitHubEventClient.AddLabel(TriageLabelConstants.NeedsTriage); } // If the user is not a member of the Azure Org AND the user does not have write or admin collaborator permission. @@ -232,8 +281,8 @@ public static async Task InitialIssueTriage(GitHubEventClient gitHubEventClient, bool hasAdminOrWritePermission = await gitHubEventClient.DoesUserHaveAdminOrWritePermission(issueEventPayload.Repository.Id, issueEventPayload.Issue.User.Login); if (!hasAdminOrWritePermission) { - gitHubEventClient.AddLabel(LabelConstants.CustomerReported); - gitHubEventClient.AddLabel(LabelConstants.Question); + gitHubEventClient.AddLabel(TriageLabelConstants.CustomerReported); + gitHubEventClient.AddLabel(TriageLabelConstants.Question); } } } @@ -260,10 +309,10 @@ public static void ManualIssueTriage(GitHubEventClient gitHubEventClient, IssueE // if the issue is open, has needs-triage label and label being added is not needs-triage // then remove the needs-triage label if (issueEventPayload.Issue.State == ItemState.Open && - LabelUtils.HasLabel(issueEventPayload.Issue.Labels, LabelConstants.NeedsTriage) && - !issueEventPayload.Label.Name.Equals(LabelConstants.NeedsTriage)) + LabelUtils.HasLabel(issueEventPayload.Issue.Labels, TriageLabelConstants.NeedsTriage) && + !issueEventPayload.Label.Name.Equals(TriageLabelConstants.NeedsTriage)) { - gitHubEventClient.RemoveLabel(LabelConstants.NeedsTriage); + gitHubEventClient.RemoveLabel(TriageLabelConstants.NeedsTriage); } } } @@ -289,7 +338,7 @@ public static void ServiceAttention(GitHubEventClient gitHubEventClient, IssueEv { // If ServiceAttention was the label added then for each label already on the issue that isn't // ServiceAttention find the people to @ mention - if (issueEventPayload.Label.Name.Equals(LabelConstants.ServiceAttention)) + if (issueEventPayload.Label.Name.Equals(TriageLabelConstants.ServiceAttention)) { // Before bothering to fetch parties to mention from the CodeOwners file, ensure that ServiceAttention // isn't the only label on the issue. @@ -299,19 +348,9 @@ public static void ServiceAttention(GitHubEventClient gitHubEventClient, IssueEv } else { - Console.WriteLine($"{LabelConstants.ServiceAttention} is the only label on the issue. Other labels are required in order to get parties to mention from the Codeowners file."); + Console.WriteLine($"{TriageLabelConstants.ServiceAttention} is the only label on the issue. Other labels are required in order to get parties to mention from the Codeowners file."); } } - // Else the label being added is not ServiceAttention and ServiceAttention is already on the issue - // but only for the label added - else if (!issueEventPayload.Label.Name.Equals(LabelConstants.ServiceAttention) && - LabelUtils.HasLabel(issueEventPayload.Issue.Labels, LabelConstants.ServiceAttention)) - { - Common_ProcessServiceAttentionForLabels(gitHubEventClient, - issueEventPayload.Issue, - issueEventPayload.Repository.Id, - new List { issueEventPayload.Label.Name }); - } } } } @@ -336,11 +375,11 @@ public static void ManualTriageAfterExternalAssignment(GitHubEventClient gitHubE { if (issueEventPayload.Issue.State == ItemState.Open && issueEventPayload.Issue.Assignee == null && - issueEventPayload.Label.Name.Equals(LabelConstants.ServiceAttention) && - LabelUtils.HasLabel(issueEventPayload.Issue.Labels, LabelConstants.CustomerReported) && - !LabelUtils.HasLabel(issueEventPayload.Issue.Labels, LabelConstants.NeedsTeamTriage)) + issueEventPayload.Label.Name.Equals(TriageLabelConstants.ServiceAttention) && + LabelUtils.HasLabel(issueEventPayload.Issue.Labels, TriageLabelConstants.CustomerReported) && + !LabelUtils.HasLabel(issueEventPayload.Issue.Labels, TriageLabelConstants.NeedsTeamTriage)) { - gitHubEventClient.AddLabel(LabelConstants.NeedsTeamTriage); + gitHubEventClient.AddLabel(TriageLabelConstants.NeedsTeamTriage); } } } @@ -379,11 +418,11 @@ public static void Common_ResetIssueActivity(GitHubEventClient gitHubEventClient if (gitHubEventClient.RulesConfiguration.RuleEnabled(RulesConstants.ResetIssueActivity)) { if ((issue.State == ItemState.Open || action == ActionConstants.Reopened) && - LabelUtils.HasLabel(issue.Labels, LabelConstants.NoRecentActivity) && + LabelUtils.HasLabel(issue.Labels, TriageLabelConstants.NoRecentActivity) && // If a user is a known GitHub bot, the user's AccountType will be Bot sender.Type != AccountType.Bot) { - gitHubEventClient.RemoveLabel(LabelConstants.NoRecentActivity); + gitHubEventClient.RemoveLabel(TriageLabelConstants.NoRecentActivity); } } } @@ -417,10 +456,10 @@ public static void Common_ProcessServiceAttentionForLabels(GitHubEventClient git { if (labels.Count > 0) { - List ownersToMention = CodeOwnerUtils.GetServiceOwnersForServiceLabels(labels); - if (ownersToMention.Count > 0) + CodeownersEntry codeownersEntry = CodeOwnerUtils.GetCodeownersEntryForLabelList(labels); + if (codeownersEntry.ServiceOwners.Count > 0) { - string partiesToMention = CodeOwnerUtils.CreateAtMentionForOwnerList(ownersToMention); + string partiesToMention = CodeOwnerUtils.CreateAtMentionForOwnerList(codeownersEntry.ServiceOwners); string issueComment = $"Thanks for the feedback! We are routing this to the appropriate team for follow-up. cc {partiesToMention}."; gitHubEventClient.CreateComment(repositoryId, issue.Number, issueComment); } @@ -455,15 +494,15 @@ public static void RequireAttentionForNonMilestone(GitHubEventClient gitHubEvent if (issueEventPayload.Action == ActionConstants.Labeled || issueEventPayload.Action == ActionConstants.Unlabeled) { if (issueEventPayload.Issue.State == ItemState.Open && - LabelUtils.HasLabel(issueEventPayload.Issue.Labels, LabelConstants.CustomerReported) && - !LabelUtils.HasLabel(issueEventPayload.Issue.Labels, LabelConstants.NeedsTeamAttention) && - !LabelUtils.HasLabel(issueEventPayload.Issue.Labels, LabelConstants.NeedsTriage) && - !LabelUtils.HasLabel(issueEventPayload.Issue.Labels, LabelConstants.NeedsTeamTriage) && - !LabelUtils.HasLabel(issueEventPayload.Issue.Labels, LabelConstants.NeedsAuthorFeedback) && - !LabelUtils.HasLabel(issueEventPayload.Issue.Labels, LabelConstants.IssueAddressed) && + LabelUtils.HasLabel(issueEventPayload.Issue.Labels, TriageLabelConstants.CustomerReported) && + !LabelUtils.HasLabel(issueEventPayload.Issue.Labels, TriageLabelConstants.NeedsTeamAttention) && + !LabelUtils.HasLabel(issueEventPayload.Issue.Labels, TriageLabelConstants.NeedsTriage) && + !LabelUtils.HasLabel(issueEventPayload.Issue.Labels, TriageLabelConstants.NeedsTeamTriage) && + !LabelUtils.HasLabel(issueEventPayload.Issue.Labels, TriageLabelConstants.NeedsAuthorFeedback) && + !LabelUtils.HasLabel(issueEventPayload.Issue.Labels, TriageLabelConstants.IssueAddressed) && null == issueEventPayload.Issue.Milestone) { - gitHubEventClient.AddLabel(LabelConstants.NeedsTeamAttention); + gitHubEventClient.AddLabel(TriageLabelConstants.NeedsTeamAttention); } } } @@ -492,21 +531,21 @@ public static void AuthorFeedbackNeeded(GitHubEventClient gitHubEventClient, Iss if (issueEventPayload.Action == ActionConstants.Labeled) { if (issueEventPayload.Issue.State == ItemState.Open && - issueEventPayload.Label.Name == LabelConstants.NeedsAuthorFeedback) + issueEventPayload.Label.Name == TriageLabelConstants.NeedsAuthorFeedback) { // Any of these labels will be removed if they exist on the Issue. If none exist then // then the comment will be the only update - if (LabelUtils.HasLabel(issueEventPayload.Issue.Labels, LabelConstants.NeedsTriage)) + if (LabelUtils.HasLabel(issueEventPayload.Issue.Labels, TriageLabelConstants.NeedsTriage)) { - gitHubEventClient.RemoveLabel(LabelConstants.NeedsTriage); + gitHubEventClient.RemoveLabel(TriageLabelConstants.NeedsTriage); } - if (LabelUtils.HasLabel(issueEventPayload.Issue.Labels, LabelConstants.NeedsTeamTriage)) + if (LabelUtils.HasLabel(issueEventPayload.Issue.Labels, TriageLabelConstants.NeedsTeamTriage)) { - gitHubEventClient.RemoveLabel(LabelConstants.NeedsTeamTriage); + gitHubEventClient.RemoveLabel(TriageLabelConstants.NeedsTeamTriage); } - if (LabelUtils.HasLabel(issueEventPayload.Issue.Labels, LabelConstants.NeedsTeamAttention)) + if (LabelUtils.HasLabel(issueEventPayload.Issue.Labels, TriageLabelConstants.NeedsTeamAttention)) { - gitHubEventClient.RemoveLabel(LabelConstants.NeedsTeamAttention); + gitHubEventClient.RemoveLabel(TriageLabelConstants.NeedsTeamAttention); } string issueComment = $"Hi @{issueEventPayload.Issue.User.Login}. Thank you for opening this issue and giving us the opportunity to assist. To help our team better understand your issue and the details of your scenario please provide a response to the question asked above or the information requested above. This will help us more accurately address your issue."; gitHubEventClient.CreateComment(issueEventPayload.Repository.Id, issueEventPayload.Issue.Number, issueComment); @@ -537,27 +576,27 @@ public static void IssueAddressed(GitHubEventClient gitHubEventClient, IssueEven if (issueEventPayload.Action == ActionConstants.Labeled) { if (issueEventPayload.Issue.State == ItemState.Open && - issueEventPayload.Label.Name == LabelConstants.IssueAddressed) + issueEventPayload.Label.Name == TriageLabelConstants.IssueAddressed) { - if (LabelUtils.HasLabel(issueEventPayload.Issue.Labels, LabelConstants.NeedsTriage)) + if (LabelUtils.HasLabel(issueEventPayload.Issue.Labels, TriageLabelConstants.NeedsTriage)) { - gitHubEventClient.RemoveLabel(LabelConstants.NeedsTriage); + gitHubEventClient.RemoveLabel(TriageLabelConstants.NeedsTriage); } - if (LabelUtils.HasLabel(issueEventPayload.Issue.Labels, LabelConstants.NeedsTeamTriage)) + if (LabelUtils.HasLabel(issueEventPayload.Issue.Labels, TriageLabelConstants.NeedsTeamTriage)) { - gitHubEventClient.RemoveLabel(LabelConstants.NeedsTeamTriage); + gitHubEventClient.RemoveLabel(TriageLabelConstants.NeedsTeamTriage); } - if (LabelUtils.HasLabel(issueEventPayload.Issue.Labels, LabelConstants.NeedsTeamAttention)) + if (LabelUtils.HasLabel(issueEventPayload.Issue.Labels, TriageLabelConstants.NeedsTeamAttention)) { - gitHubEventClient.RemoveLabel(LabelConstants.NeedsTeamAttention); + gitHubEventClient.RemoveLabel(TriageLabelConstants.NeedsTeamAttention); } - if (LabelUtils.HasLabel(issueEventPayload.Issue.Labels, LabelConstants.NeedsAuthorFeedback)) + if (LabelUtils.HasLabel(issueEventPayload.Issue.Labels, TriageLabelConstants.NeedsAuthorFeedback)) { - gitHubEventClient.RemoveLabel(LabelConstants.NeedsAuthorFeedback); + gitHubEventClient.RemoveLabel(TriageLabelConstants.NeedsAuthorFeedback); } - if (LabelUtils.HasLabel(issueEventPayload.Issue.Labels, LabelConstants.NoRecentActivity)) + if (LabelUtils.HasLabel(issueEventPayload.Issue.Labels, TriageLabelConstants.NoRecentActivity)) { - gitHubEventClient.RemoveLabel(LabelConstants.NoRecentActivity); + gitHubEventClient.RemoveLabel(TriageLabelConstants.NoRecentActivity); } // The comment is always created string issueComment = $"Hi @{issueEventPayload.Issue.User.Login}. Thank you for opening this issue and giving us the opportunity to assist. We believe that this has been addressed. If you feel that further discussion is needed, please add a comment with the text \"/unresolve\" to remove the \"issue-addressed\" label and continue the conversation."; @@ -590,15 +629,15 @@ public static void IssueAddressedReset(GitHubEventClient gitHubEventClient, Issu if (issueEventPayload.Action == ActionConstants.Labeled) { if (issueEventPayload.Issue.State == ItemState.Open && - LabelUtils.HasLabel(issueEventPayload.Issue.Labels, LabelConstants.IssueAddressed)) + LabelUtils.HasLabel(issueEventPayload.Issue.Labels, TriageLabelConstants.IssueAddressed)) { - if (issueEventPayload.Label.Name == LabelConstants.NeedsTeamAttention || - issueEventPayload.Label.Name == LabelConstants.NeedsAuthorFeedback || - issueEventPayload.Label.Name == LabelConstants.ServiceAttention || - issueEventPayload.Label.Name == LabelConstants.NeedsTriage || - issueEventPayload.Label.Name == LabelConstants.NeedsTeamTriage) + if (issueEventPayload.Label.Name == TriageLabelConstants.NeedsTeamAttention || + issueEventPayload.Label.Name == TriageLabelConstants.NeedsAuthorFeedback || + issueEventPayload.Label.Name == TriageLabelConstants.ServiceAttention || + issueEventPayload.Label.Name == TriageLabelConstants.NeedsTriage || + issueEventPayload.Label.Name == TriageLabelConstants.NeedsTeamTriage) { - gitHubEventClient.RemoveLabel(LabelConstants.IssueAddressed); + gitHubEventClient.RemoveLabel(TriageLabelConstants.IssueAddressed); } } } diff --git a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/EventProcessing/PullRequestCommentProcessing.cs b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/EventProcessing/PullRequestCommentProcessing.cs index 8c2023274cb..a0a02c40e8f 100644 --- a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/EventProcessing/PullRequestCommentProcessing.cs +++ b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/EventProcessing/PullRequestCommentProcessing.cs @@ -52,7 +52,7 @@ public static async Task ResetPullRequestActivity(GitHubEventClient gitHubEventC if (gitHubEventClient.RulesConfiguration.RuleEnabled(RulesConstants.ResetPullRequestActivity)) { if (prCommentPayload.Sender.Type != AccountType.Bot && - LabelUtils.HasLabel(prCommentPayload.Issue.Labels, LabelConstants.NoRecentActivity)) + LabelUtils.HasLabel(prCommentPayload.Issue.Labels, TriageLabelConstants.NoRecentActivity)) { if (prCommentPayload.Action == ActionConstants.Created && prCommentPayload.Issue.State == ItemState.Open && @@ -80,7 +80,7 @@ public static async Task ResetPullRequestActivity(GitHubEventClient gitHubEventC if (removeLabel) { - gitHubEventClient.RemoveLabel(LabelConstants.NoRecentActivity); + gitHubEventClient.RemoveLabel(TriageLabelConstants.NoRecentActivity); } } } @@ -111,7 +111,7 @@ public static async Task ReopenPullRequest(GitHubEventClient gitHubEventClient, if (prCommentPayload.Action == ActionConstants.Created) { if (prCommentPayload.Issue.State == ItemState.Closed && - LabelUtils.HasLabel(prCommentPayload.Issue.Labels, LabelConstants.NoRecentActivity) && + LabelUtils.HasLabel(prCommentPayload.Issue.Labels, TriageLabelConstants.NoRecentActivity) && CommentUtils.CommentContainsText(prCommentPayload.Comment.Body, CommentConstants.Reopen)) { bool reOpen = false; @@ -130,7 +130,7 @@ public static async Task ReopenPullRequest(GitHubEventClient gitHubEventClient, if (reOpen) { gitHubEventClient.SetIssueState(prCommentPayload.Issue, ItemState.Open); - gitHubEventClient.RemoveLabel(LabelConstants.NoRecentActivity); + gitHubEventClient.RemoveLabel(TriageLabelConstants.NoRecentActivity); } else { diff --git a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/EventProcessing/PullRequestProcessing.cs b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/EventProcessing/PullRequestProcessing.cs index 8279a95d340..19ebae14786 100644 --- a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/EventProcessing/PullRequestProcessing.cs +++ b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/EventProcessing/PullRequestProcessing.cs @@ -66,8 +66,8 @@ public static async Task PullRequestTriage(GitHubEventClient gitHubEventClient, bool hasAdminOrWritePermission = await gitHubEventClient.DoesUserHaveAdminOrWritePermission(prEventPayload.Repository.Id, prEventPayload.PullRequest.User.Login); if (!hasAdminOrWritePermission) { - gitHubEventClient.AddLabel(LabelConstants.CustomerReported); - gitHubEventClient.AddLabel(LabelConstants.CommunityContribution); + gitHubEventClient.AddLabel(TriageLabelConstants.CustomerReported); + gitHubEventClient.AddLabel(TriageLabelConstants.CommunityContribution); string prComment = $"Thank you for your contribution @{prEventPayload.PullRequest.User.Login}! We will review the pull request and get back to you soon."; gitHubEventClient.CreateComment(prEventPayload.Repository.Id, prEventPayload.PullRequest.Number, prComment); } @@ -110,7 +110,7 @@ public static void ResetPullRequestActivity(GitHubEventClient gitHubEventClient, // 1. The sender is not a bot. // 2. The Pull request has "no-recent-activity" label if (prEventPayload.Sender.Type != AccountType.Bot && - LabelUtils.HasLabel(prEventPayload.PullRequest.Labels, LabelConstants.NoRecentActivity)) + LabelUtils.HasLabel(prEventPayload.PullRequest.Labels, TriageLabelConstants.NoRecentActivity)) { bool removeLabel = false; // Pull request conditions AND the pull request needs to be in an opened state @@ -129,7 +129,7 @@ public static void ResetPullRequestActivity(GitHubEventClient gitHubEventClient, } if (removeLabel) { - gitHubEventClient.RemoveLabel(LabelConstants.NoRecentActivity); + gitHubEventClient.RemoveLabel(TriageLabelConstants.NoRecentActivity); } } } diff --git a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/EventProcessing/ScheduledEventProcessing.cs b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/EventProcessing/ScheduledEventProcessing.cs index 4fea7e373ac..50105043d96 100644 --- a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/EventProcessing/ScheduledEventProcessing.cs +++ b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/EventProcessing/ScheduledEventProcessing.cs @@ -103,7 +103,7 @@ public static async Task CloseAddressedIssues(GitHubEventClient gitHubEventClien List includeLabels = new List { - LabelConstants.IssueAddressed + TriageLabelConstants.IssueAddressed }; SearchIssuesRequest request = gitHubEventClient.CreateSearchRequest(scheduledEventPayload.Repository.Owner.Login, scheduledEventPayload.Repository.Name, @@ -182,8 +182,8 @@ public static async Task CloseStaleIssues(GitHubEventClient gitHubEventClient, S List includeLabels = new List { - LabelConstants.NeedsAuthorFeedback, - LabelConstants.NoRecentActivity + TriageLabelConstants.NeedsAuthorFeedback, + TriageLabelConstants.NoRecentActivity }; SearchIssuesRequest request = gitHubEventClient.CreateSearchRequest(scheduledEventPayload.Repository.Owner.Login, scheduledEventPayload.Repository.Name, @@ -258,7 +258,7 @@ public static async Task CloseStalePullRequests(GitHubEventClient gitHubEventCli List includeLabels = new List { - LabelConstants.NoRecentActivity + TriageLabelConstants.NoRecentActivity }; SearchIssuesRequest request = gitHubEventClient.CreateSearchRequest(scheduledEventPayload.Repository.Owner.Login, scheduledEventPayload.Repository.Name, @@ -337,7 +337,7 @@ public static async Task IdentifyStalePullRequests(GitHubEventClient gitHubEvent List excludeLabels = new List { - LabelConstants.NoRecentActivity + TriageLabelConstants.NoRecentActivity }; SearchIssuesRequest request = gitHubEventClient.CreateSearchRequest(scheduledEventPayload.Repository.Owner.Login, scheduledEventPayload.Repository.Name, @@ -367,7 +367,7 @@ public static async Task IdentifyStalePullRequests(GitHubEventClient gitHubEvent { Issue issue = result.Items[iCounter++]; IssueUpdate issueUpdate = gitHubEventClient.GetIssueUpdate(issue, false); - issueUpdate.AddLabel(LabelConstants.NoRecentActivity); + issueUpdate.AddLabel(TriageLabelConstants.NoRecentActivity); gitHubEventClient.AddToIssueUpdateList(scheduledEventPayload.Repository.Id, issue.Number, issueUpdate); @@ -418,11 +418,11 @@ public static async Task IdentifyStaleIssues(GitHubEventClient gitHubEventClient List includeLabels = new List { - LabelConstants.NeedsAuthorFeedback + TriageLabelConstants.NeedsAuthorFeedback }; List excludeLabels = new List { - LabelConstants.NoRecentActivity + TriageLabelConstants.NoRecentActivity }; SearchIssuesRequest request = gitHubEventClient.CreateSearchRequest(scheduledEventPayload.Repository.Owner.Login, scheduledEventPayload.Repository.Name, @@ -452,7 +452,7 @@ public static async Task IdentifyStaleIssues(GitHubEventClient gitHubEventClient { Issue issue = result.Items[iCounter++]; IssueUpdate issueUpdate = gitHubEventClient.GetIssueUpdate(issue, false); - issueUpdate.AddLabel(LabelConstants.NoRecentActivity); + issueUpdate.AddLabel(TriageLabelConstants.NoRecentActivity); gitHubEventClient.AddToIssueUpdateList(scheduledEventPayload.Repository.Id, issue.Number, issueUpdate); diff --git a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/Utils/CodeOwnerUtils.cs b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/Utils/CodeOwnerUtils.cs index 1991c27e11f..426aae40e65 100644 --- a/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/Utils/CodeOwnerUtils.cs +++ b/tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/Utils/CodeOwnerUtils.cs @@ -7,6 +7,7 @@ using Azure.Sdk.Tools.GitHubEventProcessor.Constants; using Octokit; using Azure.Sdk.Tools.CodeownersUtils.Utils; +using System.Reflection; namespace Azure.Sdk.Tools.GitHubEventProcessor.Utils { @@ -103,83 +104,44 @@ public static List GetPRAutoLabelsForFilePaths(IReadOnlyList /// The list of Octokit.Label - /// The string which contains a unique list of individuals/teams with the names formatted to @mention in github - public static List GetServiceOwnersForServiceLabels(IReadOnlyList