public async Task PullRequestBreakingChangeReview()

in tools/sdk-ai-bots/AzureSdkQaBot/GithubPrActions.cs [248:372]


        public async Task<bool> PullRequestBreakingChangeReview([ActionTurnContext] ITurnContext turnContext, [ActionTurnState] AppState turnState, [ActionEntities] Dictionary<string, object> entities)
        {
            if (turnContext == null)
            {
                throw new ArgumentNullException(nameof(turnContext));
            }

            if (turnState == null)
            {
                throw new ArgumentNullException(nameof(turnState));
            }

            string prLink = (string)entities["prLink"];
            if (string.IsNullOrEmpty(prLink) || !prLink.Contains("https://"))
            {
                await _questionAnsweringActions.QuestionAnswering(turnContext, turnState);
                return false;
            }

            // redact query to less than 60 characters
            string query = turnContext.Activity.Text;
            if (query.Length > 60)
            {
                query = turnContext.Activity.Text.Substring(0, 57) + "...";
            }
            this._logger.LogInformation($"PrBreakingChangeReview: PR link:{prLink}. Query: {query}");
            (string org, string repo, int prNum) = GetPrInfoFromPrLink(prLink);
            string reply = "";
            string action = "";

            // Get pull request info
            if (prNum != 0)
            {
                (bool isPrMerged, reply) = await IsPrMerged(org, repo, prNum);
                if (reply == Constants.Message_Error_Null_PR)
                {
                    reply += $" {prLink}";
                }
                else if (!isPrMerged)
                {
                    IReadOnlyList<Label> labels = await GetPrLabels(org, repo, prNum);
                    bool isMgmtPlane = false;
                    if (labels.Any(x => x.Name == Constants.Label_ResourceManager))
                    {
                        isMgmtPlane = true;
                    }
                    // check breaking change
                    (bool completeBcReview, reply, action) = CheckBreakingChangeReview(labels);
                    if (completeBcReview || reply == "")
                    {
                        // sdk breaking change review
                        if (!labels.Any(x => x.Name == Constants.Label_SDKBreakingChange_Go || x.Name == Constants.Label_SDKBreakingChange_Python || x.Name == Constants.Label_SDKBreakingChange_PythonTrack2 || x.Name == Constants.Label_SDKBreakingChange_JavaScript))
                        {
                            reply = Constants.Message_SDKBreakingChangeReview_NotNeeded;
                        }
                        else if ((labels.Any(x => x.Name == Constants.Label_SDKBreakingChange_Go) && !labels.Any(x => x.Name == Constants.Label_SDKBreakingChange_Go_Approval))
                                    || (labels.Any(x => x.Name == Constants.Label_SDKBreakingChange_Python || x.Name == Constants.Label_SDKBreakingChange_PythonTrack2) && !labels.Any(x => x.Name == Constants.Label_SDKBreakingChange_Python_Approval))
                                    || (labels.Any(x => x.Name == Constants.Label_SDKBreakingChange_JavaScript) && !labels.Any(x => x.Name == Constants.Label_SDKBreakingChange_JavaScript_Approval)))
                        {
                            bool completeArmReview = false;
                            if (isMgmtPlane)
                            {
                                (completeArmReview, reply, action) = CheckArmReview(labels);
                            }
                            if (isMgmtPlane && !completeArmReview && reply != "")
                            {
                                // arm review isn't finished
                                reply = Constants.Message_ArmReview_NotFinished_BeforeSdkBreakingChangeReview;
                                action = Constants.Action_ArmReview_NotFinished_BeforeSdkBreakingChangeReview;
                            }
                            // arm review completes or not needed
                            else if (labels.Any(x => x.Name == Constants.Label_SDKBreakingChange_Go) && !labels.Any(x => x.Name == Constants.Label_SDKBreakingChange_Go_Approval))
                            {
                                reply = Constants.Message_SDKBreakingChangeGo_NotFinished;
                                action = Constants.Action_SDKBreakingChangeGo_NotFinished;
                            }
                            else if (labels.Any(x => x.Name == Constants.Label_SDKBreakingChange_Python) && !labels.Any(x => x.Name == Constants.Label_SDKBreakingChange_Python_Approval))
                            {
                                reply = Constants.Message_SDKBreakingChangePython_NotFinished;
                                action = Constants.Action_SDKBreakingChangePython_NotFinished;
                            }
                            else if (labels.Any(x => x.Name == Constants.Label_SDKBreakingChange_JavaScript) && !labels.Any(x => x.Name == Constants.Label_SDKBreakingChange_JavaScript_Approval))
                            {
                                reply = Constants.Message_SDKBreakingChangeJavaScript_NotFinished;
                                action = Constants.Action_SDKBreakingChangeJavaScript_NotFinished;
                            }
                        }
                        else
                        {
                            reply = Constants.Message_BreakingChangeReview_Finished;
                            action = Constants.Action_BreakingChangeReview_Finished;
                        }
                    }
                }
                // add support message for tool failures
                reply = AddSupportMessageForTools(turnContext, reply);
            }

            // call QA function
            (string additionalAnswer, List<string>? relevancies) = await _questionAnsweringActions.QuestionAnsweringHandler(turnContext, turnState);

            // get the relevance links based on user input or PR labels to differenciate the mgmt plane and data plane
            IList<string> references = await GetRelevanceLinks(turnContext, org, repo, prNum);
            Attachment card;
            if (additionalAnswer.StartsWith("Sorry, I do not know"))
            {
                additionalAnswer = "";
                relevancies = null;
            }
            card = await CardBuilder.NewPRAndQAAttachment(query, reply, action, additionalAnswer, references, relevancies, CancellationToken.None);

            try
            {
                await turnContext.SendActivityAsync(MessageFactory.Attachment(card), CancellationToken.None);
            }
            catch (Exception ex)
            {
                await turnContext.TraceActivityAsync("SendActivityError", ex, "The bot received an error when send message to Teams.");
                Console.WriteLine("Error:" + ex);
                this._logger.LogError($"PrBreakingChangeReview: PR link:{prLink}. Query:{query}. Error: {ex}");
            }

            // End the current chain
            return false;
        }