in tools/github-event-processor/Azure.Sdk.Tools.GitHubEventProcessor/EventProcessing/IssueProcessing.cs [97:280]
public static async Task InitialIssueTriage(GitHubEventClient gitHubEventClient, IssueEventGitHubPayload issueEventPayload)
{
if (gitHubEventClient.RulesConfiguration.RuleEnabled(RulesConstants.InitialIssueTriage))
{
if (issueEventPayload.Action == ActionConstants.Opened)
{
// 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 isCustomerReported = false;
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);
isCustomerReported = true;
}
}
// If there are no labels and no assignees
if ((issueEventPayload.Issue.Labels.Count == 0) && (issueEventPayload.Issue.Assignee == null))
{
// Query AI Triage and disable Answers if this is not a customer reported issue.
IssueTriageResponse triageOutput = await gitHubEventClient.QueryAIIssueTriageService(
issueEventPayload,
true,
!isCustomerReported);
if (triageOutput.Labels.Any())
{
// If labels were predicted, add them to the issue
foreach (string label in triageOutput.Labels)
{
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(triageOutput.Labels);
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(",", triageOutput.Labels)}, 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(",", triageOutput.Labels)} but cannot be assigned as an issue owner in this repository.");
}
}
}
// If the issue had a valid assignee and only labels provided add the comment
// Also safegaurding against empty answer, this comment should be made given an invalid Answer.
if (hasValidAssignee && (string.IsNullOrEmpty(triageOutput.AnswerType) || string.IsNullOrEmpty(triageOutput.Answer)))
{
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(",", triageOutput.Labels)} 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,
triageOutput.Labels);
}
// 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 and it is not customer reported.
if (addNeedsTeamAttention && !isCustomerReported)
{
gitHubEventClient.AddLabel(TriageLabelConstants.NeedsTeamAttention);
}
// Making sure the Answer is valid
if(!string.IsNullOrEmpty(triageOutput.Answer))
{
// If answer is a suggestions/solution add the comment.
if(triageOutput.AnswerType == "suggestion")
{
gitHubEventClient.CreateComment(issueEventPayload.Repository.Id,
issueEventPayload.Issue.Number,
triageOutput.Answer);
}
// If answer is a solution add the issue-addressed label
// to close out the issue.
if(triageOutput.AnswerType == "solution")
{
gitHubEventClient.CreateComment(issueEventPayload.Repository.Id,
issueEventPayload.Issue.Number,
triageOutput.Answer);
gitHubEventClient.AddLabel(TriageLabelConstants.IssueAddressed);
}
}
}
// If there are no labels predicted add NeedsTriage to the issue
else
{
gitHubEventClient.AddLabel(TriageLabelConstants.NeedsTriage);
}
}
}
}
}