static BuildProperties CreateBuildProperties( RestApi restApi, string taskNumber, string branchName, string labelName, string buildStagePreCiOrPostCi, TrunkBotConfiguration botConfig) { int branchHeadChangesetId = TrunkMergebotApi.GetBranchHead( restApi, botConfig.Repository, branchName); ChangesetModel branchHeadChangeset = TrunkMergebotApi.GetChangeset( restApi, botConfig.Repository, branchHeadChangesetId); int trunkHeadChangesetId = TrunkMergebotApi.GetBranchHead( restApi, botConfig.Repository, botConfig.TrunkBranch); ChangesetModel trunkHeadChangeset = TrunkMergebotApi.GetChangeset( restApi, botConfig.Repository, trunkHeadChangesetId); return(new BuildProperties { BranchName = branchName, TaskNumber = taskNumber, BranchHead = branchHeadChangeset.ChangesetId.ToString(), BranchHeadGuid = branchHeadChangeset.Guid.ToString(), ChangesetOwner = branchHeadChangeset.Owner, TrunkHead = trunkHeadChangeset.ChangesetId.ToString(), TrunkHeadGuid = trunkHeadChangeset.Guid.ToString(), RepSpec = string.Format("{0}@{1}", botConfig.Repository, botConfig.Server), LabelName = labelName, Stage = buildStagePreCiOrPostCi }); }
static void SafeDeleteShelve( RestApi restApi, string repository, int shelveId) { if (shelveId == -1) { return; } try { TrunkMergebotApi.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 bool TryMergeToShelve( RestApi restApi, Branch branch, string destinationBranch, MergeReport mergeReport, string comment, string taskNumber, TrunkBotConfiguration botConfig, string codeReviewsStorageFile, out int shelveId) { shelveId = -1; MergeToResponse result = TrunkMergebotApi.MergeBranchTo( restApi, branch.Repository, branch.FullName, destinationBranch, comment, TrunkMergebotApi.MergeToOptions.CreateShelve); if (result.Status == MergeToResultStatus.MergeNotNeeded) { ChangeTaskStatus.SetTaskAsMerged( restApi, branch, taskNumber, string.Format( "Branch {0} was already merged to {1} (MergeNotNeeded).", branch.FullName, botConfig.TrunkBranch), botConfig, codeReviewsStorageFile); return(false); } if (result.Status == MergeToResultStatus.AncestorNotFound || result.Status == MergeToResultStatus.Conflicts || result.Status == MergeToResultStatus.Error || result.ChangesetNumber == 0) { BuildMergeReport.AddFailedMergeProperty(mergeReport, result.Status, result.Message); ChangeTaskStatus.SetTaskAsFailed( restApi, branch, taskNumber, string.Format( "Can't merge branch {0}. Reason: {1}", branch.FullName, result.Message), botConfig, codeReviewsStorageFile); return(false); } shelveId = result.ChangesetNumber; BuildMergeReport.AddSucceededMergeProperty(mergeReport, result.Status); return(true); }
internal static bool ExistsAttributeName( RestApi restApi, string repository, string attributeName) { string query = string.Format("attributetype where name='{0}' ", attributeName); JArray findResult = TrunkMergebotApi.Find( restApi, repository, query, DATE_FORMAT, "retrieve the list of attributes named " + attributeName, new string[] { "name" }); return(findResult != null && findResult.Count > 0); }
internal static bool TryApplyShelve( RestApi restApi, Branch branch, string destinationBranch, MergeReport mergeReport, string comment, string taskNumber, int shelveId, TrunkBotConfiguration botConfig, string codeReviewsStorageFile, out int csetId) { MergeToResponse mergeResult = TrunkMergebotApi.MergeShelveTo( restApi, branch.Repository, shelveId, destinationBranch, comment, TrunkMergebotApi.MergeToOptions.EnsureNoDstChanges); csetId = mergeResult.ChangesetNumber; BuildMergeReport.UpdateMergeProperty(mergeReport, mergeResult.Status, csetId); if (mergeResult.Status == MergeToResultStatus.OK) { return(true); } if (mergeResult.Status == MergeToResultStatus.DestinationChanges) { // it should checkin the shelve only on the exact parent shelve cset. // if there are new changes in the trunk branch enqueue againg the task return(false); } ChangeTaskStatus.SetTaskAsFailed( restApi, branch, taskNumber, string.Format( "Can't merge branch {0}. Reason: {1}", branch.FullName, mergeResult.Message), botConfig, codeReviewsStorageFile); return(false); }
internal static string GetBranchName( RestApi restApi, string repository, string branchId) { string query = string.Format("branch where id={0}", branchId); JArray findResult = TrunkMergebotApi.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")); }
internal static List <Branch> FindResolvedBranches( RestApi 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 = TrunkMergebotApi.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 void SetTaskAsMerged( RestApi restApi, Branch branch, string taskNumber, string message, TrunkBotConfiguration botConfig, string codeReviewsStorageFile) { try { if (botConfig.Plastic.IsApprovedCodeReviewFilterEnabled) { ReviewsStorage.DeleteBranchReviews( branch.Repository, branch.Id, codeReviewsStorageFile); } TrunkMergebotApi.ChangeBranchAttribute( restApi, branch.Repository, branch.FullName, botConfig.Plastic.StatusAttribute.Name, botConfig.Plastic.StatusAttribute.MergedValue); if (taskNumber != null && botConfig.Issues != null) { TrunkMergebotApi.Issues.SetIssueField( restApi, botConfig.Issues.Plug, botConfig.Issues.ProjectKey, taskNumber, botConfig.Issues.StatusField.Name, botConfig.Issues.StatusField.MergedValue); } Notifier.NotifyTaskStatus( restApi, branch.Owner, message, botConfig.Notifications); } catch (Exception ex) { Notifier.NotifyException( restApi, branch, message, "merged", ex, botConfig.Notifications); } }
internal static void SetTaskAsTesting( RestApi restApi, Branch branch, string taskNumber, string message, TrunkBotConfiguration botConfig) { try { if (!string.IsNullOrEmpty(botConfig.Plastic.StatusAttribute.TestingValue)) { TrunkMergebotApi.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)) { TrunkMergebotApi.Issues.SetIssueField( restApi, botConfig.Issues.Plug, botConfig.Issues.ProjectKey, taskNumber, botConfig.Issues.StatusField.Name, botConfig.Issues.StatusField.TestingValue); } Notifier.NotifyTaskStatus( restApi, branch.Owner, message, botConfig.Notifications); } catch (Exception ex) { Notifier.NotifyException( restApi, branch, message, "testing", ex, botConfig.Notifications); } }
internal static Result TryProcessBranch( RestApi restApi, Branch branch, TrunkBotConfiguration botConfig, string botName, string codeReviewsStorageFile) { int shelveId = -1; string taskNumber = null; MergeReport mergeReport = 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); } if (!IsMergeAllowed(restApi, branch, botConfig.TrunkBranch)) { mLog.WarnFormat( "Branch {0} is not yet ready to be merged. " + "Jumping to next branch in the queue...", branch.FullName); return(Result.NotReady); } mLog.InfoFormat("Building the merge report of task {0} ...", taskNumber); mergeReport = BuildMergeReport.Build(TrunkMergebotApi.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); } string comment = GetComment(branch.FullName, taskTittle, botName); mLog.InfoFormat("Trying to shelve server-side-merge from {0} to {1}", branch.FullName, botConfig.TrunkBranch); if (!MergeToOperations.TryMergeToShelve( restApi, branch, botConfig.TrunkBranch, mergeReport, comment, taskNumber, botConfig, codeReviewsStorageFile, out shelveId)) { return(Result.Failed); } mLog.InfoFormat("Testing branch {0} ...", branch.FullName); if (!TryBuildTask(restApi, branch, mergeReport, taskNumber, shelveId, botConfig, codeReviewsStorageFile)) { return(Result.Failed); } mLog.InfoFormat("Checking-in shelved merged {0} from {1} to {2}", shelveId, branch.FullName, botConfig.TrunkBranch); int csetId = -1; if (!MergeToOperations.TryApplyShelve( restApi, branch, botConfig.TrunkBranch, mergeReport, comment, taskNumber, shelveId, botConfig, codeReviewsStorageFile, out csetId)) { return(Result.Failed); } mLog.InfoFormat("Checkin: Created changeset {0} in branch {1}", csetId, botConfig.TrunkBranch); mLog.InfoFormat("Setting branch {0} as 'integrated'...", branch.FullName); ChangeTaskStatus.SetTaskAsMerged( restApi, branch, taskNumber, string.Format( "Branch {0} was correctly merged to {1}.", branch.FullName, botConfig.TrunkBranch), botConfig, codeReviewsStorageFile); string labelName = string.Empty; if (!CreateLabel( restApi, csetId, branch.FullName, botConfig.TrunkBranch, botConfig.Repository, botConfig.Plastic.IsAutoLabelEnabled, botConfig.Plastic.AutomaticLabelPattern, mergeReport, branch.Owner, botConfig.Notifications, out labelName)) { return(Result.Failed); } if (!HasToRunPlanAfterTaskMerged(botConfig.CI)) { return(Result.Ok); } if (!TryRunAfterCheckinPlan( restApi, branch, mergeReport, taskNumber, csetId, labelName, botConfig)) { return(Result.Failed); } } 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, string.Format( "Can't process branch {0} because of an unexpected error: {1}.", branch.FullName, ex.Message), botConfig, codeReviewsStorageFile); BuildMergeReport.SetUnexpectedExceptionProperty(mergeReport, ex.Message); return(Result.Failed); } finally { ReportMerge(restApi, branch.Repository, branch.FullName, botName, mergeReport); SafeDeleteShelve(restApi, branch.Repository, shelveId); } return(Result.Ok); }
static bool IsMergeAllowed(RestApi restApi, Branch branch, string trunkBranch) { return(TrunkMergebotApi.IsMergeAllowed( restApi, branch.Repository, branch.FullName, trunkBranch)); }
internal static List <BranchWithReview> FindPendingBranchesWithReviews( RestApi 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 = TrunkMergebotApi.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); }