Beispiel #1
0
        static BuildProperties CreateBuildProperties(
            IRestApi restApi,
            string taskNumber,
            string branchName,
            string labelName,
            string buildStagePreCiOrPostCi,
            string destinationBranch,
            MultilinerBotConfiguration botConfig)
        {
            int branchHeadChangesetId = MultilinerMergebotApi.GetBranchHead(
                restApi, botConfig.Repository, branchName);
            ChangesetModel branchHeadChangeset = MultilinerMergebotApi.GetChangeset(
                restApi, botConfig.Repository, branchHeadChangesetId);

            int trunkHeadChangesetId = MultilinerMergebotApi.GetBranchHead(
                restApi, botConfig.Repository, destinationBranch);
            ChangesetModel trunkHeadChangeset = MultilinerMergebotApi.GetChangeset(
                restApi, botConfig.Repository, trunkHeadChangesetId);

            return(new BuildProperties
            {
                BranchName = branchName,
                TaskNumber = taskNumber,
                BranchHead = branchHeadChangeset.ChangesetId.ToString(),
                BranchHeadGuid = branchHeadChangeset.Guid.ToString(),
                ChangesetOwner = branchHeadChangeset.Owner,
                TrunkBranchName = destinationBranch,
                TrunkHead = trunkHeadChangeset.ChangesetId.ToString(),
                TrunkHeadGuid = trunkHeadChangeset.Guid.ToString(),
                RepSpec = string.Format("{0}@{1}", botConfig.Repository, botConfig.Server),
                LabelName = labelName,
                Stage = buildStagePreCiOrPostCi
            });
        }
        internal static ShelveResult TryMergeToShelves(
            IRestApi restApi,
            Branch branch,
            string[] destinationBranches,
            MergeReport mergeReport,
            string taskTitle,
            string botName)
        {
            ShelveResult result = new ShelveResult();

            foreach (string destinationBranch in destinationBranches)
            {
                MergeToResponse mergeToResult = MultilinerMergebotApi.MergeBranchTo(
                    restApi,
                    branch.Repository,
                    branch.FullName,
                    destinationBranch,
                    GetComment(branch.FullName, destinationBranch, taskTitle, botName),
                    MultilinerMergebotApi.MergeToOptions.CreateShelve);

                result.MergeStatusByTargetBranch[destinationBranch] = mergeToResult.Status;

                if (mergeToResult.Status == MergeToResultStatus.MergeNotNeeded)
                {
                    string warningMessage = string.Format(
                        "Branch [{0}] was already merged to [{1}] (No merge needed).",
                        branch.FullName,
                        destinationBranch);

                    result.MergesNotNeededMessages.Add(warningMessage);
                    continue;
                }

                if (IsFailedMergeTo(mergeToResult))
                {
                    string errorMsg = string.Format(
                        "Can't merge branch [{0}] to [{1}]. Reason: {2}.",
                        branch.FullName,
                        destinationBranch,
                        mergeToResult.Message);

                    result.ErrorMessages.Add(errorMsg);

                    BuildMergeReport.AddFailedMergeProperty(
                        mergeReport, mergeToResult.Status, mergeToResult.Message);

                    continue;
                }

                result.ShelvesByTargetBranch[destinationBranch] = mergeToResult.ChangesetNumber;
                BuildMergeReport.AddSucceededMergeProperty(mergeReport, mergeToResult.Status);
            }
            return(result);
        }
        static string[] GetMergeToDestinationBranches(
            IRestApi restApi,
            Branch branch,
            string mergeToBranchesAttrName)
        {
            string rawAttrValue = string.Empty;

            try
            {
                rawAttrValue = MultilinerMergebotApi.GetBranchAttribute(
                    restApi, branch.Repository, branch.FullName, mergeToBranchesAttrName);
            }
            catch (Exception e)
            {
                mLog.WarnFormat(
                    "Unable to retrieve attribute [{0}] value from branch [{1}]. Error: {2}",
                    mergeToBranchesAttrName, branch.FullName, e.Message);
                return(new string[] { });
            }

            if (string.IsNullOrWhiteSpace(rawAttrValue))
            {
                return new string[] { }
            }
            ;

            List <string> destinationBranchesList = new List <string>();

            string[] rawSplittedDestinationBranches = rawAttrValue.Split(
                new char[] { ';', ',' },
                StringSplitOptions.RemoveEmptyEntries);

            string cleanDstBranchName;

            foreach (string rawSplittedDestinationBranch in rawSplittedDestinationBranches)
            {
                cleanDstBranchName = rawSplittedDestinationBranch.Trim();

                if (string.IsNullOrWhiteSpace(cleanDstBranchName))
                {
                    continue;
                }

                if (destinationBranchesList.Contains(cleanDstBranchName))
                {
                    continue;
                }

                destinationBranchesList.Add(cleanDstBranchName);
            }

            return(destinationBranchesList.ToArray());
        }
        static bool IsMergeAllowed(IRestApi restApi, Branch branch, string destinationBranch)
        {
            if (MultilinerMergebotApi.IsMergeAllowed(
                    restApi, branch.Repository, branch.FullName, destinationBranch))
            {
                return(true);
            }

            mLog.WarnFormat(
                "Branch [{0}] is not yet ready to be merged into [{1}] " +
                "Jumping to next branch in the queue...",
                branch.FullName,
                destinationBranch);

            return(false);
        }
Beispiel #5
0
        internal static bool ExistsAttributeName(
            IRestApi restApi,
            string repository,
            string attributeName)
        {
            string query = string.Format("attributetype where name='{0}' ", attributeName);

            JArray findResult = MultilinerMergebotApi.Find(
                restApi,
                repository,
                query,
                DATE_FORMAT,
                "retrieve the list of attributes named " + attributeName,
                new string[] { "name" });

            return(findResult != null && findResult.Count > 0);
        }
        internal static void SafeDeleteShelves(
            IRestApi restApi,
            string repository,
            string[] destinationBranches,
            ShelveResult mergesToShelvesResult)
        {
            if (destinationBranches == null ||
                destinationBranches.Length == 0 ||
                mergesToShelvesResult == null ||
                mergesToShelvesResult.ShelvesByTargetBranch == null)
            {
                return;
            }

            int shelveId = -1;

            foreach (string destinationBranch in destinationBranches)
            {
                if (!mergesToShelvesResult.ShelvesByTargetBranch.ContainsKey(destinationBranch))
                {
                    continue;
                }

                shelveId = mergesToShelvesResult.ShelvesByTargetBranch[destinationBranch];

                if (shelveId == -1)
                {
                    continue;
                }

                try
                {
                    MultilinerMergebotApi.DeleteShelve(restApi, repository, shelveId);
                }
                catch (Exception ex)
                {
                    mLog.ErrorFormat(
                        "Unable to delete shelve {0} on repository '{1}': {2}",
                        shelveId, repository, ex.Message);

                    mLog.DebugFormat(
                        "StackTrace:{0}{1}",
                        Environment.NewLine, ex.StackTrace);
                }
            }
        }
        internal static Result SetTaskAsFailed(
            IRestApi restApi,
            Branch branch,
            string taskNumber,
            MultilinerBotConfiguration botConfig,
            string codeReviewsStorageFile)
        {
            Result result = new Result();

            result.IsSuccessful = true;

            try
            {
                if (botConfig.Plastic.IsApprovedCodeReviewFilterEnabled)
                {
                    SetBranchReviewsAsPending(
                        restApi, branch.Repository, branch.Id, codeReviewsStorageFile);
                }

                MultilinerMergebotApi.ChangeBranchAttribute(
                    restApi, branch.Repository, branch.FullName,
                    botConfig.Plastic.StatusAttribute.Name,
                    botConfig.Plastic.StatusAttribute.FailedValue);

                if (taskNumber != null && botConfig.Issues != null)
                {
                    MultilinerMergebotApi.Issues.SetIssueField(
                        restApi, botConfig.Issues.Plug, botConfig.Issues.ProjectKey,
                        taskNumber, botConfig.Issues.StatusField.Name,
                        botConfig.Issues.StatusField.FailedValue);
                }
            }
            catch (Exception ex)
            {
                result.IsSuccessful = false;
                result.ErrorMessage = BuildExceptionErrorMsg(
                    branch.FullName,
                    botConfig.Plastic.StatusAttribute.FailedValue,
                    ex.Message);
            }

            return(result);
        }
Beispiel #8
0
        internal static string GetBranchName(
            IRestApi restApi, string repository, string branchId)
        {
            string query = string.Format("branch where id={0}", branchId);

            JArray findResult = MultilinerMergebotApi.Find(
                restApi,
                repository,
                query,
                DATE_FORMAT,
                "retrieve a single branch by ID",
                new string[] { "name" });

            if (findResult.Count == 0)
            {
                return(string.Empty);
            }

            return(GetStringValue((JObject)findResult[0], "name"));
        }
        static bool ExistsBranch(IRestApi restApi, string destinationBranch, string repository)
        {
            BranchModel destinationBranchModel = null;

            try
            {
                destinationBranchModel = MultilinerMergebotApi.GetBranch(
                    restApi, repository, destinationBranch);

                return(!string.IsNullOrWhiteSpace(destinationBranchModel.Name));
            }
            catch (Exception e)
            {
                mLog.WarnFormat(
                    "Unable to locate branch name [{0}] in repository [{1}]. Error: {2}",
                    destinationBranch, repository, e.Message);

                return(false);
            }
        }
Beispiel #10
0
        internal static List <Branch> FindResolvedBranches(
            IRestApi restApi,
            string repository,
            string prefix,
            string statusAttributeName,
            string resolvedStatusAttributeValue)
        {
            string query = string.Format(
                "branch where ( name like '{0}%' or name like '{1}%' or name like '{2}%' ) " +
                "and date > '{3}' " +
                "and attribute='{4}' and ( attrvalue='{5}' or attrvalue='{6}' or attrvalue='{7}') ",
                prefix,
                prefix.ToLowerInvariant(),
                prefix.ToUpperInvariant(),
                DateTime.Now.AddYears(-1).ToString(DATE_FORMAT),
                statusAttributeName,
                resolvedStatusAttributeValue,
                resolvedStatusAttributeValue.ToLowerInvariant(),
                resolvedStatusAttributeValue.ToUpperInvariant());

            JArray findResult = MultilinerMergebotApi.Find(
                restApi,
                repository,
                query,
                DATE_FORMAT,
                "retrieve the list of branches to process",
                new string[] { "id", "name", "owner", "comment" });

            List <Branch> result = new List <Branch>();

            foreach (JObject obj in findResult)
            {
                result.Add(new Branch(
                               repository,
                               GetStringValue(obj, "id"),
                               GetStringValue(obj, "name"),
                               GetStringValue(obj, "owner"),
                               GetStringValue(obj, "comment")));
            }
            return(result);
        }
        internal static Result SetTaskAsTesting(
            IRestApi restApi,
            Branch branch,
            string taskNumber,
            MultilinerBotConfiguration botConfig)
        {
            Result result = new Result();

            result.IsSuccessful = true;

            try
            {
                if (!string.IsNullOrEmpty(botConfig.Plastic.StatusAttribute.TestingValue))
                {
                    MultilinerMergebotApi.ChangeBranchAttribute(
                        restApi, branch.Repository, branch.FullName,
                        botConfig.Plastic.StatusAttribute.Name,
                        botConfig.Plastic.StatusAttribute.TestingValue);
                }

                if (taskNumber != null && botConfig.Issues != null &&
                    !string.IsNullOrEmpty(botConfig.Issues.StatusField.TestingValue))
                {
                    MultilinerMergebotApi.Issues.SetIssueField(
                        restApi, botConfig.Issues.Plug, botConfig.Issues.ProjectKey,
                        taskNumber, botConfig.Issues.StatusField.Name,
                        botConfig.Issues.StatusField.TestingValue);
                }
            }
            catch (Exception ex)
            {
                result.IsSuccessful = false;
                result.ErrorMessage = BuildExceptionErrorMsg(
                    branch.FullName,
                    botConfig.Plastic.StatusAttribute.TestingValue,
                    ex.Message);
            }

            return(result);
        }
Beispiel #12
0
        internal static List <BranchWithReview> FindPendingBranchesWithReviews(
            IRestApi restApi,
            string repository,
            string prefix,
            string statusAttributeName,
            string mergedStatusAttributeValue)
        {
            string reviewTypeConditionClause = string.Empty;

            //branches from a year ago matching with prefix with status!=merged (even those without any status set)
            string branchTypeConditionClause = string.Format(
                "( " +
                "    name like '{0}%' or name like '{1}%' or name like '{2}%' " +
                ") " +
                "and " +
                "( " +
                "    date > '{3}' " +
                ") " +
                "and " +
                "( " +
                "    (not attribute='{4}') or " +
                "    (attribute='{4}' and not ( attrvalue='{5}' or attrvalue='{6}' or attrvalue='{7}' )) " +
                ") ",
                prefix,
                prefix.ToUpperInvariant(),
                prefix.ToLowerInvariant(),
                DateTime.Now.AddYears(-1).ToString(DATE_FORMAT),
                statusAttributeName,
                mergedStatusAttributeValue,
                mergedStatusAttributeValue.ToUpperInvariant(),
                mergedStatusAttributeValue.ToLowerInvariant());

            string[] outputFields = new string[]
            { "branchid", "branchname", "branchowner", "branchcomment",
              "reviewid", "reviewtargetid", "reviewstatus", "reviewtitle" };

            JArray findResult = MultilinerMergebotApi.FindBranchesWithReviews(
                restApi,
                repository,
                reviewTypeConditionClause,
                branchTypeConditionClause,
                DATE_FORMAT,
                "retrieve the list of branches with reviews to process",
                outputFields);

            List <BranchWithReview> result = new List <BranchWithReview>();
            Branch branch = null;
            Review review = null;

            foreach (JObject obj in findResult)
            {
                branch = new Branch(
                    repository,
                    GetStringValue(obj, "branchid"),
                    GetStringValue(obj, "branchname"),
                    GetStringValue(obj, "branchowner"),
                    GetStringValue(obj, "branchcomment"));

                review = new Review(
                    repository,
                    GetStringValue(obj, "reviewid"),
                    GetStringValue(obj, "reviewtargetid"),
                    TranslateCodeReviewStatus(GetStringValue(obj, "reviewstatus")),
                    GetStringValue(obj, "reviewtitle"));

                result.Add(new BranchWithReview()
                {
                    Branch = branch,
                    Review = review
                });
            }

            return(result);
        }
        public static Result TryProcessBranch(
            IRestApi restApi,
            Branch branch,
            MultilinerBotConfiguration botConfig,
            string botName,
            string codeReviewsStorageFile)
        {
            string      taskNumber  = null;
            MergeReport mergeReport = null;

            string[] destinationBranches = null;
            MergeToOperations.ShelveResult mergesToShelves = null;
            string notificationMsg = null;

            try
            {
                mLog.InfoFormat("Getting task number of branch {0} ...", branch.FullName);

                taskNumber = GetTaskNumber(branch.FullName, botConfig.BranchPrefix);

                if (!IsTaskReady(
                        restApi,
                        taskNumber,
                        botConfig.Issues,
                        botConfig.Plastic.IsApprovedCodeReviewFilterEnabled,
                        branch.Repository,
                        branch.Id,
                        codeReviewsStorageFile))
                {
                    return(Result.NotReady);
                }

                destinationBranches = GetMergeToDestinationBranches(
                    restApi,
                    branch,
                    botConfig.MergeToBranchesAttrName);

                if (destinationBranches == null || destinationBranches.Length == 0)
                {
                    notificationMsg = string.Format(
                        "The attribute [{0}] of branch [{1}@{2}@{3}] is not properly set. " +
                        "Branch [{1}@{2}@{3}] status will be set as 'failed': [{4}].",
                        botConfig.MergeToBranchesAttrName,
                        branch.FullName,
                        branch.Repository,
                        botConfig.Server,
                        botConfig.Plastic.StatusAttribute.FailedValue);

                    mLog.Warn(notificationMsg);

                    ChangeTaskStatus.SetTaskAsFailed(
                        restApi, branch, taskNumber, botConfig, codeReviewsStorageFile);

                    Notifier.NotifyTaskStatus(
                        restApi, branch.Owner, notificationMsg, botConfig.Notifiers);

                    return(Result.Failed);
                }

                foreach (string destinationBranch in destinationBranches)
                {
                    if (ExistsBranch(restApi, destinationBranch, branch.Repository))
                    {
                        continue;
                    }

                    notificationMsg = string.Format(
                        "The destination branch [{0}@{1}@{2}] specified in attribute [{3}] " +
                        "of branch [{4}@{1}@{2}] does not exist. " +
                        "Branch [{4}@{1}@{2}] status will be set as 'failed': [{5}].",
                        destinationBranch,
                        branch.Repository,
                        botConfig.Server,
                        botConfig.MergeToBranchesAttrName,
                        branch.FullName,
                        botConfig.Plastic.StatusAttribute.FailedValue);

                    mLog.Warn(notificationMsg);

                    ChangeTaskStatus.SetTaskAsFailed(
                        restApi, branch, taskNumber, botConfig, codeReviewsStorageFile);

                    Notifier.NotifyTaskStatus(
                        restApi, branch.Owner, notificationMsg, botConfig.Notifiers);

                    return(Result.Failed);
                }

                foreach (string destinationBranch in destinationBranches)
                {
                    if (IsMergeAllowed(restApi, branch, destinationBranch))
                    {
                        continue;
                    }

                    return(Result.NotReady);
                }

                mLog.InfoFormat("Building the merge report of task {0} ...", taskNumber);

                mergeReport = BuildMergeReport.Build(
                    MultilinerMergebotApi.GetBranch(restApi, branch.Repository, branch.FullName));

                string taskTittle;
                string taskUrl;

                if (GetIssueInfo(
                        restApi,
                        taskNumber,
                        botConfig.Issues,
                        out taskTittle,
                        out taskUrl))
                {
                    BuildMergeReport.AddIssueProperty(mergeReport, taskTittle, taskUrl);
                }

                mLog.InfoFormat("Trying to shelve server-side-merge from [{0}] to [{1}]",
                                branch.FullName, string.Join(", ", destinationBranches));

                mergesToShelves =
                    MergeToOperations.TryMergeToShelves(
                        restApi,
                        branch,
                        destinationBranches,
                        mergeReport,
                        taskTittle,
                        botName);

                if (NoMergesNeeded(mergesToShelves))
                {
                    ChangeTaskStatus.Result chStatResult = ChangeTaskStatus.SetTaskAsMerged(
                        restApi,
                        branch,
                        taskNumber,
                        botConfig,
                        codeReviewsStorageFile);

                    notificationMsg = string.Join(Environment.NewLine, mergesToShelves.MergesNotNeededMessages);

                    if (!string.IsNullOrWhiteSpace(chStatResult.ErrorMessage))
                    {
                        notificationMsg = string.Concat(
                            notificationMsg, Environment.NewLine, chStatResult.ErrorMessage);
                    }

                    Notifier.NotifyTaskStatus(
                        restApi, branch.Owner, notificationMsg, botConfig.Notifiers);

                    return(Result.Failed);
                }

                if (mergesToShelves.ErrorMessages.Count > 0)
                {
                    ChangeTaskStatus.Result chStatResult = ChangeTaskStatus.SetTaskAsFailed(
                        restApi,
                        branch,
                        taskNumber,
                        botConfig,
                        codeReviewsStorageFile);

                    notificationMsg = string.Join(Environment.NewLine, mergesToShelves.ErrorMessages);

                    if (mergesToShelves.MergesNotNeededMessages.Count > 0)
                    {
                        notificationMsg = string.Concat(
                            notificationMsg,
                            Environment.NewLine,
                            string.Join(Environment.NewLine, mergesToShelves.MergesNotNeededMessages));
                    }

                    if (!string.IsNullOrWhiteSpace(chStatResult.ErrorMessage))
                    {
                        notificationMsg = string.Concat(
                            notificationMsg, Environment.NewLine, chStatResult.ErrorMessage);
                    }

                    Notifier.NotifyTaskStatus(
                        restApi, branch.Owner, notificationMsg, botConfig.Notifiers);

                    return(Result.Failed);
                }

                if (mergesToShelves.MergesNotNeededMessages.Count > 0)
                {
                    string alreadyMergedMessage = string.Join(
                        Environment.NewLine + "\t", mergesToShelves.MergesNotNeededMessages);

                    notificationMsg = string.Format(
                        "Branch [{0}] is already merged to some " +
                        "of the specified destination branches in the attribute [{1}]. " +
                        "The {2} mergebot will continue building the " +
                        "merge(s) from branch [{0}] to [{3}].{4}{4}" +
                        "Report of already merged branches:{4}\t{5}",
                        branch.FullName,
                        botConfig.MergeToBranchesAttrName,
                        botName,
                        string.Join(", ", mergesToShelves.ShelvesByTargetBranch.Keys),
                        Environment.NewLine,
                        alreadyMergedMessage);

                    mLog.Info(notificationMsg);

                    Notifier.NotifyTaskStatus(
                        restApi, branch.Owner, notificationMsg, botConfig.Notifiers);
                }

                bool allBuildsOk = Build.PreCheckinStage(
                    restApi,
                    branch,
                    mergeReport,
                    taskNumber,
                    destinationBranches,
                    mergesToShelves,
                    botConfig,
                    codeReviewsStorageFile);

                if (!allBuildsOk)
                {
                    return(Result.Failed);
                }

                MergeToOperations.CheckinResult mergesToCheckins = MergeToOperations.TryApplyShelves(
                    restApi,
                    branch,
                    destinationBranches,
                    mergesToShelves,
                    mergeReport,
                    taskNumber,
                    taskTittle,
                    botName,
                    botConfig,
                    codeReviewsStorageFile);

                //checkin went OK in all target branches
                if (mergesToCheckins.ErrorMessages.Count == 0 &&
                    mergesToCheckins.DestinationNewChangesWarnings.Count == 0)
                {
                    mLog.InfoFormat("Setting branch {0} as 'integrated'...", branch.FullName);
                    ChangeTaskStatus.SetTaskAsMerged(
                        restApi,
                        branch,
                        taskNumber,
                        botConfig,
                        codeReviewsStorageFile);

                    notificationMsg = string.Format(
                        "OK: Branch [{0}] was successfully merged to [{1}]",
                        branch.FullName,
                        string.Join(", ", mergesToShelves.ShelvesByTargetBranch.Keys));

                    Notifier.NotifyTaskStatus(
                        restApi, branch.Owner, notificationMsg, botConfig.Notifiers);

                    return(Build.PostCheckinStage(
                               restApi,
                               branch,
                               mergeReport,
                               taskNumber,
                               destinationBranches,
                               mergesToCheckins,
                               botConfig,
                               codeReviewsStorageFile));
                }

                //some of the checkins went wrong -> we must run the post-ci plan for the successful ones,
                //but force-set as failed the source branch (or requeue if the errors are due to New DstChanges
                if (mergesToCheckins.ErrorMessages.Count > 0)
                {
                    ChangeTaskStatus.Result chStatResult = ChangeTaskStatus.SetTaskAsFailed(
                        restApi,
                        branch,
                        taskNumber,
                        botConfig,
                        codeReviewsStorageFile);

                    string checkinErrorMessage = string.Join(
                        Environment.NewLine + "\t", mergesToCheckins.ErrorMessages);

                    if (mergesToCheckins.DestinationNewChangesWarnings.Count > 0)
                    {
                        string dstChangesErrorMessage = string.Join(
                            Environment.NewLine + "\t", mergesToCheckins.DestinationNewChangesWarnings);

                        checkinErrorMessage = string.Concat(
                            checkinErrorMessage,
                            Environment.NewLine + "\t",
                            dstChangesErrorMessage);
                    }

                    notificationMsg = string.Format(
                        "Failed build. The result of building merges from branch [{0}] to [{1}] went OK, " +
                        "but there were some errors checking-in the resulting shelves:{2}\t{3}{2}{2}{4}",
                        branch.FullName,
                        string.Join(", ", mergesToShelves.ShelvesByTargetBranch.Keys),
                        Environment.NewLine,
                        checkinErrorMessage,
                        string.IsNullOrWhiteSpace(chStatResult.ErrorMessage) ?
                        string.Empty : chStatResult.ErrorMessage);

                    mLog.Warn(notificationMsg);

                    if (mergesToCheckins.ChangesetsByTargetBranch.Count == 0)
                    {
                        Notifier.NotifyTaskStatus(
                            restApi, branch.Owner, notificationMsg, botConfig.Notifiers);

                        return(Result.Failed);
                    }

                    Build.PostCheckinStage(
                        restApi,
                        branch,
                        mergeReport,
                        taskNumber,
                        destinationBranches,
                        mergesToCheckins,
                        botConfig,
                        codeReviewsStorageFile);

                    Notifier.NotifyTaskStatus(
                        restApi, branch.Owner, notificationMsg, botConfig.Notifiers);

                    return(Result.Failed);
                }

                //LAST block -> if (mergesToCheckins.DestinationNewChangesWarnings.Count > 0)
                //Some of the checkins went wrong due to new changeset on at least a destination branch->
                //We must run the post-ci plan for the successful ones,
                //but force requeuing of source branch, so the failed merges to dst branches are re-run
                mLog.InfoFormat("Setting branch {0} as 'resolved' (enqueue) ...", branch.FullName);
                MultilinerMergebotApi.ChangeBranchAttribute(
                    restApi, branch.Repository, branch.FullName,
                    botConfig.Plastic.StatusAttribute.Name,
                    botConfig.Plastic.StatusAttribute.ResolvedValue);

                string dstBranchesNewCsetsMsg = string.Join(
                    Environment.NewLine + "\t", mergesToCheckins.DestinationNewChangesWarnings);

                notificationMsg = string.Format(
                    "Branch [{0}] will be enqueued again, as new changesets appeared in " +
                    "merge destination branches, and thus, the branch needs to be tested again to " +
                    "include those new changesets in the merge. Full report:{1}\t{2}",
                    branch.FullName,
                    Environment.NewLine,
                    dstBranchesNewCsetsMsg);

                mLog.Warn(notificationMsg);

                if (mergesToCheckins.ChangesetsByTargetBranch.Count == 0)
                {
                    Notifier.NotifyTaskStatus(
                        restApi, branch.Owner, notificationMsg, botConfig.Notifiers);

                    return(Result.NotReady);
                }

                Build.PostCheckinStage(
                    restApi,
                    branch,
                    mergeReport,
                    taskNumber,
                    destinationBranches,
                    mergesToCheckins,
                    botConfig,
                    codeReviewsStorageFile);

                Notifier.NotifyTaskStatus(
                    restApi, branch.Owner, notificationMsg, botConfig.Notifiers);

                return(Result.NotReady);
            }
            catch (Exception ex)
            {
                mLog.ErrorFormat(
                    "The attempt to process task {0} failed for branch {1}: {2}",
                    taskNumber, branch.FullName, ex.Message);

                mLog.DebugFormat(
                    "StackTrace:{0}{1}", Environment.NewLine, ex.StackTrace);

                ChangeTaskStatus.SetTaskAsFailed(
                    restApi,
                    branch,
                    taskNumber,
                    botConfig,
                    codeReviewsStorageFile);

                notificationMsg = string.Format(
                    "Can't process branch [{0}] because of an unexpected error: {1}.",
                    branch.FullName,
                    ex.Message);

                Notifier.NotifyTaskStatus(
                    restApi, branch.Owner, notificationMsg, botConfig.Notifiers);

                BuildMergeReport.SetUnexpectedExceptionProperty(mergeReport, ex.Message);

                return(Result.Failed);
            }
            finally
            {
                ReportMerge(restApi, branch.Repository, branch.FullName, botName, mergeReport);

                MergeToOperations.SafeDeleteShelves(
                    restApi, branch.Repository, destinationBranches, mergesToShelves);
            }
        }
        internal static CheckinResult TryApplyShelves(
            IRestApi restApi,
            Branch branch,
            string[] destinationBranches,
            ShelveResult shelves,
            MergeReport mergeReport,
            string taskNumber,
            string taskTitle,
            string botName,
            MultilinerBotConfiguration botConfig,
            string codeReviewsStorageFile)
        {
            CheckinResult result = new CheckinResult();
            int           shelveId;

            foreach (string destinationBranch in destinationBranches)
            {
                if (!shelves.ShelvesByTargetBranch.ContainsKey(destinationBranch))
                {
                    continue;
                }

                shelveId = shelves.ShelvesByTargetBranch[destinationBranch];

                mLog.InfoFormat(
                    "Checking-in shelveset [{0}] from branch [{1}] to [{2}]",
                    shelveId, branch.FullName, destinationBranch);

                MergeToResponse mergeResult = MultilinerMergebotApi.MergeShelveTo(
                    restApi,
                    branch.Repository,
                    shelveId,
                    destinationBranch,
                    GetComment(branch.FullName, destinationBranch, taskTitle, botName),
                    MultilinerMergebotApi.MergeToOptions.EnsureNoDstChanges);

                result.MergeStatusByTargetBranch[destinationBranch] = mergeResult.Status;

                BuildMergeReport.UpdateMergeProperty(mergeReport, mergeResult.Status, mergeResult.ChangesetNumber);

                if (mergeResult.Status == MergeToResultStatus.OK)
                {
                    result.ChangesetsByTargetBranch[destinationBranch] = mergeResult.ChangesetNumber;

                    mLog.InfoFormat(
                        "Checkin: Created changeset [{0}] in branch [{1}]",
                        mergeResult.ChangesetNumber, destinationBranch);

                    continue;
                }

                if (mergeResult.Status == MergeToResultStatus.DestinationChanges)
                {
                    string dstWarnMessage = string.Format(
                        "Can't checkin shelve [{0}], the resulting shelve from merging branch " +
                        "[{1}] to [{2}]. Reason: new changesets appeared in destination branch " +
                        "while mergebot {3} was processing the merge from [{1}] to [{2}].{4}{5}",
                        shelveId,
                        branch.FullName,
                        destinationBranch,
                        botName,
                        Environment.NewLine,
                        mergeResult.Message);

                    // it should checkin the shelve only on the exact parent shelve cset.
                    // if there are new changes in the destination branch enqueue again the task
                    result.DestinationNewChangesWarnings.Add(dstWarnMessage);
                    continue;
                }

                string errorMsg = string.Format(
                    "Can't checkin shelve [{0}], the resulting shelve from merging branch " +
                    "[{1}] to [{2}]. Reason: {3}",
                    shelveId,
                    branch.FullName,
                    destinationBranch,
                    mergeResult.Message);

                result.ErrorMessages.Add(errorMsg);
            }

            return(result);
        }