public async Task <IntegrationBranchResult> FindSingleIntegrationBranch(BranchGroupCompleteData details, string groupName, AttemptMergeDelegate doMerge) { var groups = new[] { details.GroupName, groupName }.OrderBy(g => g).ToArray(); var integrationBranch = await settings.FindIntegrationBranchForConflict(groups[0], groups[1], groups.ToImmutableList()); if (integrationBranch == null) { return(new IntegrationBranchResult { AddedBranches = Enumerable.Empty <string>(), }); } await doMerge(integrationBranch, details.LatestBranchName, $"Auto-merge branch '{integrationBranch}'"); #pragma warning disable CS4014 orchestration.EnqueueAction(new ConsolidateMergedAction(integrationBranch, details.GroupName)); #pragma warning restore return(new IntegrationBranchResult { Resolved = true, AddedBranches = new[] { integrationBranch }, }); }
private async Task <bool> MergesInProgress(BranchGroupCompleteData targetBranch, ImmutableList <BranchGroupCompleteData> branchesToRemove) { var actions = await orchestration.ActionQueue.FirstOrDefaultAsync(); var removingNames = branchesToRemove.Select(b => b.GroupName).ToImmutableHashSet(); return(actions.OfType <MergeDownstreamAction>() .Where(a => targetBranch.UpstreamBranchGroups.Contains(a.DownstreamBranch) || a.DownstreamBranch == targetBranch.GroupName || removingNames.Contains(a.DownstreamBranch)) .Any()); }
private BranchGroupCompleteData AddRemoteBranchNames(BranchGroupCompleteData branchDetails, ImmutableList <GitRef> remoteBranches) { var names = remoteBranches.Where(remoteBranch => branchIteration.IsBranchIteration(branchDetails.GroupName, remoteBranch.Name)).ToImmutableList(); return(new BranchGroupCompleteData(branchDetails) { Branches = names, LatestBranchName = names.Count == 0 ? null : branchIteration.GetLatestBranchNameIteration(branchDetails.GroupName, names.Select(b => b.Name)), }); }
public async Task <bool> AddAdditionalIntegrationBranches(BranchGroupCompleteData details, IUnitOfWork unitOfWork) { var branches = await branchSettings.GetIntegrationBranches(details.UpstreamBranchGroups); var toAdd = branches.Except(details.UpstreamBranchGroups).Except(new [] { details.GroupName }).ToImmutableList(); if (toAdd.Any()) { foreach (var upstreamBranch in toAdd) { branchSettings.AddBranchPropagation(upstreamBranch, details.GroupName, unitOfWork); } return(true); } return(false); }
private IObservable <(BranchGroupCompleteData branch, string latestBranchName)> GetLatestBranchTuple(BranchGroupCompleteData branch) { return(from latestBranchName in repository.LatestBranchName(branch).FirstOrDefaultAsync() select(branch, latestBranchName)); }
private async Task <ImmutableList <BranchGroupCompleteData> > GetBranchesToRemove(BranchGroupCompleteData targetBranch) { if (targetBranch.DirectDownstreamBranchGroups.Contains(newBaseBranch)) { // We're deleting an old branch, and all of its stuff moves down. This is like an integration branch rolling up. Easy. return(new[] { targetBranch }.ToImmutableList()); } var allBranches = await repository.AllBranches().FirstOrDefaultAsync(); var actualBranches = await repository.DetectUpstream(sourceBranch); var upstreamBranches = await branchSettings.GetAllUpstreamBranches(sourceBranch).FirstAsync(); // Filter to only the actual upstream branches; don't just remove anything that is downstream and happens to match! actualBranches = actualBranches.Intersect(upstreamBranches.Select(b => b.GroupName)).ToImmutableList(); // FIXME - this is the _branches_ not the _groups_ that are up-to-date. That should be okay for these purposes. var downstream = (await branchSettings.GetBranchDetails(newBaseBranch).FirstAsync()).DownstreamBranchGroups; var consolidatingBranches = (await(from branch in allBranches.ToObservable() where actualBranches.Contains(branch.GroupName) || branch.Branches.Select(b => b.Name).Any(actualBranches.Contains) where downstream.Contains(branch.GroupName) from result in GetLatestBranchTuple(branch) select result ).ToArray()).ToImmutableHashSet(); var branchesToRemove = await FindReadyToConsolidate(consolidatingBranches); branchesToRemove = branchesToRemove.Concat(allBranches.Where(g => g.Branches.Select(b => b.Name).Contains(sourceBranch))).ToImmutableList(); return(branchesToRemove); }
public async Task <IntegrationBranchResult> FindAndCreateIntegrationBranches(BranchGroupCompleteData downstreamDetails, IEnumerable <string> initialUpstreamBranchGroups, AttemptMergeDelegate doMerge) { // 1. Find branches that conflict // 2. Create integration branches for them // 3. Add the integration branch for ourselves foreach (var upstream in initialUpstreamBranchGroups) { if (await repository.IsBadBranch(upstream)) { // A branch that was directly upstream had updates pending return(new IntegrationBranchResult { PendingUpdates = true }); } } var result = await FindConflicts(downstreamDetails.GroupName, initialUpstreamBranchGroups, doMerge); if (result.PendingUpdates) { return(result); } var newIntegrationBranches = new List <string>(); using (var work = workFactory.CreateUnitOfWork()) { foreach (var conflict in result.Conflicts) { // I need an integration branch! var integrationBranch = await settings.FindIntegrationBranchForConflict(conflict.BranchA.GroupName, conflict.BranchB.GroupName, downstreamDetails.UpstreamBranchGroups); if (downstreamDetails.UpstreamBranchGroups.Contains(integrationBranch)) { // You already have one! - Maz Kanata continue; } var originalIntegrationBranch = integrationBranch; if (integrationBranch == null) { if (conflict.BranchA.GroupName == downstreamDetails.GroupName || conflict.BranchB.GroupName == downstreamDetails.GroupName) { continue; } integrationBranch = await integrationNaming.GetIntegrationBranchName(conflict.BranchA.GroupName, conflict.BranchB.GroupName); settings.CreateIntegrationBranch(conflict.BranchA.GroupName, conflict.BranchB.GroupName, integrationBranch, work); #pragma warning disable CS4014 orchestration.EnqueueAction(new MergeDownstreamAction(integrationBranch)); #pragma warning restore } if (originalIntegrationBranch != null && (conflict.BranchA.GroupName == downstreamDetails.GroupName || conflict.BranchB.GroupName == downstreamDetails.GroupName)) { // There was an integration branch with the current branch and an upstream branch. Flip it around and consolidate! newIntegrationBranches.Add(integrationBranch); settings.AddBranchPropagation(integrationBranch, downstreamDetails.GroupName, work); settings.RemoveBranchPropagation(downstreamDetails.GroupName, integrationBranch, work); #pragma warning disable CS4014 orchestration.EnqueueAction(new MergeDownstreamAction(downstreamDetails.GroupName)); orchestration.EnqueueAction(new ConsolidateMergedAction(integrationBranch, downstreamDetails.GroupName)); #pragma warning restore } else if (!downstreamDetails.UpstreamBranchGroups.Any(b => b == integrationBranch)) { newIntegrationBranches.Add(integrationBranch); settings.AddBranchPropagation(integrationBranch, downstreamDetails.GroupName, work); } } await work.CommitAsync(); } return(new IntegrationBranchResult { Conflicts = result.Conflicts, AddedBranches = newIntegrationBranches, }); }