Automatically Associate work items with a shelve command.
This commit is contained in:
@@ -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 ShelveSpecificCheckinOptionsFactory _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 ShelveSpecificCheckinOptionsFactory(_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
|
||||
? 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,6 +230,11 @@ namespace Sep.Git.Tfs.Core
|
||||
throw DerivedRemoteException;
|
||||
}
|
||||
|
||||
public void Shelve(string shelvesetName, string treeish, TfsChangesetInfo parentChangeset, CheckinOptions options, bool evaluateCheckinPolicies)
|
||||
{
|
||||
throw DerivedRemoteException;
|
||||
}
|
||||
|
||||
public void Shelve(string shelvesetName, string treeish, TfsChangesetInfo parentChangeset, bool evaluateCheckinPolicies)
|
||||
{
|
||||
throw DerivedRemoteException;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 head, 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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Sep.Git.Tfs.Commands;
|
||||
@@ -33,7 +34,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 +42,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)
|
||||
|
||||
@@ -202,6 +202,7 @@
|
||||
<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" />
|
||||
@@ -211,6 +212,7 @@
|
||||
<Compile Include="Util\GitTfsCommandFactory.cs" />
|
||||
<Compile Include="Util\GitTfsCommandRunner.cs" />
|
||||
<Compile Include="Core\IGitTfsVersionProvider.cs" />
|
||||
<Compile Include="Util\ShelveSpecificCheckinOptionsFactory.cs" />
|
||||
<Compile Include="Util\TemporaryFile.cs" />
|
||||
<Compile Include="Util\WhenDynamicDoesntWork.cs" />
|
||||
<Compile Include="Util\PluggableWithAliases.cs" />
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using Sep.Git.Tfs.Commands;
|
||||
using Sep.Git.Tfs.Core;
|
||||
|
||||
namespace Sep.Git.Tfs.Util
|
||||
{
|
||||
public static class CheckinOptionsExtensions
|
||||
{
|
||||
public static CheckinOptions Clone(this CheckinOptions source, Globals globals)
|
||||
{
|
||||
CheckinOptions clone = new CheckinOptions();
|
||||
|
||||
clone.CheckinComment = source.CheckinComment;
|
||||
clone.NoGenerateCheckinComment = source.NoGenerateCheckinComment;
|
||||
clone.NoMerge = source.NoMerge;
|
||||
clone.OverrideReason = source.OverrideReason;
|
||||
clone.Force = source.Force;
|
||||
clone.OverrideGatedCheckIn = source.OverrideGatedCheckIn;
|
||||
clone.WorkItemsToAssociate.AddRange(source.WorkItemsToAssociate);
|
||||
clone.WorkItemsToResolve.AddRange(source.WorkItemsToResolve);
|
||||
clone.AuthorTfsUserId = source.AuthorTfsUserId;
|
||||
try
|
||||
{
|
||||
string re = globals.Repository.GetConfig(GitTfsConstants.WorkItemAssociateRegexConfigKey);
|
||||
if (String.IsNullOrEmpty(re))
|
||||
clone.WorkItemAssociateRegex = GitTfsConstants.TfsWorkItemAssociateRegex;
|
||||
else
|
||||
clone.WorkItemAssociateRegex = new Regex(re);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
clone.WorkItemAssociateRegex = null;
|
||||
}
|
||||
foreach (var note in source.CheckinNotes)
|
||||
{
|
||||
clone.CheckinNotes[note.Key] = note.Value;
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
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 (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 {
|
||||
writer.WriteLine("Associating with work item {0}", match.Groups["item_id"]);
|
||||
checkinOptions.WorkItemsToAssociate.Add(match.Groups["item_id"].Value);
|
||||
}
|
||||
}
|
||||
checkinOptions.CheckinComment = GitTfsConstants.TfsWorkItemRegex.Replace(checkinOptions.CheckinComment, "").Trim(' ', '\r', '\n');
|
||||
}
|
||||
|
||||
if (checkinOptions.WorkItemAssociateRegex != null)
|
||||
{
|
||||
var workitemAssociatedMatches = checkinOptions.WorkItemAssociateRegex.Matches(checkinOptions.CheckinComment);
|
||||
if (workitemAssociatedMatches.Count != 0)
|
||||
{
|
||||
foreach (Match match in workitemAssociatedMatches)
|
||||
{
|
||||
var workitem = match.Groups["item_id"].Value;
|
||||
if (!checkinOptions.WorkItemsToAssociate.Contains(workitem))
|
||||
{
|
||||
writer.WriteLine("Associating with work item {0}", workitem);
|
||||
checkinOptions.WorkItemsToAssociate.Add(workitem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ProcessCheckinNoteCommands(this CheckinOptions checkinOptions, TextWriter writer)
|
||||
{
|
||||
foreach (Match match in GitTfsConstants.TfsReviewerRegex.Matches(checkinOptions.CheckinComment))
|
||||
{
|
||||
string reviewer = match.Groups["reviewer"].Value;
|
||||
if (!string.IsNullOrWhiteSpace(reviewer))
|
||||
{
|
||||
switch (match.Groups["type"].Value)
|
||||
{
|
||||
case "code":
|
||||
writer.WriteLine("Code reviewer: {0}", reviewer);
|
||||
checkinOptions.CheckinNotes.Add("Code Reviewer", reviewer);
|
||||
break;
|
||||
case "security":
|
||||
writer.WriteLine("Security reviewer: {0}", reviewer);
|
||||
checkinOptions.CheckinNotes.Add("Security Reviewer", reviewer);
|
||||
break;
|
||||
case "performance":
|
||||
writer.WriteLine("Performance reviewer: {0}", reviewer);
|
||||
checkinOptions.CheckinNotes.Add("Performance Reviewer", reviewer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
checkinOptions.CheckinComment = GitTfsConstants.TfsReviewerRegex.Replace(checkinOptions.CheckinComment, "").Trim(' ', '\r', '\n');
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void ProcessForceCommand(this CheckinOptions checkinOptions, TextWriter writer)
|
||||
{
|
||||
MatchCollection workitemMatches;
|
||||
if ((workitemMatches = GitTfsConstants.TfsForceRegex.Matches(checkinOptions.CheckinComment)).Count == 1)
|
||||
{
|
||||
string overrideReason = workitemMatches[0].Groups["reason"].Value;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(overrideReason))
|
||||
{
|
||||
writer.WriteLine("Forcing the checkin: {0}", overrideReason);
|
||||
checkinOptions.Force = true;
|
||||
checkinOptions.OverrideReason = overrideReason;
|
||||
}
|
||||
checkinOptions.CheckinComment = GitTfsConstants.TfsForceRegex.Replace(checkinOptions.CheckinComment, "").Trim(' ', '\r', '\n');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void ProcessAuthor(this CheckinOptions checkinOptions, TextWriter writer, GitCommit commit, AuthorsFile authors)
|
||||
{
|
||||
if (!authors.IsParseSuccessfull)
|
||||
return;
|
||||
|
||||
Author a = authors.FindAuthor(commit.AuthorAndEmail);
|
||||
if (a == null)
|
||||
{
|
||||
checkinOptions.AuthorTfsUserId = null;
|
||||
return;
|
||||
}
|
||||
|
||||
checkinOptions.AuthorTfsUserId = a.TfsUserId;
|
||||
writer.WriteLine("Commit was authored by git user {0} {1} ({2})", a.Name, a.Email, a.TfsUserId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Sep.Git.Tfs.Commands;
|
||||
using Sep.Git.Tfs.Core;
|
||||
using System.Text.RegularExpressions;
|
||||
using StructureMap;
|
||||
|
||||
namespace Sep.Git.Tfs.Util
|
||||
{
|
||||
@@ -19,181 +16,38 @@ namespace Sep.Git.Tfs.Util
|
||||
public class CommitSpecificCheckinOptionsFactory
|
||||
{
|
||||
private readonly TextWriter writer;
|
||||
private readonly AuthorsFile authors;
|
||||
private readonly Globals globals;
|
||||
private AuthorsFile authors;
|
||||
|
||||
public CommitSpecificCheckinOptionsFactory(TextWriter writer, Globals globals, AuthorsFile authors)
|
||||
{
|
||||
this.writer = writer;
|
||||
this.globals = globals;
|
||||
this.authors = authors;
|
||||
this.globals = globals;
|
||||
}
|
||||
|
||||
public CheckinOptions BuildCommitSpecificCheckinOptions(CheckinOptions sourceCheckinOptions, string commitMessage)
|
||||
{
|
||||
var customCheckinOptions = Clone(sourceCheckinOptions);
|
||||
var customCheckinOptions = sourceCheckinOptions.Clone(this.globals);
|
||||
|
||||
customCheckinOptions.CheckinComment = commitMessage;
|
||||
|
||||
ProcessWorkItemCommands(customCheckinOptions, writer);
|
||||
customCheckinOptions.ProcessWorkItemCommands(writer);
|
||||
|
||||
ProcessCheckinNoteCommands(customCheckinOptions, writer);
|
||||
customCheckinOptions.ProcessCheckinNoteCommands(writer);
|
||||
|
||||
ProcessForceCommand(customCheckinOptions, writer);
|
||||
customCheckinOptions.ProcessForceCommand(writer);
|
||||
|
||||
return customCheckinOptions;
|
||||
}
|
||||
|
||||
public CheckinOptions BuildCommitSpecificCheckinOptions(CheckinOptions sourceCheckinOptions, string commitMessage, GitCommit commit)
|
||||
{
|
||||
var customCheckinOptions = Clone(sourceCheckinOptions);
|
||||
var customCheckinOptions = BuildCommitSpecificCheckinOptions(sourceCheckinOptions, commitMessage);
|
||||
|
||||
customCheckinOptions.CheckinComment = commitMessage;
|
||||
|
||||
ProcessWorkItemCommands(customCheckinOptions, writer);
|
||||
|
||||
ProcessCheckinNoteCommands(customCheckinOptions, writer);
|
||||
|
||||
ProcessForceCommand(customCheckinOptions, writer);
|
||||
|
||||
ProcessAuthor(customCheckinOptions, writer, commit);
|
||||
customCheckinOptions.ProcessAuthor(writer, commit, authors);
|
||||
|
||||
return customCheckinOptions;
|
||||
}
|
||||
|
||||
private CheckinOptions Clone(CheckinOptions source)
|
||||
{
|
||||
CheckinOptions clone = new CheckinOptions();
|
||||
|
||||
clone.CheckinComment = source.CheckinComment;
|
||||
clone.NoGenerateCheckinComment = source.NoGenerateCheckinComment;
|
||||
clone.NoMerge = source.NoMerge;
|
||||
clone.OverrideReason = source.OverrideReason;
|
||||
clone.Force = source.Force;
|
||||
clone.OverrideGatedCheckIn = source.OverrideGatedCheckIn;
|
||||
clone.WorkItemsToAssociate.AddRange(source.WorkItemsToAssociate);
|
||||
clone.WorkItemsToResolve.AddRange(source.WorkItemsToResolve);
|
||||
clone.AuthorTfsUserId = source.AuthorTfsUserId;
|
||||
try
|
||||
{
|
||||
string re = globals.Repository.GetConfig(GitTfsConstants.WorkItemAssociateRegexConfigKey);
|
||||
if (String.IsNullOrEmpty(re))
|
||||
clone.WorkItemAssociateRegex = GitTfsConstants.TfsWorkItemAssociateRegex;
|
||||
else
|
||||
clone.WorkItemAssociateRegex = new Regex(re);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
clone.WorkItemAssociateRegex = null;
|
||||
}
|
||||
foreach (var note in source.CheckinNotes)
|
||||
{
|
||||
clone.CheckinNotes[note.Key] = note.Value;
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
private void ProcessWorkItemCommands(CheckinOptions checkinOptions, TextWriter writer)
|
||||
{
|
||||
MatchCollection workitemMatches;
|
||||
if ((workitemMatches = GitTfsConstants.TfsWorkItemRegex.Matches(checkinOptions.CheckinComment)).Count > 0)
|
||||
{
|
||||
foreach (Match match in workitemMatches)
|
||||
{
|
||||
if (match.Groups["action"].Value == "resolve")
|
||||
{
|
||||
writer.WriteLine("Resolving work item {0}", match.Groups["item_id"]);
|
||||
checkinOptions.WorkItemsToResolve.Add(match.Groups["item_id"].Value);
|
||||
}else{
|
||||
writer.WriteLine("Associating with work item {0}", match.Groups["item_id"]);
|
||||
checkinOptions.WorkItemsToAssociate.Add(match.Groups["item_id"].Value);
|
||||
}
|
||||
}
|
||||
checkinOptions.CheckinComment = GitTfsConstants.TfsWorkItemRegex.Replace(checkinOptions.CheckinComment, "").Trim(' ', '\r', '\n');
|
||||
}
|
||||
|
||||
if (checkinOptions.WorkItemAssociateRegex != null)
|
||||
{
|
||||
var workitemAssociatedMatches = checkinOptions.WorkItemAssociateRegex.Matches(checkinOptions.CheckinComment);
|
||||
if (workitemAssociatedMatches.Count != 0)
|
||||
{
|
||||
foreach (Match match in workitemAssociatedMatches)
|
||||
{
|
||||
var workitem = match.Groups["item_id"].Value;
|
||||
if (!checkinOptions.WorkItemsToAssociate.Contains(workitem))
|
||||
{
|
||||
writer.WriteLine("Associating with work item {0}", workitem);
|
||||
checkinOptions.WorkItemsToAssociate.Add(workitem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessCheckinNoteCommands(CheckinOptions checkinOptions, TextWriter writer)
|
||||
{
|
||||
foreach (Match match in GitTfsConstants.TfsReviewerRegex.Matches(checkinOptions.CheckinComment))
|
||||
{
|
||||
string reviewer = match.Groups["reviewer"].Value;
|
||||
if (!string.IsNullOrWhiteSpace(reviewer))
|
||||
{
|
||||
switch (match.Groups["type"].Value)
|
||||
{
|
||||
case "code":
|
||||
writer.WriteLine("Code reviewer: {0}", reviewer);
|
||||
checkinOptions.CheckinNotes.Add("Code Reviewer", reviewer);
|
||||
break;
|
||||
case "security":
|
||||
writer.WriteLine("Security reviewer: {0}", reviewer);
|
||||
checkinOptions.CheckinNotes.Add("Security Reviewer", reviewer);
|
||||
break;
|
||||
case "performance":
|
||||
writer.WriteLine("Performance reviewer: {0}", reviewer);
|
||||
checkinOptions.CheckinNotes.Add("Performance Reviewer", reviewer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
checkinOptions.CheckinComment = GitTfsConstants.TfsReviewerRegex.Replace(checkinOptions.CheckinComment, "").Trim(' ', '\r', '\n');
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void ProcessForceCommand(CheckinOptions checkinOptions, TextWriter writer)
|
||||
{
|
||||
MatchCollection workitemMatches;
|
||||
if ((workitemMatches = GitTfsConstants.TfsForceRegex.Matches(checkinOptions.CheckinComment)).Count == 1)
|
||||
{
|
||||
string overrideReason = workitemMatches[0].Groups["reason"].Value;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(overrideReason))
|
||||
{
|
||||
writer.WriteLine("Forcing the checkin: {0}", overrideReason);
|
||||
checkinOptions.Force = true;
|
||||
checkinOptions.OverrideReason = overrideReason;
|
||||
}
|
||||
checkinOptions.CheckinComment = GitTfsConstants.TfsForceRegex.Replace(checkinOptions.CheckinComment, "").Trim(' ', '\r', '\n');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void ProcessAuthor(CheckinOptions checkinOptions, TextWriter writer, GitCommit commit)
|
||||
{
|
||||
if (!authors.IsParseSuccessfull)
|
||||
return;
|
||||
|
||||
Author a = authors.FindAuthor(commit.AuthorAndEmail);
|
||||
if (a == null)
|
||||
{
|
||||
checkinOptions.AuthorTfsUserId = null;
|
||||
return;
|
||||
}
|
||||
|
||||
checkinOptions.AuthorTfsUserId = a.TfsUserId;
|
||||
writer.WriteLine("Commit was authored by git user {0} {1} ({2})", a.Name, a.Email, a.TfsUserId);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
using System.IO;
|
||||
using Sep.Git.Tfs.Commands;
|
||||
|
||||
namespace Sep.Git.Tfs.Util
|
||||
{
|
||||
public class ShelveSpecificCheckinOptionsFactory
|
||||
{
|
||||
private readonly TextWriter writer;
|
||||
private readonly Globals globals;
|
||||
|
||||
public ShelveSpecificCheckinOptionsFactory(TextWriter writer, Globals globals)
|
||||
{
|
||||
this.writer = writer;
|
||||
this.globals = globals;
|
||||
}
|
||||
|
||||
public CheckinOptions BuildShelveSetSpecificCheckinOptions(CheckinOptions sourceCheckinOptions,
|
||||
string commitMessage)
|
||||
{
|
||||
var customCheckinOptions = sourceCheckinOptions.Clone(this.globals);
|
||||
|
||||
customCheckinOptions.CheckinComment = commitMessage;
|
||||
|
||||
customCheckinOptions.ProcessWorkItemCommands(writer, false);
|
||||
|
||||
return customCheckinOptions;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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<ShelveSpecificCheckinOptionsFactory> mocks;
|
||||
|
||||
public ShelveSpecificCheckinOptionsFactoryTests()
|
||||
{
|
||||
mocks = new RhinoAutoMocker<ShelveSpecificCheckinOptionsFactory>();
|
||||
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 = GetShelveSpecificCheckinOptions().BuildShelveSetSpecificCheckinOptions(new CheckinOptions(), commitMessage);
|
||||
|
||||
Assert.Equal(1, specificCheckinOptions.WorkItemsToAssociate.Count);
|
||||
Assert.Contains("1234", specificCheckinOptions.WorkItemsToAssociate);
|
||||
Assert.Equal(expectedCheckinComment, specificCheckinOptions.CheckinComment);
|
||||
}
|
||||
|
||||
private ShelveSpecificCheckinOptionsFactory GetShelveSpecificCheckinOptions()
|
||||
{
|
||||
return new ShelveSpecificCheckinOptionsFactory(new StringWriter(), mocks.Get<Globals>());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,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
|
||||
|
||||
Reference in New Issue
Block a user