using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using Microsoft.TeamFoundation.VersionControl.Client; using Sep.Git.Tfs.Core; using Sep.Git.Tfs.Core.BranchVisitors; using Sep.Git.Tfs.Core.TfsInterop; using StructureMap; namespace Sep.Git.Tfs.VsCommon { public abstract class TfsHelperVs2010Base : TfsHelperBase { TfsApiBridge _bridge; public TfsHelperVs2010Base(TextWriter stdout, TfsApiBridge bridge, IContainer container) : base(stdout, bridge, container) { _bridge = bridge; } public override bool CanGetBranchInformation { get { return true; } } public override IEnumerable GetAllTfsRootBranchesOrderedByCreation() { return VersionControl.QueryRootBranchObjects(RecursionType.Full) .Where(b => b.Properties.ParentBranch == null) .Select(b => b.Properties.RootItem.Item); } public override IEnumerable GetBranches() { var branches = VersionControl.QueryRootBranchObjects(RecursionType.Full) .Where(b => b.Properties.RootItem.IsDeleted == false); return _bridge.Wrap(branches); } public override int GetRootChangesetForBranch(string tfsPathBranchToCreate, string tfsPathParentBranch = null) { try { if (!string.IsNullOrWhiteSpace(tfsPathParentBranch)) Trace.WriteLine("Parameter about parent branch will be ignored because this version of TFS is able to find the parent!"); Trace.WriteLine("Looking for all branches..."); var allTfsBranches = VersionControl.QueryRootBranchObjects(RecursionType.Full); var tfsBranchToCreate = allTfsBranches.FirstOrDefault(b => b.Properties.RootItem.Item.ToLower() == tfsPathBranchToCreate.ToLower()); if (tfsBranchToCreate == null) { Trace.WriteLine("error: TFS branches "+ tfsPathBranchToCreate +" not found!"); return -1; } tfsPathParentBranch = tfsBranchToCreate.Properties.ParentBranch.Item; Trace.WriteLine("Found parent branch : " + tfsPathParentBranch); var firstChangesetInBranchToCreate = VersionControl.QueryHistory(tfsPathBranchToCreate, VersionSpec.Latest, 0, RecursionType.Full, null, null, null, int.MaxValue, true, false, false).Cast().LastOrDefault(); if (firstChangesetInBranchToCreate == null) { throw new GitTfsException("An unexpected error occured when trying to find the root changeset.\nFailed to find first changeset for " + tfsPathBranchToCreate); } var mergedItemsToFirstChangesetInBranchToCreate = VersionControl .TrackMerges(new int[] {firstChangesetInBranchToCreate.ChangesetId}, new ItemIdentifier(tfsPathBranchToCreate), new ItemIdentifier[] {new ItemIdentifier(tfsPathParentBranch),}, null) .OrderBy(x => x.SourceChangeset.ChangesetId); var rootChangesetInParentBranch = GetRelevantChangesetBasedOnChangeType(mergedItemsToFirstChangesetInBranchToCreate, tfsPathParentBranch, tfsPathBranchToCreate); return rootChangesetInParentBranch.ChangesetId; } catch (FeatureNotSupportedException ex) { Trace.WriteLine(ex.Message); return base.GetRootChangesetForBranch(tfsPathBranchToCreate, tfsPathParentBranch); } } /// /// Gets the relevant TFS for the root changeset given a set /// of objects and a given . /// /// An array of objects describing the a set of merges. /// The tfs Path Parent Branch. /// The tfs Path Branch To Create. /// /// Each uses the SourceChangeset, SourceItem, TargetChangeset, and TargetItem /// properties with different semantics, depending on what it needs to describe, so the strategy to determine /// whether we are interested in a given ExtendedMerge summary depends on the SourceItem's . /// /// True if the given is relevant; False otherwise. /// private static ChangesetSummary GetRelevantChangesetBasedOnChangeType(IEnumerable merges, string tfsPathParentBranch, string tfsPathBranchToCreate) { merges = (merges ?? new ExtendedMerge[] {}).ToArray(); var merge = merges.LastOrDefault(m => m.SourceItem.Item.ServerItem.Equals(tfsPathParentBranch, StringComparison.InvariantCultureIgnoreCase)) ?? merges.LastOrDefault(); if (merge == null) { throw new GitTfsException("An unexpected error occured when trying to find the root changeset.\nFailed to find root changeset for " + tfsPathBranchToCreate + " branch in " + tfsPathParentBranch + " branch"); } if (merge.SourceItem.ChangeType.HasFlag(ChangeType.Branch) || merge.SourceItem.ChangeType.HasFlag(ChangeType.Merge) || merge.SourceItem.ChangeType.HasFlag(ChangeType.Add)) { Trace.WriteLine("Found C" + merge.SourceChangeset.ChangesetId + " on branch " + merge.SourceItem.Item.ServerItem); return merge.SourceChangeset; } if (merge.SourceItem.ChangeType.HasFlag(ChangeType.Rename) || merge.SourceItem.ChangeType.HasFlag(ChangeType.SourceRename)) { Trace.WriteLine("Found C" + merge.TargetChangeset.ChangesetId + " on branch " + merge.TargetItem.Item); return merge.TargetChangeset; } throw new GitTfsException( "Don't know (yet) how to find the root changeset for an ExtendedMerge of type " + merge.SourceItem.ChangeType, new string[] { "Open an Issue on Github to notify the community that you need support for '" + merge.SourceItem.ChangeType + "': https://github.com/git-tfs/git-tfs/issues" }); } public override void CreateBranch(string sourcePath, string targetPath, int changesetId, string comment = null) { var changesetToBranch = new ChangesetVersionSpec(changesetId); int branchChangesetId = VersionControl.CreateBranch(sourcePath, targetPath, changesetToBranch); if (comment != null) { Changeset changeset = VersionControl.GetChangeset(branchChangesetId); changeset.Comment = comment; changeset.Update(); } } } }