Filter case-only file renames, as they cannot be applied in tfs. (#1063)

This commit is contained in:
EdorianDark
2017-04-25 23:48:24 +02:00
committed by Philippe Miossec
parent f6930c3697
commit 4e9a5a0312
2 changed files with 153 additions and 2 deletions
+54 -2
View File
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using StructureMap;
@@ -11,6 +12,7 @@ namespace Sep.Git.Tfs.Core
{
public class GitChangeInfo
{
const string ElementToRemove = "[ElementToRemove]";
public struct ChangeType
{
public const string ADD = "A";
@@ -46,6 +48,7 @@ namespace Sep.Git.Tfs.Core
public static IEnumerable<GitChangeInfo> GetChangedFiles(TextReader reader)
{
string line;
var changes = new List<GitChangeInfo>();
while (null != (line = GetDiffTreeLine(reader)))
{
var change = Parse(line);
@@ -53,10 +56,58 @@ namespace Sep.Git.Tfs.Core
if (FileMode.GitLink == change.NewMode)
continue;
yield return change;
changes.Add(change);
}
return FilterChangesIntroducedByCaseRenaming(changes);
}
/// <summary>
/// Filter changes made when renames are "case only" because such changes are not supported by TFS
/// </summary>
/// <param name="changes">changes to filter</param>
/// <returns>changes once filtered</returns>
private static IEnumerable<GitChangeInfo> FilterChangesIntroducedByCaseRenaming(IEnumerable<GitChangeInfo> changes)
{
//filter out "case only renames" because they cannot be represented in TFS
var remainingChanges = changes.Where(change => change.Status != ChangeType.RENAMEEDIT ||
String.Compare(change.path, change.pathTo, StringComparison.OrdinalIgnoreCase) != 0 ||
change.newSha != change.oldSha).ToList();
UpdateChangeStatusForCaseOnlyRenames(remainingChanges);
UpdateChangeStatusForAddedAndDeletedCaseOnlyRenames(remainingChanges);
return remainingChanges.Where(c => c.Status != ElementToRemove);
}
private static void UpdateChangeStatusForCaseOnlyRenames(List<GitChangeInfo> remainingChanges)
{
foreach (var change in remainingChanges.Where(c => c.Status == ChangeType.RENAMEEDIT))
{
if (String.Compare(change.path, change.pathTo, StringComparison.OrdinalIgnoreCase) == 0)
{
change.Status = ChangeType.MODIFY;
}
}
}
private static void UpdateChangeStatusForAddedAndDeletedCaseOnlyRenames(List<GitChangeInfo> remainingChanges)
{
var deletes = remainingChanges.Where(c => c.Status == ChangeType.DELETE).ToArray();
foreach (var addChange in remainingChanges.Where(c => c.Status == ChangeType.ADD))
{
//change adds to renameedit, if the file name is the same as a delete
var matchingDelete = deletes.FirstOrDefault(
d => String.Equals(addChange.path, d.path, StringComparison.OrdinalIgnoreCase));
if (matchingDelete != null)
{
addChange.Status = addChange.newSha != matchingDelete.oldSha ? ChangeType.MODIFY : ElementToRemove;
matchingDelete.Status = ElementToRemove;
}
}
}
private static string GetDiffTreeLine(TextReader reader)
{
var sb = new StringBuilder();
@@ -121,14 +172,15 @@ namespace Sep.Git.Tfs.Core
}
private readonly Match _match;
public string Status { get; set; }
private GitChangeInfo(Match match)
{
_match = match;
Status = _match.Groups["status"].Value;
}
public LibGit2Sharp.Mode NewMode { get { return _match.Groups["dstmode"].Value.ToFileMode(); } }
public string Status { get { return _match.Groups["status"].Value; } }
public string oldMode { get { return _match.Groups["srcmode"].Value; } }
public string newMode { get { return _match.Groups["dstmode"].Value; } }
+99
View File
@@ -245,5 +245,104 @@ namespace Sep.Git.Tfs.Test.Core
Assert.Equal("TestFiles/試し4.txt", changes[4].path);
}
}
[Fact]
public void ShouldDetectNormalRename_AndReturnOneRenameChange()
{
string input = ":100644 100644 ab6422c94fcb11e61378a231b0f3ce36958206d4 bb6422c94fcb11e61378a231b0f3ce36958206d4 R100\0TestFiles/Test0.txt\0TestFiles/Test_moved.txt\0";
using (var reader = new System.IO.StringReader(input))
{
var changes = GitChangeInfo.GetChangedFiles(reader).ToArray();
Assert.Equal(1, changes.Length);
Assert.Equal("R", changes[0].Status);
Assert.Equal("TestFiles/Test_moved.txt", changes[0].pathTo);
}
}
[Fact]
public void ShouldDetectCaseOnlyRenameWithNoContentChange_AndReturnNoChanges()
{
string input = ":100644 100644 fb6422c94fcb11e61378a231b0f3ce36958206d4 fb6422c94fcb11e61378a231b0f3ce36958206d4 R100\0TestFiles/Test2.txt\0TestFiles/test2.txt\0";
using (var reader = new System.IO.StringReader(input))
{
var changes = GitChangeInfo.GetChangedFiles(reader).ToArray();
Assert.Empty(changes);
}
}
[Fact]
public void ShouldDetectCaseOnlyRenameWithContentChange_AndReturnOneModificationChanges()
{
string input = ":100644 100644 aaaac94fcb11e61378a231b0f3ce36958206d4dd bbbb22c94fcb11e61378a231b0f3ce36958206d4 R100\0TestFiles/Test1.txt\0TestFiles/test1.txt\0";
using (var reader = new System.IO.StringReader(input))
{
var changes = GitChangeInfo.GetChangedFiles(reader).ToArray();
Assert.Equal(1, changes.Length);
Assert.Equal("M", changes[0].Status);
Assert.Equal("TestFiles/Test1.txt", changes[0].path);
}
}
[Fact]
public void ShouldDetectAddDeleteCorrespondingToCaseRenameWithContentChange_AndReturnOneModificationChange()
{
string input =
":000000 100644 0000000000000000000000000000000000000000 ed61b923604692e7c8b14763bd94412f471d91cc A\0TestFiles/Test0.txt\0" +
":100644 000000 de4ea28b4e441777cf99329788d545986456183f 0000000000000000000000000000000000000000 D\0TestFiles/test0.txt\0";
using (var reader = new System.IO.StringReader(input))
{
var changes = GitChangeInfo.GetChangedFiles(reader).ToArray();
Assert.Equal(1, changes.Length);
Assert.Equal("M", changes[0].Status);
Assert.Equal("TestFiles/Test0.txt", changes[0].path);
}
}
[Fact]
public void ShouldDetectAddDeleteNotCorrespondingToCaseRenameWithContentChange_AndReturnOneAdditionAndOneDeletionChange()
{
string input =
":100644 000000 de4ea28b4e441777cf99329788d545986456183f 0000000000000000000000000000000000000000 D\0TestFiles/Test1.txt\0" +
":000000 100644 0000000000000000000000000000000000000000 ed61b923604692e7c8b14763bd94412f471d91cc A\0TestFiles/Test2.txt\0";
using (var reader = new System.IO.StringReader(input))
{
var changes = GitChangeInfo.GetChangedFiles(reader).ToArray();
Assert.Equal(2, changes.Length);
Assert.Equal("D", changes[0].Status);
Assert.Equal("TestFiles/Test1.txt", changes[0].path);
Assert.Equal("A", changes[1].Status);
Assert.Equal("TestFiles/Test2.txt", changes[1].path);
}
}
[Fact]
public void ShouldDetectAddDeleteCorrespondingToCaseRenameWithoutContentChange_AndReturnNoChanges()
{
string input =
":000000 100644 0000000000000000000000000000000000000000 ed61b923604692e7c8b14763bd94412f471d91cc A\0TestFiles/Test3.txt\0" +
":100644 000000 ed61b923604692e7c8b14763bd94412f471d91cc 0000000000000000000000000000000000000000 D\0TestFiles/test3.txt\0";
using (var reader = new System.IO.StringReader(input))
{
var changes = GitChangeInfo.GetChangedFiles(reader).ToArray();
Assert.Empty(changes);
}
}
}
}