From 242d171650c120eb4dc55e9960a428104e21d505 Mon Sep 17 00:00:00 2001 From: Philippe Miossec Date: Sat, 12 Jan 2013 00:28:06 +0100 Subject: [PATCH 01/10] Verify if querying branch informations are supported --- GitTfs/Commands/Branch.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/GitTfs/Commands/Branch.cs b/GitTfs/Commands/Branch.cs index d546f9ad..521f659d 100644 --- a/GitTfs/Commands/Branch.cs +++ b/GitTfs/Commands/Branch.cs @@ -58,6 +58,10 @@ namespace Sep.Git.Tfs.Commands { var root = tfsHelper.GetRootTfsBranchForRemotePath(tfsRepositoryPath); + if (!tfsHelper.CanGetBranchInformation) + { + throw new GitTfsException("error: this version of TFS doesn't support this functionality"); + } var visitor = new WriteBranchStructureTreeVisitor(tfsRepositoryPath, writer, tfsRemotes); root.AcceptVisitor(visitor); } @@ -114,4 +118,4 @@ namespace Sep.Git.Tfs.Commands } } } -} \ No newline at end of file +} From f2c7832ac219926f2c67f20b382f6494738cd452 Mon Sep 17 00:00:00 2001 From: Philippe Miossec Date: Thu, 10 Jan 2013 22:45:29 +0100 Subject: [PATCH 02/10] Don't return unvalid remotes The one without Tfs URL or path... It could happen when renaming a tfs remote with parameters no more supported --- GitTfs/Core/RemoteConfigConverter.cs | 2 +- GitTfsTest/Core/RemoteConfigConverterTests.cs | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/GitTfs/Core/RemoteConfigConverter.cs b/GitTfs/Core/RemoteConfigConverter.cs index 0dbb0d33..e94c7f17 100644 --- a/GitTfs/Core/RemoteConfigConverter.cs +++ b/GitTfs/Core/RemoteConfigConverter.cs @@ -36,7 +36,7 @@ namespace Sep.Git.Tfs.Core remote.Autotag = bool.Parse(entry.Value); } } - return remotes.Values; + return remotes.Values.Where(r => !string.IsNullOrWhiteSpace(r.Url) && !string.IsNullOrWhiteSpace(r.Repository)); } public IEnumerable> Dump(RemoteInfo remote) diff --git a/GitTfsTest/Core/RemoteConfigConverterTests.cs b/GitTfsTest/Core/RemoteConfigConverterTests.cs index d2e5e417..45c66bed 100644 --- a/GitTfsTest/Core/RemoteConfigConverterTests.cs +++ b/GitTfsTest/Core/RemoteConfigConverterTests.cs @@ -134,6 +134,24 @@ namespace Sep.Git.Tfs.Test.Core Assert.Equal(new string[] { "http://old:8080/", "http://other/" }, remote.Aliases); Assert.True(remote.Autotag); } + + + [Fact] + public void ShouldNotReturnLackingTfsUrlRemote() + { + var remotes = Load( + c("tfs-remote.default.repository", "$/project")); + Assert.Equal(0, remotes.Count()); + } + + [Fact] + public void ShouldNotReturnLackingTfsRepositoryRemote() + { + var remotes = Load( + c("tfs-remote.default.url", "http://server/path")); + Assert.Equal(0, remotes.Count()); + } + } RemoteConfigConverter _converter = new RemoteConfigConverter(); From a334a579523647284c7493089004d1695f33eca2 Mon Sep 17 00:00:00 2001 From: Philippe Miossec Date: Sat, 5 Jan 2013 18:54:41 +0100 Subject: [PATCH 03/10] Add move and delete branch option to `branch`command and add a DeleteTfsRemote() and MoveRemote() in GitRepository --- GitTfs/Commands/Branch.cs | 63 +++++++++++++++++++++++++++- GitTfs/Core/DerivedGitTfsRemote.cs | 6 +++ GitTfs/Core/GitRepository.cs | 54 ++++++++++++++++++++++++ GitTfs/Core/GitTfsRemote.cs | 2 + GitTfs/Core/IGitRepository.cs | 6 ++- GitTfs/Core/IGitTfsRemote.cs | 1 + GitTfs/Core/RemoteConfigConverter.cs | 8 ++++ 7 files changed, 137 insertions(+), 3 deletions(-) diff --git a/GitTfs/Commands/Branch.cs b/GitTfs/Commands/Branch.cs index 521f659d..9b6ac3da 100644 --- a/GitTfs/Commands/Branch.cs +++ b/GitTfs/Commands/Branch.cs @@ -1,4 +1,5 @@ using System.ComponentModel; +using System.Diagnostics; using System.IO; using System.Linq; using System.Collections.Generic; @@ -16,25 +17,83 @@ namespace Sep.Git.Tfs.Commands { private Globals globals; private TextWriter stdout; + private readonly Help helper; + private readonly Cleanup cleanup; public bool DisplayRemotes { get; set; } + public bool RenameRemote { get; set; } + public bool DeleteRemote { get; set; } public OptionSet OptionSet { get { return new OptionSet { - { "r|remotes", "Display all the TFS branch of the current TFS server", v => DisplayRemotes = (v != null) } + { "r|remotes", "Display all the TFS branch of the current TFS server", v => DisplayRemotes = (v != null) }, + { "m|move", "Rename a TFS branch", v => RenameRemote = (v != null) }, + { "delete", "Delete a TFS branch", v => DeleteRemote = (v != null) }, } .Merge(globals.OptionSet); } } - public Branch(Globals globals, TextWriter stdout) + public Branch(Globals globals, TextWriter stdout, Help helper, Cleanup cleanup) { this.globals = globals; this.stdout = stdout; + this.helper = helper; + this.cleanup = cleanup; } + public int Run(string oldRemoteName, string newRemoteName) + { + if (!RenameRemote) + { + helper.Run(this); + return GitTfsExitCodes.Help; + } + + var newRemoteNameExpected = globals.Repository.AssertValidBranchName(newRemoteName.ToGitRefName()); + if (newRemoteNameExpected != newRemoteName) + stdout.WriteLine("The name of the branch after renaming will be : " + newRemoteNameExpected); + + if (globals.Repository.HasRemote(newRemoteNameExpected)) + { + throw new GitTfsException("error: this remote name is already used!"); + } + + stdout.WriteLine("Cleaning before processing rename..."); + cleanup.Run(); + + globals.Repository.MoveRemote(oldRemoteName, newRemoteNameExpected); + + if(globals.Repository.RenameBranch(oldRemoteName, newRemoteName) == null) + stdout.WriteLine("warning: no local branch found to rename"); + + return GitTfsExitCodes.OK; + } + + public int Run(string remoteName) + { + if (!DeleteRemote) + { + helper.Run(this); + return GitTfsExitCodes.Help; + } + + var remote = globals.Repository.ReadTfsRemote(remoteName); + if (remote == null) + { + throw new GitTfsException(string.Format("Error: Remote \"{0}\" not found!", remoteName)); + } + + stdout.WriteLine("Cleaning before processing delete..."); + cleanup.Run(); + + globals.Repository.DeleteTfsRemote(remote); + return GitTfsExitCodes.OK; + } + + public int Run() { // should probably pull this from options so that it is settable from the command-line diff --git a/GitTfs/Core/DerivedGitTfsRemote.cs b/GitTfs/Core/DerivedGitTfsRemote.cs index b208a482..ef5b9df8 100644 --- a/GitTfs/Core/DerivedGitTfsRemote.cs +++ b/GitTfs/Core/DerivedGitTfsRemote.cs @@ -233,5 +233,11 @@ namespace Sep.Git.Tfs.Core } #endregion + + + public RemoteInfo RemoteInfo + { + get { throw new NotImplementedException(); } + } } } diff --git a/GitTfs/Core/GitRepository.cs b/GitTfs/Core/GitRepository.cs index 8a87cc87..676b529a 100644 --- a/GitTfs/Core/GitRepository.cs +++ b/GitTfs/Core/GitRepository.cs @@ -8,6 +8,7 @@ using Sep.Git.Tfs.Commands; using Sep.Git.Tfs.Core.TfsInterop; using StructureMap; using LibGit2Sharp; +using Branch = LibGit2Sharp.Branch; namespace Sep.Git.Tfs.Core { @@ -136,6 +137,59 @@ namespace Sep.Git.Tfs.Core return _cachedRemotes[remote.Id] = gitTfsRemote; } + public void DeleteTfsRemote(IGitTfsRemote remote) + { + if (remote == null) + throw new GitTfsException("error: the name of the remote to delete is invalid!"); + + UnsetTfsRemoteConfig(remote.Id); + _repository.Refs.Remove(remote.RemoteRef); + } + + private void UnsetTfsRemoteConfig(string remoteId) + { + foreach (var entry in _remoteConfigReader.Delete(remoteId)) + { + _repository.Config.Unset(entry.Key); + } + _cachedRemotes = null; + } + + public void MoveRemote(string oldRemoteName, string newRemoteName) + { + if (!_repository.Refs.IsValidName("refs/heads/" + oldRemoteName)) + throw new GitTfsException("error: the name of the remote to move is invalid!"); + + if (!_repository.Refs.IsValidName("refs/heads/" + newRemoteName)) + throw new GitTfsException("error: the new name of the remote is invalid!"); + + if (HasRemote(newRemoteName)) + throw new GitTfsException(string.Format("error: this remote name \"{0}\" is already used!", newRemoteName)); + + var oldRemote = ReadTfsRemote(oldRemoteName); + if(oldRemote == null) + throw new GitTfsException(string.Format("error: the remote \"{0}\" doesn't exist!", oldRemoteName)); + + var remoteInfo = oldRemote.RemoteInfo; + remoteInfo.Id = newRemoteName; + + CreateTfsRemote(remoteInfo); + var newRemote = ReadTfsRemote(newRemoteName); + + _repository.Refs.Move(oldRemote.RemoteRef, newRemote.RemoteRef); + UnsetTfsRemoteConfig(oldRemoteName); + } + + public Branch RenameBranch(string oldName, string newName) + { + var branch = _repository.Branches[oldName]; + + if (branch == null) + return null; + + return _repository.Branches.Move(branch, newName); + } + private IDictionary ReadTfsRemotes() { // does this need to ensuretfsauthenticated? diff --git a/GitTfs/Core/GitTfsRemote.cs b/GitTfs/Core/GitTfsRemote.cs index 6972d467..07046784 100644 --- a/GitTfs/Core/GitTfsRemote.cs +++ b/GitTfs/Core/GitTfsRemote.cs @@ -20,6 +20,7 @@ namespace Sep.Git.Tfs.Core private long? maxChangesetId; private string maxCommitHash; private bool isTfsAuthenticated; + public RemoteInfo RemoteInfo { get; private set; } public GitTfsRemote(RemoteInfo info, IGitRepository repository, RemoteOptions remoteOptions, Globals globals, ITfsHelper tfsHelper, TextWriter stdout) { @@ -29,6 +30,7 @@ namespace Sep.Git.Tfs.Core Tfs = tfsHelper; Repository = repository; + RemoteInfo = info; Id = info.Id; TfsUrl = info.Url; TfsRepositoryPath = info.Repository; diff --git a/GitTfs/Core/IGitRepository.cs b/GitTfs/Core/IGitRepository.cs index 5369a558..641ee7e3 100644 --- a/GitTfs/Core/IGitRepository.cs +++ b/GitTfs/Core/IGitRepository.cs @@ -1,7 +1,8 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using Sep.Git.Tfs.Commands; +using Branch = LibGit2Sharp.Branch; namespace Sep.Git.Tfs.Core { @@ -12,6 +13,7 @@ namespace Sep.Git.Tfs.Core IEnumerable ReadAllTfsRemotes(); IGitTfsRemote ReadTfsRemote(string remoteId); IGitTfsRemote CreateTfsRemote(RemoteInfo remoteInfo); + void DeleteTfsRemote(IGitTfsRemote remoteId); bool HasRemote(string remoteId); bool HasRef(string gitRef); void MoveTfsRefForwardIfNeeded(IGitTfsRemote remote); @@ -27,8 +29,10 @@ namespace Sep.Git.Tfs.Core string GetCommitMessage(string head, string parentCommitish); string AssertValidBranchName(string gitBranchName); bool CreateBranch(string gitBranchName, string target); + Branch RenameBranch(string oldName, string newName); string FindCommitHashByCommitMessage(string patternToFind); void CreateTag(string name, string sha, string comment, string Owner, string emailOwner, System.DateTime creationDate); void CreateNote(string sha, string content, string owner, string emailOwner, DateTime creationDate); + void MoveRemote(string oldRemoteName, string newRemoteName); } } diff --git a/GitTfs/Core/IGitTfsRemote.cs b/GitTfs/Core/IGitTfsRemote.cs index 09e8091f..942c6cea 100644 --- a/GitTfs/Core/IGitTfsRemote.cs +++ b/GitTfs/Core/IGitTfsRemote.cs @@ -8,6 +8,7 @@ namespace Sep.Git.Tfs.Core public interface IGitTfsRemote { bool IsDerived { get; } + RemoteInfo RemoteInfo { get; } string Id { get; set; } string TfsUrl { get; set; } string TfsRepositoryPath { get; set; } diff --git a/GitTfs/Core/RemoteConfigConverter.cs b/GitTfs/Core/RemoteConfigConverter.cs index e94c7f17..d07183a3 100644 --- a/GitTfs/Core/RemoteConfigConverter.cs +++ b/GitTfs/Core/RemoteConfigConverter.cs @@ -58,5 +58,13 @@ namespace Sep.Git.Tfs.Core { return new KeyValuePair(key, value); } + + public IEnumerable> Delete(string remoteId) + { + if (string.IsNullOrWhiteSpace(remoteId)) + return new List>(); + + return Dump(new RemoteInfo {Id = remoteId}); + } } } From 00a6e34d8c775295d44baa93a7a036c05ed05673 Mon Sep 17 00:00:00 2001 From: Philippe Miossec Date: Sun, 6 Jan 2013 14:17:00 +0100 Subject: [PATCH 04/10] Add create Tfs branch option to `branch`command + other small refactoring --- GitTfs.VsCommon/TfsHelper.Common.cs | 6 +++ .../TfsHelper.PostVs2010.Common.cs | 13 +++++ GitTfs.VsFake/TfsHelper.VsFake.cs | 5 ++ GitTfs/Commands/Branch.cs | 50 +++++++++++++++---- GitTfs/Core/GitRepository.cs | 6 +++ GitTfs/Core/IGitRepository.cs | 1 + GitTfs/Core/TfsInterop/ITfsHelper.cs | 1 + 7 files changed, 72 insertions(+), 10 deletions(-) diff --git a/GitTfs.VsCommon/TfsHelper.Common.cs b/GitTfs.VsCommon/TfsHelper.Common.cs index 596f7468..3581f0b3 100644 --- a/GitTfs.VsCommon/TfsHelper.Common.cs +++ b/GitTfs.VsCommon/TfsHelper.Common.cs @@ -590,5 +590,11 @@ namespace Sep.Git.Tfs.VsCommon }); } + public virtual void CreateBranch(string sourcePath, string targetPath, int changesetId, string comment = null) + { + throw new NotImplementedException(); + + } + } } diff --git a/GitTfs.VsCommon/TfsHelper.PostVs2010.Common.cs b/GitTfs.VsCommon/TfsHelper.PostVs2010.Common.cs index 918f408e..87dfc38d 100644 --- a/GitTfs.VsCommon/TfsHelper.PostVs2010.Common.cs +++ b/GitTfs.VsCommon/TfsHelper.PostVs2010.Common.cs @@ -118,6 +118,19 @@ namespace Sep.Git.Tfs.VsCommon }); } } + + 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(); + } + } } } diff --git a/GitTfs.VsFake/TfsHelper.VsFake.cs b/GitTfs.VsFake/TfsHelper.VsFake.cs index 4c505f44..6a815dba 100644 --- a/GitTfs.VsFake/TfsHelper.VsFake.cs +++ b/GitTfs.VsFake/TfsHelper.VsFake.cs @@ -366,6 +366,11 @@ namespace Sep.Git.Tfs.VsFake { throw new NotImplementedException(); } + + public void CreateBranch(string sourcePath, string targetPath, int changesetId, string comment = null) + { + throw new NotImplementedException(); + } #endregion } } diff --git a/GitTfs/Commands/Branch.cs b/GitTfs/Commands/Branch.cs index 9b6ac3da..0f5c4f1d 100644 --- a/GitTfs/Commands/Branch.cs +++ b/GitTfs/Commands/Branch.cs @@ -19,34 +19,40 @@ namespace Sep.Git.Tfs.Commands private TextWriter stdout; private readonly Help helper; private readonly Cleanup cleanup; + private readonly InitBranch initBranch; public bool DisplayRemotes { get; set; } - public bool RenameRemote { get; set; } - public bool DeleteRemote { get; set; } + public bool ShouldRenameRemote { get; set; } + public bool ShouldDeleteRemote { get; set; } + public bool ShouldCreateRemote { get; set; } + public string Comment { get; set; } public OptionSet OptionSet { get { return new OptionSet { - { "r|remotes", "Display all the TFS branch of the current TFS server", v => DisplayRemotes = (v != null) }, - { "m|move", "Rename a TFS branch", v => RenameRemote = (v != null) }, - { "delete", "Delete a TFS branch", v => DeleteRemote = (v != null) }, + { "r|remotes", "Display the TFS branches of the current TFS root branch existing on the TFS server", v => DisplayRemotes = (v != null) }, + { "c|create", "Create a TFS branch", v => ShouldCreateRemote = (v != null) }, + { "comment=", "Comment used for the creation of the TFS branch ", v => Comment = v }, + { "m|move", "Rename a TFS remote", v => ShouldRenameRemote = (v != null) }, + { "delete", "Delete a TFS remote", v => ShouldDeleteRemote = (v != null) }, } .Merge(globals.OptionSet); } } - public Branch(Globals globals, TextWriter stdout, Help helper, Cleanup cleanup) + public Branch(Globals globals, TextWriter stdout, Help helper, Cleanup cleanup, InitBranch initBranch) { this.globals = globals; this.stdout = stdout; this.helper = helper; this.cleanup = cleanup; + this.initBranch = initBranch; } public int Run(string oldRemoteName, string newRemoteName) { - if (!RenameRemote) + if (!ShouldRenameRemote) { helper.Run(this); return GitTfsExitCodes.Help; @@ -72,14 +78,38 @@ namespace Sep.Git.Tfs.Commands return GitTfsExitCodes.OK; } - public int Run(string remoteName) + public int Run(string param) + { + if (!(ShouldDeleteRemote ^ ShouldCreateRemote)) { - if (!DeleteRemote) - { helper.Run(this); return GitTfsExitCodes.Help; } + if (ShouldDeleteRemote) + return DeleteRemote(param); + if (ShouldCreateRemote) + return CreateRemote(param, "test creation branch"); + + return GitTfsExitCodes.OK; + } + + private int CreateRemote(string tfsPath, string gitBranchNameExpected = null) + { + tfsPath.AssertValidTfsPath(); + Trace.WriteLine("Getting commit informations..."); + var commit = globals.Repository.GetCurrentTfsCommit(); + if(commit == null) + throw new GitTfsException("error : the current commit is not checked in TFS!"); + var remote = commit.Remote; + Trace.WriteLine("Creating branch in TFS..."); + remote.Tfs.CreateBranch(remote.TfsRepositoryPath, tfsPath, (int)commit.ChangesetId, Comment ?? "Creation branch " + tfsPath); + Trace.WriteLine("Init branch in local repository..."); + return initBranch.Run(tfsPath, gitBranchNameExpected); + } + + private int DeleteRemote(string remoteName) + { var remote = globals.Repository.ReadTfsRemote(remoteName); if (remote == null) { diff --git a/GitTfs/Core/GitRepository.cs b/GitTfs/Core/GitRepository.cs index 676b529a..59444cfb 100644 --- a/GitTfs/Core/GitRepository.cs +++ b/GitTfs/Core/GitRepository.cs @@ -260,6 +260,12 @@ namespace Sep.Git.Tfs.Core return tfsCommits; } + public TfsChangesetInfo GetCurrentTfsCommit() + { + var currentCommit = _repository.Head.Commits.First(); + return TryParseChangesetInfo(currentCommit.Message, currentCommit.Sha, false); + } + private void FindTfsCommits(TextReader stdout, ICollection tfsCommits, bool includeStubRemotes) { string currentCommit = null; diff --git a/GitTfs/Core/IGitRepository.cs b/GitTfs/Core/IGitRepository.cs index 641ee7e3..bec2321a 100644 --- a/GitTfs/Core/IGitRepository.cs +++ b/GitTfs/Core/IGitRepository.cs @@ -19,6 +19,7 @@ namespace Sep.Git.Tfs.Core void MoveTfsRefForwardIfNeeded(IGitTfsRemote remote); IEnumerable GetLastParentTfsCommits(string head); IEnumerable GetLastParentTfsCommits(string head, bool includeStubRemotes); + TfsChangesetInfo GetCurrentTfsCommit(); IDictionary GetObjects(string commit); string HashAndInsertObject(string filename); IEnumerable GetChangedFiles(string from, string to); diff --git a/GitTfs/Core/TfsInterop/ITfsHelper.cs b/GitTfs/Core/TfsInterop/ITfsHelper.cs index 26bcb2a1..8ed4434a 100644 --- a/GitTfs/Core/TfsInterop/ITfsHelper.cs +++ b/GitTfs/Core/TfsInterop/ITfsHelper.cs @@ -32,5 +32,6 @@ namespace Sep.Git.Tfs.Core.TfsInterop IEnumerable GetAllTfsRootBranchesOrderedByCreation(); IEnumerable GetBranches(); void EnsureAuthenticated(); + void CreateBranch(string sourcePath, string targetPath, int changesetId, string comment = null); } } From b5ba9a07ae610bb1a0b0a262acf40a8de15af841 Mon Sep 17 00:00:00 2001 From: Philippe Miossec Date: Sun, 3 Feb 2013 19:06:55 +0100 Subject: [PATCH 05/10] Add option `--all` to display all the root TFS branches --- GitTfs/Commands/Branch.cs | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/GitTfs/Commands/Branch.cs b/GitTfs/Commands/Branch.cs index 0f5c4f1d..62da6c76 100644 --- a/GitTfs/Commands/Branch.cs +++ b/GitTfs/Commands/Branch.cs @@ -21,6 +21,7 @@ namespace Sep.Git.Tfs.Commands private readonly Cleanup cleanup; private readonly InitBranch initBranch; public bool DisplayRemotes { get; set; } + public bool DisplayAllRootRemotes { get; set; } public bool ShouldRenameRemote { get; set; } public bool ShouldDeleteRemote { get; set; } public bool ShouldCreateRemote { get; set; } @@ -32,6 +33,7 @@ namespace Sep.Git.Tfs.Commands return new OptionSet { { "r|remotes", "Display the TFS branches of the current TFS root branch existing on the TFS server", v => DisplayRemotes = (v != null) }, + { "a|all", "Display the TFS branches of all the root branches existing on the TFS server", v => DisplayAllRootRemotes = (v != null) }, { "c|create", "Create a TFS branch", v => ShouldCreateRemote = (v != null) }, { "comment=", "Comment used for the creation of the TFS branch ", v => Comment = v }, { "m|move", "Rename a TFS remote", v => ShouldRenameRemote = (v != null) }, @@ -132,11 +134,29 @@ namespace Sep.Git.Tfs.Commands var tfsRemotes = globals.Repository.ReadAllTfsRemotes(); if (DisplayRemotes) { - var remote = globals.Repository.ReadTfsRemote(remoteId); + if (!DisplayAllRootRemotes) + { + var remote = globals.Repository.ReadTfsRemote(remoteId); - stdout.WriteLine("\nTFS branch structure:"); - WriteRemoteTfsBranchStructure(remote.Tfs, stdout, remote.TfsRepositoryPath, tfsRemotes); - return GitTfsExitCodes.OK; + stdout.WriteLine("\nTFS branch structure:"); + WriteRemoteTfsBranchStructure(remote.Tfs, stdout, remote.TfsRepositoryPath, tfsRemotes); + return GitTfsExitCodes.OK; + } + else + { + var remote = tfsRemotes.First(r => r.Id == remoteId); + if (!remote.Tfs.CanGetBranchInformation) + { + throw new GitTfsException("error: this version of TFS doesn't support this functionality"); + } + foreach (var branch in remote.Tfs.GetBranches().Where(b=>b.IsRoot)) + { + var root = remote.Tfs.GetRootTfsBranchForRemotePath(branch.Path); + var visitor = new WriteBranchStructureTreeVisitor(remote.TfsRepositoryPath, stdout, tfsRemotes); + root.AcceptVisitor(visitor); + } + return GitTfsExitCodes.OK; + } } WriteTfsRemoteDetails(stdout, tfsRemotes); From f5f21f26346227fcf5005d1dce053e1b0bc41db2 Mon Sep 17 00:00:00 2001 From: Philippe Miossec Date: Sun, 3 Feb 2013 19:39:17 +0100 Subject: [PATCH 06/10] branch command description --- GitTfs/Commands/Branch.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GitTfs/Commands/Branch.cs b/GitTfs/Commands/Branch.cs index 62da6c76..5696956a 100644 --- a/GitTfs/Commands/Branch.cs +++ b/GitTfs/Commands/Branch.cs @@ -11,7 +11,7 @@ using StructureMap; namespace Sep.Git.Tfs.Commands { [Pluggable("branch")] - [Description("branch")] + [Description("branch\n git tfs branch -r\n git tfs branch -r -all\n git tfs branch $/Repository/ProjectBranchToCreate \n git tfs branch --move oldTfsRemoteName newTfsRemoteName\n git tfs branch --delete tfsRemoteName\n")] [RequiresValidGitRepository] public class Branch : GitTfsCommand { From 3c4f45f3c128fb24f630c985aa10c8b46f3adb8e Mon Sep 17 00:00:00 2001 From: Philippe Miossec Date: Sun, 3 Feb 2013 22:28:49 +0100 Subject: [PATCH 07/10] Creation branch is no more an option but the main action (like git branch ommand) + rewrite Run() methods --- GitTfs/Commands/Branch.cs | 58 +++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/GitTfs/Commands/Branch.cs b/GitTfs/Commands/Branch.cs index 5696956a..bbfbb318 100644 --- a/GitTfs/Commands/Branch.cs +++ b/GitTfs/Commands/Branch.cs @@ -24,7 +24,6 @@ namespace Sep.Git.Tfs.Commands public bool DisplayAllRootRemotes { get; set; } public bool ShouldRenameRemote { get; set; } public bool ShouldDeleteRemote { get; set; } - public bool ShouldCreateRemote { get; set; } public string Comment { get; set; } public OptionSet OptionSet @@ -34,7 +33,6 @@ namespace Sep.Git.Tfs.Commands { { "r|remotes", "Display the TFS branches of the current TFS root branch existing on the TFS server", v => DisplayRemotes = (v != null) }, { "a|all", "Display the TFS branches of all the root branches existing on the TFS server", v => DisplayAllRootRemotes = (v != null) }, - { "c|create", "Create a TFS branch", v => ShouldCreateRemote = (v != null) }, { "comment=", "Comment used for the creation of the TFS branch ", v => Comment = v }, { "m|move", "Rename a TFS remote", v => ShouldRenameRemote = (v != null) }, { "delete", "Delete a TFS remote", v => ShouldDeleteRemote = (v != null) }, @@ -52,14 +50,43 @@ namespace Sep.Git.Tfs.Commands this.initBranch = initBranch; } - public int Run(string oldRemoteName, string newRemoteName) { - if (!ShouldRenameRemote) + public int Run() + { + if (ShouldRenameRemote || ShouldDeleteRemote) + return helper.Run(this); + + return DisplayBranchData(); + } + + public int Run(string param) + { + if (ShouldRenameRemote) + return helper.Run(this); + { - helper.Run(this); - return GitTfsExitCodes.Help; } + if (ShouldDeleteRemote) + return DeleteRemote(param); + + return CreateRemote(param); + } + + public int Run(string param1, string param2) + { + + if (ShouldDeleteRemote) + return helper.Run(this); + + if (ShouldRenameRemote) + return RenameRemote(param1, param2); + + return CreateRemote(param1, param2); + } + + private int RenameRemote(string oldRemoteName, string newRemoteName) + { var newRemoteNameExpected = globals.Repository.AssertValidBranchName(newRemoteName.ToGitRefName()); if (newRemoteNameExpected != newRemoteName) stdout.WriteLine("The name of the branch after renaming will be : " + newRemoteNameExpected); @@ -80,22 +107,6 @@ namespace Sep.Git.Tfs.Commands return GitTfsExitCodes.OK; } - public int Run(string param) - { - if (!(ShouldDeleteRemote ^ ShouldCreateRemote)) - { - helper.Run(this); - return GitTfsExitCodes.Help; - } - if (ShouldDeleteRemote) - return DeleteRemote(param); - - if (ShouldCreateRemote) - return CreateRemote(param, "test creation branch"); - - return GitTfsExitCodes.OK; - } - private int CreateRemote(string tfsPath, string gitBranchNameExpected = null) { tfsPath.AssertValidTfsPath(); @@ -125,8 +136,7 @@ namespace Sep.Git.Tfs.Commands return GitTfsExitCodes.OK; } - - public int Run() + public int DisplayBranchData() { // should probably pull this from options so that it is settable from the command-line const string remoteId = GitTfsConstants.DefaultRepositoryId; From bc1b49c8a80555da5767064811ff10ff8d691ce7 Mon Sep 17 00:00:00 2001 From: Philippe Miossec Date: Sun, 3 Feb 2013 22:29:22 +0100 Subject: [PATCH 08/10] Add `init-branch` features to `branch` command --- GitTfs/Commands/Branch.cs | 40 ++++++++++++++++++++++++++++++++--- GitTfs/Commands/InitBranch.cs | 12 +++++------ 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/GitTfs/Commands/Branch.cs b/GitTfs/Commands/Branch.cs index bbfbb318..79d7f295 100644 --- a/GitTfs/Commands/Branch.cs +++ b/GitTfs/Commands/Branch.cs @@ -1,3 +1,4 @@ +using System; using System.ComponentModel; using System.Diagnostics; using System.IO; @@ -21,10 +22,15 @@ namespace Sep.Git.Tfs.Commands private readonly Cleanup cleanup; private readonly InitBranch initBranch; public bool DisplayRemotes { get; set; } - public bool DisplayAllRootRemotes { get; set; } + public bool ManageAll { get; set; } public bool ShouldRenameRemote { get; set; } public bool ShouldDeleteRemote { get; set; } + public bool ShouldInitBranch { get; set; } public string Comment { get; set; } + public string TfsUsername { get; set; } + public string TfsPassword { get; set; } + public string AuthorsFilePath { get; set; } + public string ParentBranch { get; set; } public OptionSet OptionSet { @@ -32,10 +38,15 @@ namespace Sep.Git.Tfs.Commands return new OptionSet { { "r|remotes", "Display the TFS branches of the current TFS root branch existing on the TFS server", v => DisplayRemotes = (v != null) }, - { "a|all", "Display the TFS branches of all the root branches existing on the TFS server", v => DisplayAllRootRemotes = (v != null) }, + { "all", "Display (used with option --remotes) the TFS branches of all the root branches existing on the TFS server\n or Initialize (used with option --init) all existing TFS branches (For TFS 2010 and later)", v => ManageAll = (v != null) }, { "comment=", "Comment used for the creation of the TFS branch ", v => Comment = v }, { "m|move", "Rename a TFS remote", v => ShouldRenameRemote = (v != null) }, { "delete", "Delete a TFS remote", v => ShouldDeleteRemote = (v != null) }, + { "init", "Initialize an existing TFS branch", v => ShouldInitBranch = (v != null) }, + { "b|tfs-parent-branch=", "TFS Parent branch of the TFS branch to clone (TFS 2008 only! And required!!) ex: $/Repository/ProjectParentBranch", v => ParentBranch = v }, + { "u|username=", "TFS username", v => TfsUsername = v }, + { "p|password=", "TFS password", v => TfsPassword = v }, + { "a|authors=", "Path to an Authors file to map TFS users to Git users", v => AuthorsFilePath = v }, } .Merge(globals.OptionSet); } @@ -50,12 +61,26 @@ namespace Sep.Git.Tfs.Commands this.initBranch = initBranch; } + public void SetInitBranchParameters() { + initBranch.TfsUsername = TfsUsername; + initBranch.TfsPassword = TfsPassword; + initBranch.AuthorsFilePath = AuthorsFilePath; + initBranch.CloneAllBranches = ManageAll; + initBranch.ParentBranch = ParentBranch; + } + public int Run() { if (ShouldRenameRemote || ShouldDeleteRemote) return helper.Run(this); + if (ShouldInitBranch) + { + SetInitBranchParameters(); + return initBranch.Run(); + } + return DisplayBranchData(); } @@ -64,7 +89,10 @@ namespace Sep.Git.Tfs.Commands if (ShouldRenameRemote) return helper.Run(this); + if (ShouldInitBranch) { + SetInitBranchParameters(); + return initBranch.Run(param); } if (ShouldDeleteRemote) @@ -79,6 +107,12 @@ namespace Sep.Git.Tfs.Commands if (ShouldDeleteRemote) return helper.Run(this); + if (ShouldInitBranch) + { + SetInitBranchParameters(); + return initBranch.Run(param1, param2); + } + if (ShouldRenameRemote) return RenameRemote(param1, param2); @@ -144,7 +178,7 @@ namespace Sep.Git.Tfs.Commands var tfsRemotes = globals.Repository.ReadAllTfsRemotes(); if (DisplayRemotes) { - if (!DisplayAllRootRemotes) + if (!ManageAll) { var remote = globals.Repository.ReadTfsRemote(remoteId); diff --git a/GitTfs/Commands/InitBranch.cs b/GitTfs/Commands/InitBranch.cs index e70c9ffb..4745c973 100644 --- a/GitTfs/Commands/InitBranch.cs +++ b/GitTfs/Commands/InitBranch.cs @@ -26,14 +26,14 @@ namespace Sep.Git.Tfs.Commands public string TfsPassword { get; set; } public string ParentBranch { get; set; } public bool CloneAllBranches { get; set; } - string AuthorsFilePath { get; set; } + public string AuthorsFilePath { get; set; } public InitBranch(TextWriter stdout, Globals globals, Help helper, AuthorsFile authors) { - this._stdout = stdout; - this._globals = globals; - this._helper = helper; - this._authors = authors; + _stdout = stdout; + _globals = globals; + _helper = helper; + _authors = authors; } public OptionSet OptionSet @@ -87,7 +87,7 @@ namespace Sep.Git.Tfs.Commands if (defaultRemote.TfsRepositoryPath.ToLower() != rootBranch.Path.ToLower()) throw new GitTfsException(string.Format("error: Init all the branches is only possible when 'git tfs clone' was done from the trunk!!! Please clone again from '{0}'...", rootBranch.Path)); - var childBranchPaths = rootBranch.GetAllChildren().Select(b=>b.Path); + var childBranchPaths = rootBranch.GetAllChildren().Select(b=>b.Path).ToList(); _stdout.WriteLine("Tfs branches found:"); foreach (var tfsBranchPath in childBranchPaths) From e4c4776fb77597ffb14dd5276cf6e59543b886f9 Mon Sep 17 00:00:00 2001 From: Philippe Miossec Date: Sun, 3 Feb 2013 20:36:45 +0100 Subject: [PATCH 09/10] Control to detect bad command use --- GitTfs/Commands/Branch.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/GitTfs/Commands/Branch.cs b/GitTfs/Commands/Branch.cs index 79d7f295..20793df6 100644 --- a/GitTfs/Commands/Branch.cs +++ b/GitTfs/Commands/Branch.cs @@ -70,8 +70,17 @@ namespace Sep.Git.Tfs.Commands initBranch.ParentBranch = ParentBranch; } + public bool IsCommandWellUsed() + { + //Verify that some mutual exclusive options are not used together + return new[] {ShouldDeleteRemote, ShouldInitBranch, ShouldRenameRemote}.Count(b => b) <= 1; + } + public int Run() { + if (!IsCommandWellUsed()) + return helper.Run(this); + if (ShouldRenameRemote || ShouldDeleteRemote) return helper.Run(this); @@ -86,6 +95,9 @@ namespace Sep.Git.Tfs.Commands public int Run(string param) { + if (!IsCommandWellUsed()) + return helper.Run(this); + if (ShouldRenameRemote) return helper.Run(this); @@ -103,6 +115,8 @@ namespace Sep.Git.Tfs.Commands public int Run(string param1, string param2) { + if (!IsCommandWellUsed()) + return helper.Run(this); if (ShouldDeleteRemote) return helper.Run(this); From 2ca75950cba35d525d38358edff2675aa4113b81 Mon Sep 17 00:00:00 2001 From: Philippe Miossec Date: Sun, 3 Feb 2013 20:37:23 +0100 Subject: [PATCH 10/10] better `branch` command description --- GitTfs/Commands/Branch.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/GitTfs/Commands/Branch.cs b/GitTfs/Commands/Branch.cs index 20793df6..a1cfdab3 100644 --- a/GitTfs/Commands/Branch.cs +++ b/GitTfs/Commands/Branch.cs @@ -12,7 +12,12 @@ using StructureMap; namespace Sep.Git.Tfs.Commands { [Pluggable("branch")] - [Description("branch\n git tfs branch -r\n git tfs branch -r -all\n git tfs branch $/Repository/ProjectBranchToCreate \n git tfs branch --move oldTfsRemoteName newTfsRemoteName\n git tfs branch --delete tfsRemoteName\n")] + [Description("branch\n\n" + + " * Display remote TFS branches:\n git tfs branch -r\n git tfs branch -r -all\n\n" + + " * Create a TFS branch from current commit:\n git tfs branch $/Repository/ProjectBranchToCreate --comment=\"Creation of my branch\"\n\n" + + " * Rename a remote branch:\n git tfs branch --move oldTfsRemoteName newTfsRemoteName\n\n" + + " * Delete a remote branche:\n git tfs branch --delete tfsRemoteName\n\n" + + " * Initialise an existing remote TFS branch:\n git tfs --init $/Repository/ProjectBranch\n git tfs --init $/Repository/ProjectBranch myNewBranch\n git tfs --init --all\n git tfs --init --tfs-parent-branch=$/Repository/ProjectParentBranch $/Repository/ProjectBranch\n")] [RequiresValidGitRepository] public class Branch : GitTfsCommand {