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); }
internal static Result PostCheckinStage( IRestApi restApi, Branch branch, MergeReport mergeReport, string taskNumber, string[] destinationBranches, MergeToOperations.CheckinResult mergesToCheckins, MultilinerBotConfiguration botConfig, string codeReviewsStorageFile) { if (!HasToRunPlanAfterTaskMerged(botConfig.CI)) { string noCIMessage = "No Continuous Integration Plug was set for this mergebot. Therefore, no " + "build actions for task " + taskNumber + " will be performed."; mLog.Info(noCIMessage); return(Result.Ok); } if (mergesToCheckins == null || mergesToCheckins.ChangesetsByTargetBranch == null || mergesToCheckins.ChangesetsByTargetBranch.Count == 0) { string noChangesetsErrorMessage = string.Format( "Something wrong happened. There are no merge-to changesets to build after " + "merging branch [{0}] to its destination branches.", branch.FullName); mLog.Info(noChangesetsErrorMessage); Notifier.NotifyTaskStatus( restApi, branch.Owner, noChangesetsErrorMessage, botConfig.Notifiers); return(Result.Failed); } string startTestingMessage = string.Format( "Testing branch [{0}] after being merged in the following destination branches: [{1}].", branch.FullName, string.Join(", ", mergesToCheckins.ChangesetsByTargetBranch.Keys)); mLog.Info(startTestingMessage); Notifier.NotifyTaskStatus( restApi, branch.Owner, startTestingMessage, botConfig.Notifiers); int iniTime = Environment.TickCount; BuildOperations.Result result = BuildOperations.TryBuildTask( restApi, branch, mergeReport, taskNumber, destinationBranches, mergesToCheckins.ChangesetsByTargetBranch, Messages.BuildProperties.StageValues.POST_CHECKIN, botConfig); BuildMergeReport.AddBuildTimeProperty( mergeReport, Environment.TickCount - iniTime); if (result.AreAllSuccessful) { BuildMergeReport.AddSucceededBuildProperty( mergeReport, botConfig.CI.PlanAfterCheckin); string notifyOKMesage = string.Format( "Build successful after merging branch [{0}] " + "to the following destination branches: [{1}].", branch.FullName, string.Join(", ", mergesToCheckins.ChangesetsByTargetBranch.Keys)); Notifier.NotifyTaskStatus( restApi, branch.Owner, notifyOKMesage, botConfig.Notifiers); return(Result.Ok); } string errorMessage = string.Join(Environment.NewLine, result.ErrorMessages); BuildMergeReport.AddFailedBuildProperty( mergeReport, botConfig.CI.PlanAfterCheckin, errorMessage); Notifier.NotifyTaskStatus( restApi, branch.Owner, errorMessage, botConfig.Notifiers); return(Result.Failed); }
internal static bool PreCheckinStage( IRestApi restApi, Branch branch, MergeReport mergeReport, string taskNumber, string[] destinationBranches, MergeToOperations.ShelveResult mergesToShelves, MultilinerBotConfiguration botConfig, string codeReviewsStorageFile) { if (botConfig.CI == null) { string noCIMessage = "No Continuous Integration Plug was set for this mergebot. Therefore, no " + "build actions for task " + taskNumber + " will be performed."; mLog.Info(noCIMessage); Notifier.NotifyTaskStatus( restApi, branch.Owner, noCIMessage, botConfig.Notifiers); return(true); } if (mergesToShelves == null || mergesToShelves.ShelvesByTargetBranch == null || mergesToShelves.ShelvesByTargetBranch.Count == 0) { string noShelvesErrorMessage = "Something wrong happened. There are no merge-to shelves to build task " + taskNumber; mLog.Info(noShelvesErrorMessage); Notifier.NotifyTaskStatus( restApi, branch.Owner, noShelvesErrorMessage, botConfig.Notifiers); ChangeTaskStatus.SetTaskAsFailed( restApi, branch, taskNumber, botConfig, codeReviewsStorageFile); return(false); } string startTestingMessage = string.Format( "Testing branch [{0}] before being merged in the following destination branches: [{1}].", branch.FullName, string.Join(", ", mergesToShelves.ShelvesByTargetBranch.Keys)); mLog.Info(startTestingMessage); ChangeTaskStatus.SetTaskAsTesting(restApi, branch, taskNumber, botConfig); Notifier.NotifyTaskStatus( restApi, branch.Owner, startTestingMessage, botConfig.Notifiers); int iniTime = Environment.TickCount; BuildOperations.Result result = BuildOperations.TryBuildTask( restApi, branch, mergeReport, taskNumber, destinationBranches, mergesToShelves.ShelvesByTargetBranch, Messages.BuildProperties.StageValues.PRE_CHECKIN, botConfig); BuildMergeReport.AddBuildTimeProperty( mergeReport, Environment.TickCount - iniTime); if (result.AreAllSuccessful) { BuildMergeReport.AddSucceededBuildProperty( mergeReport, botConfig.CI.PlanBranch); return(true); } string errorMessage = string.Join(Environment.NewLine, result.ErrorMessages); BuildMergeReport.AddFailedBuildProperty( mergeReport, botConfig.CI.PlanBranch, errorMessage); ChangeTaskStatus.SetTaskAsFailed( restApi, branch, taskNumber, botConfig, codeReviewsStorageFile); Notifier.NotifyTaskStatus( restApi, branch.Owner, errorMessage, botConfig.Notifiers); return(false); }
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); }