Merge pull request #912 from NathanLBCooper/master

Automatically Associate work items with a shelve command.
This commit is contained in:
Matt Burke
2016-02-08 13:36:23 -05:00
17 changed files with 196 additions and 106 deletions
+3 -3
View File
@@ -16,7 +16,7 @@ namespace Sep.Git.Tfs.Commands
{
private readonly TextWriter _stdout;
private readonly CheckinOptions _checkinOptions;
private readonly CommitSpecificCheckinOptionsFactory _checkinOptionsFactory;
private readonly CheckinOptionsFactory _checkinOptionsFactory;
private readonly TfsWriter _writer;
private readonly Globals _globals;
private readonly AuthorsFile _authors;
@@ -28,7 +28,7 @@ namespace Sep.Git.Tfs.Commands
{
_stdout = stdout;
_checkinOptions = checkinOptions;
_checkinOptionsFactory = new CommitSpecificCheckinOptionsFactory(_stdout, globals, authors);
_checkinOptionsFactory = new CheckinOptionsFactory(_stdout, globals);
_writer = writer;
_globals = globals;
_authors = authors;
@@ -131,7 +131,7 @@ namespace Sep.Git.Tfs.Commands
var parents = commit.Parents.Where(c => c.Sha != currentParent).ToArray();
string tfsRepositoryPathOfMergedBranch = FindTfsRepositoryPathOfMergedBranch(tfsRemote, parents, target);
var commitSpecificCheckinOptions = _checkinOptionsFactory.BuildCommitSpecificCheckinOptions(_checkinOptions, message, commit);
var commitSpecificCheckinOptions = _checkinOptionsFactory.BuildCommitSpecificCheckinOptions(_checkinOptions, message, commit, _authors);
_stdout.WriteLine("Starting checkin of {0} '{1}'", target.Substring(0, 8), commitSpecificCheckinOptions.CheckinComment);
try
+23 -2
View File
@@ -2,6 +2,7 @@
using System.IO;
using NDesk.Options;
using Sep.Git.Tfs.Core;
using Sep.Git.Tfs.Util;
using StructureMap;
namespace Sep.Git.Tfs.Commands
@@ -13,14 +14,18 @@ namespace Sep.Git.Tfs.Commands
{
private readonly TextWriter _stdout;
private readonly CheckinOptions _checkinOptions;
private readonly CheckinOptionsFactory _checkinOptionsFactory;
private readonly TfsWriter _writer;
private readonly Globals _globals;
private bool EvaluateCheckinPolicies { get; set; }
public Shelve(TextWriter stdout, CheckinOptions checkinOptions, TfsWriter writer)
public Shelve(TextWriter stdout, CheckinOptions checkinOptions, TfsWriter writer, Globals globals)
{
_stdout = stdout;
_globals = globals;
_checkinOptions = checkinOptions;
_checkinOptionsFactory = new CheckinOptionsFactory(_stdout, _globals);
_writer = writer;
}
@@ -52,9 +57,25 @@ namespace Sep.Git.Tfs.Commands
_stdout.WriteLine("Shelveset \"" + shelvesetName + "\" already exists. Use -f to replace it.");
return GitTfsExitCodes.ForceRequired;
}
changeset.Remote.Shelve(shelvesetName, referenceToShelve, changeset, EvaluateCheckinPolicies);
var commit = _globals.Repository.GetCommit(refToShelve);
var message = commit != null // this is only null in the unit tests
? BuildCommitMessage(commit, !_checkinOptions.NoGenerateCheckinComment,
changeset.Remote.MaxCommitHash)
: string.Empty;
var shelveSpecificCheckinOptions = _checkinOptionsFactory.BuildShelveSetSpecificCheckinOptions(_checkinOptions, message);
changeset.Remote.Shelve(shelvesetName, referenceToShelve, changeset, shelveSpecificCheckinOptions, EvaluateCheckinPolicies);
return GitTfsExitCodes.OK;
});
}
public string BuildCommitMessage(GitCommit commit, bool generateCheckinComment, string latest)
{
return generateCheckinComment
? _globals.Repository.GetCommitMessage(commit.Sha, latest)
: _globals.Repository.GetCommit(commit.Sha).Message;
}
}
}
+1 -1
View File
@@ -230,7 +230,7 @@ namespace Sep.Git.Tfs.Core
throw DerivedRemoteException;
}
public void Shelve(string shelvesetName, string treeish, TfsChangesetInfo parentChangeset, bool evaluateCheckinPolicies)
public void Shelve(string shelvesetName, string treeish, TfsChangesetInfo parentChangeset, CheckinOptions options, bool evaluateCheckinPolicies)
{
throw DerivedRemoteException;
}
+4 -4
View File
@@ -846,9 +846,9 @@ namespace Sep.Git.Tfs.Core
Repository.UpdateRef(destinationRef, commit, "Shelveset " + shelvesetName + " from " + shelvesetOwner);
}
public void Shelve(string shelvesetName, string head, TfsChangesetInfo parentChangeset, bool evaluateCheckinPolicies)
public void Shelve(string shelvesetName, string head, TfsChangesetInfo parentChangeset, CheckinOptions options, bool evaluateCheckinPolicies)
{
WithWorkspace(parentChangeset, workspace => Shelve(shelvesetName, head, parentChangeset, evaluateCheckinPolicies, workspace));
WithWorkspace(parentChangeset, workspace => Shelve(shelvesetName, head, parentChangeset, options, evaluateCheckinPolicies, workspace));
}
public bool HasShelveset(string shelvesetName)
@@ -856,10 +856,10 @@ namespace Sep.Git.Tfs.Core
return Tfs.HasShelveset(shelvesetName);
}
private void Shelve(string shelvesetName, string head, TfsChangesetInfo parentChangeset, bool evaluateCheckinPolicies, ITfsWorkspace workspace)
private void Shelve(string shelvesetName, string head, TfsChangesetInfo parentChangeset, CheckinOptions options, bool evaluateCheckinPolicies, ITfsWorkspace workspace)
{
PendChangesToWorkspace(head, parentChangeset.GitCommit, workspace);
workspace.Shelve(shelvesetName, evaluateCheckinPolicies, () => Repository.GetCommitMessage(head, parentChangeset.GitCommit));
workspace.Shelve(shelvesetName, evaluateCheckinPolicies, options);
}
public int CheckinTool(string head, TfsChangesetInfo parentChangeset)
+1 -1
View File
@@ -56,7 +56,7 @@ namespace Sep.Git.Tfs.Core
void QuickFetch();
void QuickFetch(int changesetId);
void Unshelve(string shelvesetOwner, string shelvesetName, string destinationBranch, Action<Exception> ignorableErrorHandler, bool force);
void Shelve(string shelvesetName, string treeish, TfsChangesetInfo parentChangeset, bool evaluateCheckinPolicies);
void Shelve(string shelvesetName, string treeish, TfsChangesetInfo parentChangeset, CheckinOptions options, bool evaluateCheckinPolicies);
bool HasShelveset(string shelvesetName);
int CheckinTool(string head, TfsChangesetInfo parentChangeset);
int Checkin(string treeish, TfsChangesetInfo parentChangeset, CheckinOptions options, string sourceTfsPath = null);
+1 -1
View File
@@ -25,7 +25,7 @@ namespace Sep.Git.Tfs.Core
/// <summary>
/// Shelves all pending changes, with the given shelveset name.
/// </summary>
void Shelve(string shelvesetName, bool evaluateCheckinPolicies, Func<string> generateCheckinComment);
void Shelve(string shelvesetName, bool evaluateCheckinPolicies, CheckinOptions checkinOptions);
/// <summary>
/// Evaluates check-in policies and checks in all pending changes.
/// </summary>
+3 -3
View File
@@ -33,7 +33,7 @@ namespace Sep.Git.Tfs.Core
this.Remote = remote;
}
public void Shelve(string shelvesetName, bool evaluateCheckinPolicies, Func<string> generateCheckinComment)
public void Shelve(string shelvesetName, bool evaluateCheckinPolicies, CheckinOptions checkinOptions)
{
var pendingChanges = _workspace.GetPendingChanges();
@@ -41,8 +41,8 @@ namespace Sep.Git.Tfs.Core
throw new GitTfsException("Nothing to shelve!");
var shelveset = _tfsHelper.CreateShelveset(_workspace, shelvesetName);
shelveset.Comment = string.IsNullOrWhiteSpace(_checkinOptions.CheckinComment) && !_checkinOptions.NoGenerateCheckinComment ? generateCheckinComment() : _checkinOptions.CheckinComment;
shelveset.WorkItemInfo = GetWorkItemInfos().ToArray();
shelveset.Comment = checkinOptions.CheckinComment;
shelveset.WorkItemInfo = GetWorkItemInfos(checkinOptions).ToArray();
if (evaluateCheckinPolicies)
{
foreach (var message in _policyEvaluator.EvaluateCheckin(_workspace, pendingChanges, shelveset.Comment, null, shelveset.WorkItemInfo).Messages)
+2 -1
View File
@@ -202,10 +202,11 @@
<Compile Include="Util\AuthorsFile.cs" />
<Compile Include="Util\Bouncer.cs" />
<Compile Include="Util\ChangeSieve.cs" />
<Compile Include="Util\CheckinOptionsExtensions.cs" />
<Compile Include="Util\ConfigPropertyLoader.cs" />
<Compile Include="Util\ExportMetadatasInitializer.cs" />
<Compile Include="Util\PathResolver.cs" />
<Compile Include="Util\CommitSpecificCheckinOptionsFactory.cs" />
<Compile Include="Util\CheckinOptionsFactory.cs" />
<Compile Include="Core\GitTfsVersionProvider.cs" />
<Compile Include="Util\ExceptionFormattingExtensions.cs" />
<Compile Include="Util\GitTfsCommandFactory.cs" />
@@ -1,67 +1,14 @@
using System;
using System;
using System.IO;
using System.Text.RegularExpressions;
using Sep.Git.Tfs.Commands;
using Sep.Git.Tfs.Core;
using System.Text.RegularExpressions;
using StructureMap;
namespace Sep.Git.Tfs.Util
{
/// <summary>
/// Creates a new <see cref="CheckinOptions"/> that is customized based
/// on extracting special git-tfs commands from a git commit message.
/// </summary>
/// <remarks>
/// This class handles the pre-checkin commit message parsing that
/// enables special git-tfs commands:
/// https://github.com/git-tfs/git-tfs/blob/master/doc/Special-actions-in-commit-messages.md
/// </remarks>
public class CommitSpecificCheckinOptionsFactory
public static class CheckinOptionsExtensions
{
private readonly TextWriter writer;
private readonly Globals globals;
private AuthorsFile authors;
public CommitSpecificCheckinOptionsFactory(TextWriter writer, Globals globals, AuthorsFile authors)
{
this.writer = writer;
this.globals = globals;
this.authors = authors;
}
public CheckinOptions BuildCommitSpecificCheckinOptions(CheckinOptions sourceCheckinOptions, string commitMessage)
{
var customCheckinOptions = Clone(sourceCheckinOptions);
customCheckinOptions.CheckinComment = commitMessage;
ProcessWorkItemCommands(customCheckinOptions, writer);
ProcessCheckinNoteCommands(customCheckinOptions, writer);
ProcessForceCommand(customCheckinOptions, writer);
return customCheckinOptions;
}
public CheckinOptions BuildCommitSpecificCheckinOptions(CheckinOptions sourceCheckinOptions, string commitMessage, GitCommit commit)
{
var customCheckinOptions = Clone(sourceCheckinOptions);
customCheckinOptions.CheckinComment = commitMessage;
ProcessWorkItemCommands(customCheckinOptions, writer);
ProcessCheckinNoteCommands(customCheckinOptions, writer);
ProcessForceCommand(customCheckinOptions, writer);
ProcessAuthor(customCheckinOptions, writer, commit);
return customCheckinOptions;
}
private CheckinOptions Clone(CheckinOptions source)
public static CheckinOptions Clone(this CheckinOptions source, Globals globals)
{
CheckinOptions clone = new CheckinOptions();
@@ -94,18 +41,19 @@ namespace Sep.Git.Tfs.Util
return clone;
}
private void ProcessWorkItemCommands(CheckinOptions checkinOptions, TextWriter writer)
public static void ProcessWorkItemCommands(this CheckinOptions checkinOptions, TextWriter writer, bool isResolvable = true)
{
MatchCollection workitemMatches;
if ((workitemMatches = GitTfsConstants.TfsWorkItemRegex.Matches(checkinOptions.CheckinComment)).Count > 0)
{
foreach (Match match in workitemMatches)
{
if (match.Groups["action"].Value == "resolve")
if (isResolvable && match.Groups["action"].Value == "resolve")
{
writer.WriteLine("Resolving work item {0}", match.Groups["item_id"]);
checkinOptions.WorkItemsToResolve.Add(match.Groups["item_id"].Value);
}else{
}
else {
writer.WriteLine("Associating with work item {0}", match.Groups["item_id"]);
checkinOptions.WorkItemsToAssociate.Add(match.Groups["item_id"].Value);
}
@@ -131,7 +79,7 @@ namespace Sep.Git.Tfs.Util
}
}
private void ProcessCheckinNoteCommands(CheckinOptions checkinOptions, TextWriter writer)
public static void ProcessCheckinNoteCommands(this CheckinOptions checkinOptions, TextWriter writer)
{
foreach (Match match in GitTfsConstants.TfsReviewerRegex.Matches(checkinOptions.CheckinComment))
{
@@ -160,7 +108,7 @@ namespace Sep.Git.Tfs.Util
private void ProcessForceCommand(CheckinOptions checkinOptions, TextWriter writer)
public static void ProcessForceCommand(this CheckinOptions checkinOptions, TextWriter writer)
{
MatchCollection workitemMatches;
if ((workitemMatches = GitTfsConstants.TfsForceRegex.Matches(checkinOptions.CheckinComment)).Count == 1)
@@ -179,7 +127,7 @@ namespace Sep.Git.Tfs.Util
private void ProcessAuthor(CheckinOptions checkinOptions, TextWriter writer, GitCommit commit)
public static void ProcessAuthor(this CheckinOptions checkinOptions, TextWriter writer, GitCommit commit, AuthorsFile authors)
{
if (!authors.IsParseSuccessfull)
return;
@@ -194,6 +142,5 @@ namespace Sep.Git.Tfs.Util
checkinOptions.AuthorTfsUserId = a.TfsUserId;
writer.WriteLine("Commit was authored by git user {0} {1} ({2})", a.Name, a.Email, a.TfsUserId);
}
}
}
+64
View File
@@ -0,0 +1,64 @@
using System.IO;
using Sep.Git.Tfs.Commands;
using Sep.Git.Tfs.Core;
namespace Sep.Git.Tfs.Util
{
/// <summary>
/// Creates a new <see cref="CheckinOptions"/> that is customized based
/// on extracting special git-tfs commands from a git commit message.
/// </summary>
/// <remarks>
/// This class handles the pre-checkin commit message parsing that
/// enables special git-tfs commands:
/// https://github.com/git-tfs/git-tfs/blob/master/doc/Special-actions-in-commit-messages.md
/// </remarks>
public class CheckinOptionsFactory
{
private readonly TextWriter writer;
private readonly Globals globals;
public CheckinOptionsFactory(TextWriter writer, Globals globals)
{
this.writer = writer;
this.globals = globals;
}
public CheckinOptions BuildCommitSpecificCheckinOptions(CheckinOptions sourceCheckinOptions, string commitMessage)
{
var customCheckinOptions = sourceCheckinOptions.Clone(this.globals);
customCheckinOptions.CheckinComment = commitMessage;
customCheckinOptions.ProcessWorkItemCommands(writer);
customCheckinOptions.ProcessCheckinNoteCommands(writer);
customCheckinOptions.ProcessForceCommand(writer);
return customCheckinOptions;
}
public CheckinOptions BuildCommitSpecificCheckinOptions(CheckinOptions sourceCheckinOptions,
string commitMessage, GitCommit commit, AuthorsFile authors)
{
var customCheckinOptions = BuildCommitSpecificCheckinOptions(sourceCheckinOptions, commitMessage);
customCheckinOptions.ProcessAuthor(writer, commit, authors);
return customCheckinOptions;
}
public CheckinOptions BuildShelveSetSpecificCheckinOptions(CheckinOptions sourceCheckinOptions,
string commitMessage)
{
var customCheckinOptions = sourceCheckinOptions.Clone(this.globals);
customCheckinOptions.CheckinComment = commitMessage;
customCheckinOptions.ProcessWorkItemCommands(writer, false);
return customCheckinOptions;
}
}
}
+6 -6
View File
@@ -118,8 +118,8 @@ namespace Sep.Git.Tfs.Test.Commands
mocks.ClassUnderTest.Run("shelveset name");
remote.AssertWasCalled(x => x.Shelve(null, null, null, false),
y => y.Constraints(Is.Equal("shelveset name"), Is.Equal("HEAD"), Is.Anything(), Is.Anything()));
remote.AssertWasCalled(x => x.Shelve(null, null, null, null, false),
y => y.Constraints(Is.Equal("shelveset name"), Is.Equal("HEAD"), Is.Anything(), Is.Anything(), Is.Anything()));
}
[Fact]
@@ -135,8 +135,8 @@ namespace Sep.Git.Tfs.Test.Commands
mocks.ClassUnderTest.Run("shelveset name", "treeish");
remote.AssertWasCalled(x => x.Shelve(null, null, null, false),
y => y.Constraints(Is.Equal("shelveset name"), Is.Equal("treeish"), Is.Anything(), Is.Anything()));
remote.AssertWasCalled(x => x.Shelve(null, null, null, null, false),
y => y.Constraints(Is.Equal("shelveset name"), Is.Equal("treeish"), Is.Anything(), Is.Anything(), Is.Anything()));
}
[Fact]
@@ -158,7 +158,7 @@ namespace Sep.Git.Tfs.Test.Commands
mocks.ClassUnderTest.Run("shelveset name", "treeish");
mocks.Get<IGitTfsRemote>().AssertWasNotCalled(
x => x.Shelve(Arg<string>.Is.Anything, Arg<string>.Is.Anything, Arg<TfsChangesetInfo>.Is.Anything, Arg<bool>.Is.Anything));
x => x.Shelve(Arg<string>.Is.Anything, Arg<string>.Is.Anything, Arg<TfsChangesetInfo>.Is.Anything, Arg<CheckinOptions>.Is.Anything, Arg<bool>.Is.Anything));
}
[Fact]
@@ -171,7 +171,7 @@ namespace Sep.Git.Tfs.Test.Commands
mocks.ClassUnderTest.Run("shelveset name", "treeish");
mocks.Get<IGitTfsRemote>().AssertWasCalled(
x => x.Shelve(Arg<string>.Is.Anything, Arg<string>.Is.Anything, Arg<TfsChangesetInfo>.Is.Anything, Arg<bool>.Is.Anything));
x => x.Shelve(Arg<string>.Is.Anything, Arg<string>.Is.Anything, Arg<TfsChangesetInfo>.Is.Anything, Arg<CheckinOptions>.Is.Anything, Arg<bool>.Is.Anything));
}
private TfsChangesetInfo ChangesetForRemote(string remoteId)
+1
View File
@@ -136,6 +136,7 @@
<Compile Include="Util\CommitSpecificCheckinOptionsFactoryTests.cs" />
<Compile Include="Util\GitTfsCommandRunnerTests.cs" />
<Compile Include="Util\BouncerTest.cs" />
<Compile Include="Util\ShelveSpecificCheckinOptionsFactoryTests.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\GitTfs.VsFake\GitTfs.VsFake.csproj">
@@ -12,15 +12,15 @@ namespace Sep.Git.Tfs.Test.Util
{
public class CommitSpecificCheckinOptionsFactoryTests
{
private RhinoAutoMocker<CommitSpecificCheckinOptionsFactory> mocks;
private RhinoAutoMocker<CheckinOptionsFactory> mocks;
public CommitSpecificCheckinOptionsFactoryTests()
{
mocks = new RhinoAutoMocker<CommitSpecificCheckinOptionsFactory>();
mocks = new RhinoAutoMocker<CheckinOptionsFactory>();
mocks.Get<Globals>().Repository = mocks.Get<IGitRepository>();
}
private CommitSpecificCheckinOptionsFactory GetCommitSpecificCheckinOptions(string workItemRegex = null)
private CheckinOptionsFactory GetCheckinOptionsFactory(string workItemRegex = null)
{
IGitRepository gitRepository = mocks.Get<IGitRepository>();
mocks.Get<Globals>().Repository = gitRepository;
@@ -28,7 +28,7 @@ namespace Sep.Git.Tfs.Test.Util
gitRepository.Stub(r => r.GitDir).Return(".");
gitRepository.Stub(r => r.GetConfig(GitTfsConstants.WorkItemAssociateRegexConfigKey)).Return(workItemRegex);
return new CommitSpecificCheckinOptionsFactory(new StringWriter(), mocks.Get<Globals>(), new AuthorsFile());
return new CheckinOptionsFactory(new StringWriter(), mocks.Get<Globals>());
}
[Fact]
@@ -44,7 +44,7 @@ namespace Sep.Git.Tfs.Test.Util
formatted git commit message";
var specificCheckinOptions = GetCommitSpecificCheckinOptions().BuildCommitSpecificCheckinOptions(singletonCheckinOptions, commitMessage);
var specificCheckinOptions = GetCheckinOptionsFactory().BuildCommitSpecificCheckinOptions(singletonCheckinOptions, commitMessage);
Assert.Equal(commitMessage, specificCheckinOptions.CheckinComment);
}
@@ -63,7 +63,7 @@ namespace Sep.Git.Tfs.Test.Util
";
var specificCheckinOptions = GetCommitSpecificCheckinOptions().BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
var specificCheckinOptions = GetCheckinOptionsFactory().BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
Assert.Equal(1, specificCheckinOptions.WorkItemsToAssociate.Count);
Assert.Contains("1234", specificCheckinOptions.WorkItemsToAssociate);
@@ -78,7 +78,7 @@ namespace Sep.Git.Tfs.Test.Util
git-tfs-work-item: 1234";
var specificCheckinOptions = GetCommitSpecificCheckinOptions().BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
var specificCheckinOptions = GetCheckinOptionsFactory().BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
Assert.Equal(1, specificCheckinOptions.WorkItemsToAssociate.Count);
}
@@ -87,7 +87,7 @@ namespace Sep.Git.Tfs.Test.Util
{
string commitMessage = @"test workitem #5676";
var specificCheckinOptions = GetCommitSpecificCheckinOptions().BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
var specificCheckinOptions = GetCheckinOptionsFactory().BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
Assert.Equal(1, specificCheckinOptions.WorkItemsToAssociate.Count);
Assert.Contains("5676", specificCheckinOptions.WorkItemsToAssociate);
}
@@ -97,7 +97,7 @@ namespace Sep.Git.Tfs.Test.Util
{
string commitMessage = @"test workitem #5676";
var specificCheckinOptions = GetCommitSpecificCheckinOptions(@"workitem id:(?<item_id>\d+)").BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
var specificCheckinOptions = GetCheckinOptionsFactory(@"workitem id:(?<item_id>\d+)").BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
Assert.Equal(0, specificCheckinOptions.WorkItemsToAssociate.Count);
}
@@ -106,7 +106,7 @@ namespace Sep.Git.Tfs.Test.Util
{
string commitMessage = @"test workitem id:5676";
var specificCheckinOptions = GetCommitSpecificCheckinOptions(@"workitem id:(?<item_id>\d+)").BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
var specificCheckinOptions = GetCheckinOptionsFactory(@"workitem id:(?<item_id>\d+)").BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
Assert.Equal(1, specificCheckinOptions.WorkItemsToAssociate.Count);
Assert.Contains("5676", specificCheckinOptions.WorkItemsToAssociate);
}
@@ -116,7 +116,7 @@ namespace Sep.Git.Tfs.Test.Util
{
string commitMessage = @"test workitem #5676";
var specificCheckinOptions = GetCommitSpecificCheckinOptions(@"workitem id:((?<item_id>\d+)").BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
var specificCheckinOptions = GetCheckinOptionsFactory(@"workitem id:((?<item_id>\d+)").BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
Assert.Equal(0, specificCheckinOptions.WorkItemsToAssociate.Count);
}
@@ -125,7 +125,7 @@ namespace Sep.Git.Tfs.Test.Util
{
string commitMessage = @"test workitem #5676";
var specificCheckinOptions = GetCommitSpecificCheckinOptions(@"").BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
var specificCheckinOptions = GetCheckinOptionsFactory(@"").BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
Assert.Equal(1, specificCheckinOptions.WorkItemsToAssociate.Count);
Assert.Contains("5676", specificCheckinOptions.WorkItemsToAssociate);
}
@@ -135,7 +135,7 @@ namespace Sep.Git.Tfs.Test.Util
{
string commitMessage = @"test workitem #56p76";
var specificCheckinOptions = GetCommitSpecificCheckinOptions().BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
var specificCheckinOptions = GetCheckinOptionsFactory().BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
Assert.Equal(1, specificCheckinOptions.WorkItemsToAssociate.Count);
Assert.Contains("56", specificCheckinOptions.WorkItemsToAssociate);
}
@@ -145,7 +145,7 @@ namespace Sep.Git.Tfs.Test.Util
{
string commitMessage = @"test workitem #f5676";
var specificCheckinOptions = GetCommitSpecificCheckinOptions().BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
var specificCheckinOptions = GetCheckinOptionsFactory().BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
Assert.Equal(0, specificCheckinOptions.WorkItemsToAssociate.Count);
}
@@ -155,7 +155,7 @@ namespace Sep.Git.Tfs.Test.Util
string commitMessage = @"test workitem #5676 1 only
git-tfs-work-item: 1234";
var specificCheckinOptions = GetCommitSpecificCheckinOptions().BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
var specificCheckinOptions = GetCheckinOptionsFactory().BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
Assert.Equal(2, specificCheckinOptions.WorkItemsToAssociate.Count);
Assert.Contains("1234", specificCheckinOptions.WorkItemsToAssociate);
Assert.Contains("5676", specificCheckinOptions.WorkItemsToAssociate);
@@ -167,7 +167,7 @@ namespace Sep.Git.Tfs.Test.Util
string commitMessage = @"test workitem #5676
git-tfs-work-item: 5676";
var specificCheckinOptions = GetCommitSpecificCheckinOptions().BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
var specificCheckinOptions = GetCheckinOptionsFactory().BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
Assert.Equal(1, specificCheckinOptions.WorkItemsToAssociate.Count);
Assert.Contains("5676", specificCheckinOptions.WorkItemsToAssociate);
}
@@ -187,7 +187,7 @@ namespace Sep.Git.Tfs.Test.Util
";
var specificCheckinOptions = GetCommitSpecificCheckinOptions().BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
var specificCheckinOptions = GetCheckinOptionsFactory().BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
Assert.Equal(1, specificCheckinOptions.WorkItemsToResolve.Count);
Assert.Contains("1234", specificCheckinOptions.WorkItemsToResolve);
Assert.Equal(expectedCheckinComment.Replace(Environment.NewLine, "NEWLINE"), specificCheckinOptions.CheckinComment.Replace(Environment.NewLine, "NEWLINE"));
@@ -211,7 +211,7 @@ namespace Sep.Git.Tfs.Test.Util
";
var specificCheckinOptions = GetCommitSpecificCheckinOptions().BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
var specificCheckinOptions = GetCheckinOptionsFactory().BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
Assert.Equal(1, specificCheckinOptions.WorkItemsToResolve.Count);
Assert.Equal(1, specificCheckinOptions.WorkItemsToAssociate.Count);
Assert.Contains("1234", specificCheckinOptions.WorkItemsToResolve);
@@ -238,7 +238,7 @@ namespace Sep.Git.Tfs.Test.Util
"Some more information,\n" +
"in a paragraph.";
var specificCheckinOptions = GetCommitSpecificCheckinOptions().BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
var specificCheckinOptions = GetCheckinOptionsFactory().BuildCommitSpecificCheckinOptions(new CheckinOptions(), commitMessage);
Assert.Equal(3, specificCheckinOptions.CheckinNotes.Count);
Assert.Equal("John Smith", specificCheckinOptions.CheckinNotes["Code Reviewer"]);
Assert.Equal("Teddy Knox", specificCheckinOptions.CheckinNotes["Security Reviewer"]);
@@ -0,0 +1,47 @@
using System.IO;
using Sep.Git.Tfs.Commands;
using Sep.Git.Tfs.Core;
using Sep.Git.Tfs.Util;
using StructureMap.AutoMocking;
using Xunit;
namespace Sep.Git.Tfs.Test.Util
{
public class ShelveSpecificCheckinOptionsFactoryTests
{
private RhinoAutoMocker<CheckinOptionsFactory> mocks;
public ShelveSpecificCheckinOptionsFactoryTests()
{
mocks = new RhinoAutoMocker<CheckinOptionsFactory>();
mocks.Get<Globals>().Repository = mocks.Get<IGitRepository>();
}
[Fact]
public void Adds_work_item_to_associate_and_removes_checkin_command_comment()
{
string commitMessage = @"test message
formatted git commit message
git-tfs-work-item: 1234 associate";
string expectedCheckinComment = @"test message
formatted git commit message
";
var specificCheckinOptions = GetCheckinOptionsFactory().BuildShelveSetSpecificCheckinOptions(new CheckinOptions(), commitMessage);
Assert.Equal(1, specificCheckinOptions.WorkItemsToAssociate.Count);
Assert.Contains("1234", specificCheckinOptions.WorkItemsToAssociate);
Assert.Equal(expectedCheckinComment, specificCheckinOptions.CheckinComment);
}
private CheckinOptionsFactory GetCheckinOptionsFactory()
{
return new CheckinOptionsFactory(new StringWriter(), mocks.Get<Globals>());
}
}
}
+4
View File
@@ -1,6 +1,10 @@
## Summary
Creates a TFS shelveset from a Git branch.
## Features
[Special actions in commit messages](../special-actions-in-commit-messages.md) can be inserted, to associate TFS work items.
## Synopsis
Usage: git-tfs shelve [options] shelveset-name [ref-to-shelve]
where options are:
+1
View File
@@ -0,0 +1 @@
* Shelve commands can be automatically associated with work items (#908)
+5 -1
View File
@@ -1,4 +1,4 @@
The [rcheckin](commands/rcheckin.md) command examines the commmit message for additional TFS specific
The [rcheckin](commands/rcheckin.md) command examines the commit message for additional TFS specific
notifications. The following may be appended as separate lines to the end of the commit message:
* `git-tfs-work-item: <id>` will link the new changeset with the given work item and the default action type.
@@ -8,6 +8,10 @@ notifications. The following may be appended as separate lines to the end of the
* `git-tfs-performance-reviewer: <name>` sets the Performance Reviewer field.
* `git-tfs-force: <reason>` will force the checkin, overriding TFS checkin policies with the given reason.
The [shelve](commands/shelve.md) command also examines the commit message for the following TFS specific notifications, in the same matter as the rcheckin command:
* `git-tfs-work-item: <id>` will link the new changeset with the given work item and the default action type.
Additionally the text of the message is searched for work item IDs. If a string matching a # followed
by a valid work-item ID number is found, then the commit will be associated with the specified TFS work-item.
For cases where this may be undesirable, the default match may be overridden by setting the