Skip to content

Commit 19614e2

Browse files
authored
Merge pull request #606 from qmfrederik/fix587
Path filters: Recurse into directories if child entries may be included by filters
2 parents 8c11e8d + 0066fa0 commit 19614e2

File tree

3 files changed

+50
-31
lines changed

3 files changed

+50
-31
lines changed

src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ public void Worktree_Support(bool detachedHead)
444444
var context = this.CreateGitContext(workTreePath);
445445
var oracleWorkTree = new VersionOracle(context);
446446
Assert.Equal(oracleOriginal.Version, oracleWorkTree.Version);
447-
447+
448448
Assert.True(context.TrySelectCommit("HEAD"));
449449
Assert.True(context.TrySelectCommit(this.LibGit2Repository.Head.Tip.Sha));
450450
}
@@ -731,6 +731,28 @@ public void GetVersionHeight_IncludeRootExcludeSome()
731731
Assert.Equal(2, this.GetVersionHeight(relativeDirectory));
732732
}
733733

734+
[Fact]
735+
public void GetVersion_PathFilterInTwoDeepSubDirAndVersionBump()
736+
{
737+
this.InitializeSourceControl();
738+
739+
const string relativeDirectory = "src/lib";
740+
var versionOptions = new VersionOptions
741+
{
742+
Version = new SemanticVersion("1.1"),
743+
PathFilters = new FilterPath[]
744+
{
745+
new FilterPath(".", relativeDirectory),
746+
},
747+
};
748+
this.WriteVersionFile(versionOptions, relativeDirectory);
749+
Assert.Equal(1, this.GetVersionHeight(relativeDirectory));
750+
751+
versionOptions.Version = new SemanticVersion("1.2");
752+
this.WriteVersionFile(versionOptions, relativeDirectory);
753+
Assert.Equal(1, this.GetVersionHeight(relativeDirectory));
754+
}
755+
734756
[Fact]
735757
public void GetVersionHeight_ProjectDirectoryDifferentToVersionJsonDirectory()
736758
{

src/NerdBank.GitVersioning/FilterPath.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,31 @@ public bool Includes(string repoRelativePath, bool ignoreCase)
199199
stringComparison);
200200
}
201201

202+
/// <summary>
203+
/// Determines if children of <paramref name="repoRelativePath"/> may be included
204+
/// by this <see cref="FilterPath"/>.
205+
/// </summary>
206+
/// <param name="repoRelativePath">Forward-slash delimited path (repo relative).</param>
207+
/// <param name="ignoreCase">
208+
/// Whether paths should be compared case insensitively.
209+
/// Should be the 'core.ignorecase' config value for the repository.
210+
/// </param>
211+
/// <returns>
212+
/// <see langword="true"/> if this <see cref="FilterPath"/> is an including filter that may match
213+
/// children of <paramref name="repoRelativePath"/>, otherwise <see langword="false"/>.
214+
/// </returns>
215+
public bool IncludesChildren(string repoRelativePath, bool ignoreCase)
216+
{
217+
if (repoRelativePath is null)
218+
throw new ArgumentNullException(nameof(repoRelativePath));
219+
220+
if (!this.IsInclude) return false;
221+
if (this.IsRoot) return true;
222+
223+
var stringComparison = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
224+
return this.RepoRelativePath.StartsWith(repoRelativePath + "/", stringComparison);
225+
}
226+
202227
private static (int dirsToAscend, StringBuilder result) GetRelativePath(string path, string relativeTo)
203228
{
204229
var pathParts = path.Split('/');

src/NerdBank.GitVersioning/Managed/ManagedGitExtensions.cs

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -165,15 +165,6 @@ bool TryCalculateHeight(GitCommit commit)
165165

166166
var ignoreCase = repository.IgnoreCase;
167167

168-
/*
169-
bool ContainsRelevantChanges(IEnumerable<TreeEntryChanges> changes) =>
170-
excludePaths.Count == 0
171-
? changes.Any()
172-
// If there is a single change that isn't excluded,
173-
// then this commit is relevant.
174-
: changes.Any(change => !excludePaths.Any(exclude => exclude.Excludes(change.Path, ignoreCase)));
175-
*/
176-
177168
int height = 1;
178169

179170
if (pathFilters != null)
@@ -194,26 +185,6 @@ bool ContainsRelevantChanges(IEnumerable<TreeEntryChanges> changes) =>
194185
}
195186
}
196187

197-
/*
198-
// If there are no include paths, or any of the include
199-
// paths refer to the root of the repository, then do not
200-
// filter the diff at all.
201-
var diffInclude =
202-
includePaths.Count == 0 || pathFilters.Any(filter => filter.IsRoot)
203-
? null
204-
: includePaths;
205-
206-
// If the diff between this commit and any of its parents
207-
// does not touch a path that we care about, don't bump the
208-
// height.
209-
var relevantCommit =
210-
commit.Parents.Any()
211-
? commit.Parents.Any(parent => ContainsRelevantChanges(commit.GetRepository().Diff
212-
.Compare<TreeChanges>(parent.Tree, commit.Tree, diffInclude, DiffOptions)))
213-
: ContainsRelevantChanges(commit.GetRepository().Diff
214-
.Compare<TreeChanges>(null, commit.Tree, diffInclude, DiffOptions));
215-
*/
216-
217188
if (!relevantCommit)
218189
{
219190
height = 0;
@@ -268,7 +239,8 @@ private static bool IsRelevantCommit(GitRepository repository, GitTree tree, Git
268239

269240
bool isRelevant =
270241
// Either there are no include filters at all (i.e. everything is included), or there's an explicit include filter
271-
(!filters.Any(f => f.IsInclude) || filters.Any(f => f.Includes(fullPath, repository.IgnoreCase)))
242+
(!filters.Any(f => f.IsInclude) || filters.Any(f => f.Includes(fullPath, repository.IgnoreCase))
243+
|| (!entry.IsFile && filters.Any(f => f.IncludesChildren(fullPath, repository.IgnoreCase))))
272244
// The path is not excluded by any filters
273245
&& !filters.Any(f => f.Excludes(fullPath, repository.IgnoreCase));
274246

0 commit comments

Comments
 (0)