Beispiel #1
0
        public IList <Conflict> Merge(int changesetFrom, int changesetTo, MergeOptionsEx mergeOptions = MergeOptionsEx.None)
        {
            CheckPathsDefined();

            string sourcePath = _branchMap[BranchType.Source].Local;
            string targetPath = _branchMap[BranchType.Target].Local;

            var versionFrom = new ChangesetVersionSpec(changesetFrom);
            var versionTo   = new ChangesetVersionSpec(changesetTo);

            GetStatus status = WorkSpace.Merge(sourcePath, targetPath, versionFrom, versionTo, LockLevel.Unchanged,
                                               RecursionType.Full, mergeOptions);

            if (status.NoActionNeeded && status.NumOperations == 0)
            {
                Popups.ShowMessage("No changes found when merging cs " + versionFrom.ToString() + "-" + versionTo.ToString() + ".", MessageBoxImage.Asterisk);
            }

            /* Interpreting the return value:
             * http://teamfoundation.blogspot.fi/2006/11/merging-and-resolving-conflicts-using.html
             * NoActionNeeded == true && NumOperations == 0  – means that no changes in source needed to be merged, so no actual changes were pended
             * NoActionNeeded == false && NumOperations > 0 && HaveResolvableWarnings == false  – means that merges were performed,
             *                   but all conflicts were resolved automatically. Need to check in pended merge changes and that’s about it
             * NoActionNeeded == false && NumConflicts > 0  – merge was performed and there are conflicts to resolve
             * */

            return(GetConflicts(targetPath, status));
        }
Beispiel #2
0
        /// <summary>
        /// Merges a range changesets. Does not perform a check in.
        /// </summary>
        /// <returns>A tuple, where the boolean signals success, and the string contains and error message in case of failure.</returns>
        public static Tuple <bool, string> MergeRange(MyTfsConnection tfsConnection, Changeset[] changesets, IList <DirectoryInfo> branches,
                                                      IProgress <ProgressReportArgs> reporter, CancellationToken cancelToken, FileInfo tfExecutable, IPopupService popupService,
                                                      MergeOptionsEx mergeOptions = MergeOptionsEx.None)
        {
            Debug.Assert(branches.Count == 2, "Merging as range currently only supports two branches (1 source + 1 target)");
            //if (doCheckin == false)
            //{
            //    Debug.Assert(branches.Count == 2, "Currently not supported to have more than two branches in the chain when not checkin in after each merge.");
            //}

            if (changesets.Any() && branches.Count > 1)
            {
                DirectoryInfo sourceBranch = branches[0];
                DirectoryInfo targetBranch = branches[1];
                tfsConnection.SetLocalPath(BranchType.Source, sourceBranch.FullName);
                tfsConnection.SetLocalPath(BranchType.Target, targetBranch.FullName);

                string whatAreWeDoing = $"Merging changesets {changesets.First().ChangesetId} - {changesets.Last().ChangesetId}";
                reporter?.Report(new ProgressReportArgs(0, null, whatAreWeDoing));

                cancelToken.ThrowIfCancellationRequested();

                try
                {
                    CheckInitialConflicts(tfsConnection, targetBranch, whatAreWeDoing);

                    int firstId = changesets.First().ChangesetId;
                    int lastId  = changesets.Last().ChangesetId;

                    IList <Conflict> conflicts = tfsConnection.Merge(firstId, lastId, mergeOptions);

                    cancelToken.ThrowIfCancellationRequested();

                    if (conflicts.Count > 0 && !conflicts.All(c => c.AutoResolved))
                    {
                        //ResolveConflictsWithAPICall(conflicts, tfsConnection, checkinComment);
                        var conflictRetval = ConflictResolver.ResolveConflictsWithExternalExecutable(tfExecutable, tfsConnection, targetBranch.FullName, popupService);

                        if (!conflictRetval.Item1)
                        {
                            throw new MyTfsConflictException(conflictRetval.Item2.Count() + " unresolved conflicts.");
                        }

                        cancelToken.ThrowIfCancellationRequested();
                    }

                    reporter?.Report(new ProgressReportArgs(1));
                }
                catch (MyTfsConnectionException ex)
                {
                    reporter?.Report(new ProgressReportArgs(0, "Error", "Error " + whatAreWeDoing + "\n\n" + ex.ToString()));
                    return(Tuple.Create(false, ex.ToString()));
                }

                return(Tuple.Create(true, "Successfully merged."));
            }

            return(Tuple.Create(false, "No changesets, or not >= 2 branches."));
        }
Beispiel #3
0
        /// <summary>
        /// Build a comment for checkin for a single change set. Tries to remove any previously generated comments from the given comment string.
        /// </summary>
        public static string GetComment(string originalComment, int changesetId, string owner, string sourceBranch,
                                        string targetBranch, MergeOptionsEx mergeOptions = MergeOptionsEx.None)
        {
            string commentPart = TryToRemoveOldPrefix(originalComment, out string originalOwner);

            string ownerShort = !string.IsNullOrEmpty(originalOwner) ?
                                ShortenOwnerName(originalOwner) :
                                ShortenOwnerName(owner);

            string optionsPrefix = GetOptionsString(mergeOptions);

            if (!string.IsNullOrEmpty(optionsPrefix))
            {
                optionsPrefix = optionsPrefix + ", ";
            }

            var retval = string.Format(optionsPrefix + "{0} {1} > {2}, {3}: {4}",
                                       sourceBranch, changesetId, targetBranch, ownerShort, commentPart);

            return(retval);
        }
Beispiel #4
0
        /// <summary>
        /// Converts MergeOptionsEx to string. Returns an empty string if options is None.
        /// </summary>
        /// <remarks>Does some replace work to improve readability, e.g. AlwaysAcceptMine -> Discard.</remarks>
        private static string GetOptionsString(MergeOptionsEx options)
        {
            string retval;

            if (options == MergeOptionsEx.None)
            {
                retval = string.Empty;
            }
            else
            {
                retval = options.ToString();

                if (options.HasFlag(MergeOptionsEx.ForceMerge))
                {
                    retval = retval.Replace("ForceMerge", "Force");
                }
                else if (options.HasFlag(MergeOptionsEx.AlwaysAcceptMine))
                {
                    retval = retval.Replace("AlwaysAcceptMine", "Discard");
                }
            }

            return(retval);
        }
Beispiel #5
0
        /// <summary>
        /// Merges the changesets one by one. Each of the changesets is merged through all branches, ie. from first to last.
        /// </summary>
        /// <returns>A tuple, where the boolean signals success, and the string contains and error message in case of failure.</returns>
        public static Tuple <bool, string> MergeAndCommitOneByOne(MyTfsConnection tfsConnection, Changeset[] changesets,
                                                                  IList <DirectoryInfo> branches, IProgress <ProgressReportArgs> reporter, IProgress <FinishedItemReport> finishedItem,
                                                                  CancellationToken cancelToken, FileInfo tfExecutable, IPopupService popupService,
                                                                  MergeOptionsEx mergeOptions = MergeOptionsEx.None, bool doCheckin = true, bool associateWorkItems = true)
        {
            if (!changesets.Any() || branches.Count <= 1)
            {
                return(Tuple.Create(false, "No changesets, or not >= 2 branches."));
            }

            if (doCheckin == false)
            {
                Debug.Assert(branches.Count == 2, "Currently not supported to have more than two branches in the chain when not checkin in after each merge.");
            }

            // For the whole length of the list of changeset in the source branch.
            foreach (var csOriginal in changesets)
            {
                cancelToken.ThrowIfCancellationRequested();

                // For the whole depth of the list of branch merge chain.
                var csCurrent    = tfsConnection.GetChangeset(csOriginal.ChangesetId);
                int newCheckinId = 0;
                for (int ii = 0; ii < branches.Count - 1; ii++)
                {
                    cancelToken.ThrowIfCancellationRequested();

                    if (csCurrent != null)
                    {
                        var sourceBranch = branches[ii];
                        var targetBranch = branches[ii + 1];
                        tfsConnection.SetLocalPath(BranchType.Source, sourceBranch.FullName);
                        tfsConnection.SetLocalPath(BranchType.Target, targetBranch.FullName);

                        var    id             = csCurrent.ChangesetId;
                        string checkinComment = CommentBuilder.GetComment(csOriginal.Comment, id, csOriginal.OwnerDisplayName,
                                                                          sourceBranch.Name, targetBranch.Name, mergeOptions);

                        reporter?.Report(new ProgressReportArgs(0, null, "Merging: " + checkinComment));

                        try
                        {
                            CheckInitialConflicts(tfsConnection, targetBranch, checkinComment);

                            IList <Conflict> conflicts = tfsConnection.Merge(id, id, mergeOptions);

                            cancelToken.ThrowIfCancellationRequested();

                            if (conflicts.Count > 0 && !conflicts.All(c => c.AutoResolved))
                            {
                                //ResolveConflictsWithAPICall(conflicts, tfsConnection, checkinComment);
                                var conflictRetval = ConflictResolver.ResolveConflictsWithExternalExecutable(
                                    tfExecutable, tfsConnection, targetBranch.FullName, popupService, checkinComment);

                                if (conflictRetval.Item1 == false)
                                {
                                    throw new MyTfsConflictException(conflictRetval.Item2.Count() + " unresolved conflicts.");
                                }

                                cancelToken.ThrowIfCancellationRequested();
                            }

                            if (doCheckin)
                            {
                                reporter?.Report(new ProgressReportArgs(1, null, "Checkin: " + checkinComment));

                                var workItems = associateWorkItems ? csCurrent.WorkItems : new WorkItem[0];
                                workItems    = FilterWorkItemsToUpdate(workItems);
                                newCheckinId = tfsConnection.Checkin(checkinComment, workItems);
                            }

                            reporter?.Report(new ProgressReportArgs(1));

                            finishedItem?.Report(new FinishedItemReport()
                            {
                                SourceChangesetId = id,
                                CommitChangesetId = newCheckinId,
                                CommitComment     = checkinComment,
                                SourceBranchIndex = ii
                            });
                        }
                        catch (MyTfsConnectionException ex)
                        {
                            reporter?.Report(new ProgressReportArgs(0, "Error", "Error merging changeset: " + id.ToString() + "\n\n" + ex.ToString()));
                            return(Tuple.Create(false, ex.ToString()));
                        }
                    }
                    else
                    {
                        var errorMsg = "Error getting changeset information for id " + csOriginal.ChangesetId + ". Operation aborted.";
                        reporter?.Report(new ProgressReportArgs(0, "Error", errorMsg));
                        return(Tuple.Create(false, errorMsg));
                    }

                    if (newCheckinId > 0)
                    {
                        csCurrent = tfsConnection.GetChangeset(newCheckinId);
                    }
                }
            }

            return(Tuple.Create(true, "Successfully merged."));
        }
Beispiel #6
0
 public GetStatus Merge(string sourcePath, string targetPath, VersionSpec versionFrom, VersionSpec versionTo, LockLevel lockLevel, RecursionType recursion, MergeOptionsEx mergeOptions)
 {
     return(Workspace.Merge(sourcePath, targetPath, versionFrom, versionTo, lockLevel, recursion, mergeOptions));
 }
Beispiel #7
0
        /// <summary>
        /// Build a comment for checkin for a range of change sets.
        /// </summary>
        public static string GetCombinedMergeCheckinComment(string sourceBranch, string targetBranch,
                                                            ICollection <Tuple <int, string> > idAndOwnerOfChanges, MergeOptionsEx mergeOptions)
        {
            int firstChangeset = idAndOwnerOfChanges.Min(ch => ch.Item1);
            int lastChangeset  = idAndOwnerOfChanges.Max(ch => ch.Item1);
            var owners         = idAndOwnerOfChanges.Select(cs => cs.Item2).Distinct().ToArray();

            string ownerStr = owners.Length == 1
                ? ShortenOwnerName(owners.First())
                : $"{owners.Length} authors";

            string optionsPrefix = GetOptionsString(mergeOptions);

            if (!string.IsNullOrEmpty(optionsPrefix))
            {
                optionsPrefix += ", ";
            }

            string branchStr = $"{sourceBranch} {firstChangeset}-{lastChangeset} > {targetBranch}";
            string comment   = optionsPrefix + branchStr + ", " + ownerStr + ": ";

            if (mergeOptions.HasFlag(MergeOptionsEx.AlwaysAcceptMine))
            {
                var popups = Caliburn.Micro.IoC.Get <IPopupService>();
                var answer = popups.AskYesNoQuestion("Is this a \"Cleaning history\" case?");
                if (answer == System.Windows.MessageBoxResult.Yes)
                {
                    comment = $"Cleaning merge history ({comment})";
                }
            }

            return(comment);
        }
Beispiel #8
0
        /// <summary>
        /// Does the main merge operation for selected items and checks-in every changeset.
        /// </summary>
        /// <param name="mfrm">The UserControl.</param>
        /// <param name="lvcoll">The Collection of ListViewItems.</param>
        /// <param name="trg">The target path.</param>
        static internal void DoMerge(UserControl mfrm, IEnumerable <ListViewItem> lvcoll, string trg)
        {
            Workspace wrkspc = Utilities.vcext.Explorer.Workspace;

            if (!ServerItemExists(trg))
            {
                MessageBox.Show("Target server path is cloacked or doesn't exist.", Utilities.AppTitle);
                return;
            }

            if (AutomaticCheckin && wrkspc.GetPendingChanges().Length > 0)
            {
                MessageBox.Show("Please resolve all pending changes before going on.", Utilities.AppTitle);
                return;
            }

            //object prgmerge = CreateProgressMerge(vcsrv);
            //ShowProgressMerge(prgmerge, mfrm);

            int  idx       = 0;
            bool bcanceled = false;
            int  icanceled;
            var  dlg = Utilities.CreateThreadedWaitDialog("Merging changesets", "Stating changesets merge...", "status", 100);

            ErrorHandler.ThrowOnFailure(dlg.UpdateProgress("Merging changesets", "Stating changesets merge...", "status", idx++, 100, false, out bcanceled));
            if (bcanceled)
            {
                return;
            }

            foreach (var lvItem in lvcoll)
            {
                string MergeTypeText = lvItem.SubItems[MergeTypeIndex].Text;
                if (MergeTypeText == "none")
                {
                    continue;
                }

                Changeset ch = Utilities.vcsrv.GetChangeset((lvItem.Tag as ListViewItemTag).ChangesetID);
                Utilities.OutputCommandString("Preparing for merge changeset: " + ch.ChangesetId);

                if (LinkWorkItems)
                {
                    foreach (var workItm in ch.WorkItems)
                    {
                        Utilities.OutputCommandString("Associated WorkItem: " + workItm.Id);
                    }
                }

                ErrorHandler.ThrowOnFailure(dlg.UpdateProgress("Merging changesets", "Merging changeset: " + ch.ChangesetId, "status", idx++, 100, false, out bcanceled));
                if (bcanceled)
                {
                    return;
                }

                var chverspc = new ChangesetVersionSpec(ch.ChangesetId);
                Utilities.OutputCommandString("Changeset Version: " + chverspc.DisplayString);

                MergeOptionsEx mergeType = (MergeTypeText == "baseless" ? MergeOptionsEx.Baseless : MergeTypeText == "force" ? MergeOptionsEx.ForceMerge : MergeOptionsEx.None);
                mergeType |= mergeOptions;

                GetStatus sts = wrkspc.Merge((lvItem.Tag as ListViewItemTag).sourcePath, trg, chverspc, chverspc, LockLevel.Unchanged, RecursionType.Full, mergeType);
                Utilities.OutputCommandString("Merge summary: MergeOptionsEx=" + mergeType + ", NoActionNeeded=" + sts.NoActionNeeded + ", NumFailures=" + sts.NumFailures + ", NumOperations=" + sts.NumOperations + ", NumUpdated=" + sts.NumUpdated + ", NumWarnings=" + sts.NumWarnings);

                if (AutomaticCheckin)
                {
                    while (wrkspc.QueryConflicts(ch.Changes.Select(x => x.Item.ServerItem).ToArray(), true).Length > 0)
                    {
                        //foreach (var conflict in conflicts) wrkspc.ResolveConflict(conflict);
                        DialogResult res = MessageBox.Show("Merge conflicts where found. Resolve them or click Cancel to break merge operaton.", "Merge conflicts", MessageBoxButtons.OKCancel);
                        if (res == DialogResult.Cancel)
                        {
                            ErrorHandler.ThrowOnFailure(dlg.EndWaitDialog(out icanceled));
                            return;
                        }

                        if (mfrm.InvokeRequired)
                        {
                            var asynchres = mfrm.BeginInvoke(new MethodInvoker(Utilities.ShowResolveConflictsDlg));
                            mfrm.EndInvoke(asynchres);
                        }
                        else
                        {
                            Utilities.ShowResolveConflictsDlg();
                        }
                    }

                    var pendingCh = wrkspc.GetPendingChanges();//ch.Changes.Select(x => new ItemSpec(x.Item.ServerItem, RecursionType.Full, x.Item.DeletionId)).ToArray(), true).ToArray();
                    if (pendingCh.Length == 0)
                    {
                        Utilities.OutputCommandString("No pending changes found.");
                        continue;
                    }

                    var wrkitmch = (LinkWorkItems ? ch.WorkItems.Select(x => new WorkItemCheckinInfo(x, WorkItemCheckinAction.Associate)).ToArray() : null);

                    foreach (var pendChItem in pendingCh)
                    {
                        Utilities.OutputCommandString("Found pending change " + pendChItem.ChangeTypeName + ": " + pendChItem.SourceServerItem);
                    }

                    int newchid = wrkspc.CheckIn(pendingCh, ch.Committer, ch.Comment, ch.CheckinNote, wrkitmch, null, CheckinOptions.SuppressEvent);
                    Utilities.OutputCommandString("Created new changeset: " + newchid);
                }
                if (idx == 100)
                {
                    idx = 0;
                }
            }

            ErrorHandler.ThrowOnFailure(dlg.EndWaitDialog(out icanceled));
            //CloseProgressMerge(prgmerge);
        }