diff --git a/docs/input/docs/reference/configuration.md b/docs/input/docs/reference/configuration.md
index f6ac35c566..eb6302ab7b 100644
--- a/docs/input/docs/reference/configuration.md
+++ b/docs/input/docs/reference/configuration.md
@@ -191,6 +191,7 @@ branches:
is-main-branch: false
ignore:
sha: []
+ paths: []
mode: ContinuousDelivery
label: '{BranchName}'
increment: Inherit
@@ -208,7 +209,7 @@ tracks-release-branches: false
is-release-branch: false
is-main-branch: false
```
-snippet source | anchor
+snippet source | anchor
The supported built-in configuration for the `GitHubFlow` workflow (`workflow: GitHubFlow/v1`) looks like:
@@ -315,6 +316,7 @@ branches:
is-main-branch: false
ignore:
sha: []
+ paths: []
mode: ContinuousDelivery
label: '{BranchName}'
increment: Inherit
@@ -332,7 +334,7 @@ tracks-release-branches: false
is-release-branch: false
is-main-branch: false
```
-snippet source | anchor
+snippet source | anchor
The preview built-in configuration (experimental usage only) for the `TrunkBased` workflow (`workflow: TrunkBased/preview1`) looks like:
@@ -424,6 +426,7 @@ branches:
pre-release-weight: 30000
ignore:
sha: []
+ paths: []
mode: ContinuousDelivery
label: '{BranchName}'
increment: Inherit
@@ -441,7 +444,7 @@ tracks-release-branches: false
is-release-branch: false
is-main-branch: false
```
-snippet source | anchor
+snippet source | anchor
The details of the available options are as follows:
diff --git a/docs/input/docs/workflows/GitFlow/v1.yml b/docs/input/docs/workflows/GitFlow/v1.yml
index 114ecf8e4f..dd44250ac5 100644
--- a/docs/input/docs/workflows/GitFlow/v1.yml
+++ b/docs/input/docs/workflows/GitFlow/v1.yml
@@ -148,6 +148,7 @@ branches:
is-main-branch: false
ignore:
sha: []
+ paths: []
mode: ContinuousDelivery
label: '{BranchName}'
increment: Inherit
diff --git a/docs/input/docs/workflows/GitHubFlow/v1.yml b/docs/input/docs/workflows/GitHubFlow/v1.yml
index bc0452231a..be7da3a729 100644
--- a/docs/input/docs/workflows/GitHubFlow/v1.yml
+++ b/docs/input/docs/workflows/GitHubFlow/v1.yml
@@ -97,6 +97,7 @@ branches:
is-main-branch: false
ignore:
sha: []
+ paths: []
mode: ContinuousDelivery
label: '{BranchName}'
increment: Inherit
diff --git a/docs/input/docs/workflows/TrunkBased/preview1.yml b/docs/input/docs/workflows/TrunkBased/preview1.yml
index 83d231527f..c261444d9f 100644
--- a/docs/input/docs/workflows/TrunkBased/preview1.yml
+++ b/docs/input/docs/workflows/TrunkBased/preview1.yml
@@ -82,6 +82,7 @@ branches:
pre-release-weight: 30000
ignore:
sha: []
+ paths: []
mode: ContinuousDelivery
label: '{BranchName}'
increment: Inherit
diff --git a/new-cli/GitVersion.Core.Libgit2Sharp/GitVersion.Core.Libgit2Sharp.csproj b/new-cli/GitVersion.Core.Libgit2Sharp/GitVersion.Core.Libgit2Sharp.csproj
index 20c3f4bedf..4e8f95ddc5 100644
--- a/new-cli/GitVersion.Core.Libgit2Sharp/GitVersion.Core.Libgit2Sharp.csproj
+++ b/new-cli/GitVersion.Core.Libgit2Sharp/GitVersion.Core.Libgit2Sharp.csproj
@@ -56,6 +56,9 @@
Git\TagCollection.cs
+
+
+ Git\TreeChanges.cs
diff --git a/src/GitVersion.Configuration.Tests/Configuration/ConfigurationProviderTests.CanWriteOutEffectiveConfiguration.approved.txt b/src/GitVersion.Configuration.Tests/Configuration/ConfigurationProviderTests.CanWriteOutEffectiveConfiguration.approved.txt
index 114ecf8e4f..dd44250ac5 100644
--- a/src/GitVersion.Configuration.Tests/Configuration/ConfigurationProviderTests.CanWriteOutEffectiveConfiguration.approved.txt
+++ b/src/GitVersion.Configuration.Tests/Configuration/ConfigurationProviderTests.CanWriteOutEffectiveConfiguration.approved.txt
@@ -148,6 +148,7 @@ branches:
is-main-branch: false
ignore:
sha: []
+ paths: []
mode: ContinuousDelivery
label: '{BranchName}'
increment: Inherit
diff --git a/src/GitVersion.Configuration.Tests/Workflows/approved/GitFlow/v1.yml b/src/GitVersion.Configuration.Tests/Workflows/approved/GitFlow/v1.yml
index 114ecf8e4f..dd44250ac5 100644
--- a/src/GitVersion.Configuration.Tests/Workflows/approved/GitFlow/v1.yml
+++ b/src/GitVersion.Configuration.Tests/Workflows/approved/GitFlow/v1.yml
@@ -148,6 +148,7 @@ branches:
is-main-branch: false
ignore:
sha: []
+ paths: []
mode: ContinuousDelivery
label: '{BranchName}'
increment: Inherit
diff --git a/src/GitVersion.Configuration.Tests/Workflows/approved/GitHubFlow/v1.yml b/src/GitVersion.Configuration.Tests/Workflows/approved/GitHubFlow/v1.yml
index bc0452231a..be7da3a729 100644
--- a/src/GitVersion.Configuration.Tests/Workflows/approved/GitHubFlow/v1.yml
+++ b/src/GitVersion.Configuration.Tests/Workflows/approved/GitHubFlow/v1.yml
@@ -97,6 +97,7 @@ branches:
is-main-branch: false
ignore:
sha: []
+ paths: []
mode: ContinuousDelivery
label: '{BranchName}'
increment: Inherit
diff --git a/src/GitVersion.Configuration.Tests/Workflows/approved/TrunkBased/preview1.yml b/src/GitVersion.Configuration.Tests/Workflows/approved/TrunkBased/preview1.yml
index 83d231527f..c261444d9f 100644
--- a/src/GitVersion.Configuration.Tests/Workflows/approved/TrunkBased/preview1.yml
+++ b/src/GitVersion.Configuration.Tests/Workflows/approved/TrunkBased/preview1.yml
@@ -82,6 +82,7 @@ branches:
pre-release-weight: 30000
ignore:
sha: []
+ paths: []
mode: ContinuousDelivery
label: '{BranchName}'
increment: Inherit
diff --git a/src/GitVersion.Configuration/IgnoreConfiguration.cs b/src/GitVersion.Configuration/IgnoreConfiguration.cs
index cb1e81e679..4ea9d6d86e 100644
--- a/src/GitVersion.Configuration/IgnoreConfiguration.cs
+++ b/src/GitVersion.Configuration/IgnoreConfiguration.cs
@@ -1,3 +1,4 @@
+using System.Collections.ObjectModel;
using GitVersion.Configuration.Attributes;
namespace GitVersion.Configuration;
@@ -23,6 +24,12 @@ public string? BeforeString
[JsonPropertyDescription("A sequence of SHAs to be excluded from the version calculations.")]
public HashSet Shas { get; init; } = [];
+ IReadOnlyCollection IIgnoreConfiguration.Paths => Paths;
+
+ [JsonPropertyName("paths")]
+ [JsonPropertyDescription("A sequence of file paths to be excluded from the version calculations.")]
+ public Collection Paths { get; init; } = [];
+
[JsonIgnore]
- public bool IsEmpty => Before == null && Shas.Count == 0;
+ public bool IsEmpty => Before == null && Shas.Count == 0 && Paths.Count == 0;
}
diff --git a/src/GitVersion.Core.Tests/Extensions/GitRepositoryTestingExtensions.cs b/src/GitVersion.Core.Tests/Extensions/GitRepositoryTestingExtensions.cs
index 1570e7bf58..1dd6e242c8 100644
--- a/src/GitVersion.Core.Tests/Extensions/GitRepositoryTestingExtensions.cs
+++ b/src/GitVersion.Core.Tests/Extensions/GitRepositoryTestingExtensions.cs
@@ -32,6 +32,13 @@ public static ICommit CreateMockCommit()
return commit;
}
+ public static ICommit CreateMockCommit(List diffPaths)
+ {
+ var commit = CreateMockCommit();
+ commit.DiffPaths.Returns(diffPaths);
+ return commit;
+ }
+
public static IBranch CreateMockBranch(string name, params ICommit[] commits)
{
var branch = Substitute.For();
diff --git a/src/GitVersion.Core.Tests/IntegrationTests/IgnoreCommitScenarios.cs b/src/GitVersion.Core.Tests/IntegrationTests/IgnoreCommitScenarios.cs
index e1f567e92f..a789867705 100644
--- a/src/GitVersion.Core.Tests/IntegrationTests/IgnoreCommitScenarios.cs
+++ b/src/GitVersion.Core.Tests/IntegrationTests/IgnoreCommitScenarios.cs
@@ -135,8 +135,9 @@ public void GivenTrunkBasedWorkflowWithIgnoreConfigurationBeforeCommitWithTagThe
fixture.ApplyTag("1.0.0");
fixture.MakeACommit("D");
+ var before = commitC.Committer.When.AddSeconds(1);
var configuration = TrunkBasedConfigurationBuilder.New
- .WithIgnoreConfiguration(new IgnoreConfiguration { Before = commitC.Committer.When })
+ .WithIgnoreConfiguration(new IgnoreConfiguration { Before = before })
.Build();
// ✅ succeeds as expected
@@ -285,8 +286,9 @@ public void GivenGitHubFlowWorkflowWithIgnoreConfigurationBeforeCommitWithTagThe
fixture.ApplyTag("1.0.0");
fixture.MakeACommit("D");
+ var before = commitC.Committer.When.AddSeconds(1);
var configuration = GitHubFlowConfigurationBuilder.New
- .WithIgnoreConfiguration(new IgnoreConfiguration { Before = commitC.Committer.When })
+ .WithIgnoreConfiguration(new IgnoreConfiguration { Before = before })
.Build();
// ✅ succeeds as expected
@@ -331,4 +333,104 @@ public void GivenGitHubFlowWorkflowWithCommitParameterBThenTagShouldBeConsidered
// ✅ succeeds as expected
fixture.AssertFullSemver(semanticVersion, configuration, commitId: commitA.Sha);
}
+
+ [Test]
+ public void GivenTrunkBasedWorkflowWithIgnoreConfigurationForPathThenVersionShouldBeCorrect()
+ {
+ using var fixture = new EmptyRepositoryFixture();
+
+ var commitA = fixture.Repository.MakeACommit("A");
+ var commitB = fixture.Repository.MakeACommit("B");
+ fixture.MakeACommit("C");
+ fixture.MakeACommit("D");
+
+ var ignoredPath = fixture.Repository.Diff.Compare(commitA.Tree, commitB.Tree).Select(element => element.Path).First();
+
+ var configuration = TrunkBasedConfigurationBuilder.New
+ .WithIgnoreConfiguration(new IgnoreConfiguration { Paths = { ignoredPath } })
+ .Build();
+
+ // commitB should be ignored, so version should be as if B didn't exist
+ fixture.AssertFullSemver("0.0.3", configuration);
+ }
+
+ [Test]
+ public void GivenTrunkBasedWorkflowWithIgnoreConfigurationForPathAndCommitParameterCThenVersionShouldBeCorrect()
+ {
+ using var fixture = new EmptyRepositoryFixture();
+
+ var commitA = fixture.Repository.MakeACommit("A");
+ fixture.MakeACommit("B");
+ var commitC = fixture.Repository.MakeACommit("C");
+ fixture.MakeACommit("D");
+
+ var ignoredPath = fixture.Repository.Diff.Compare(commitA.Tree, commitC.Tree).Select(element => element.Path).First();
+
+ var configuration = TrunkBasedConfigurationBuilder.New
+ .WithIgnoreConfiguration(new IgnoreConfiguration { Paths = { ignoredPath } })
+ .Build();
+
+ // commitC should be ignored, so version should be as if C didn't exist
+ fixture.AssertFullSemver("0.0.2", configuration, commitId: commitC.Sha);
+ }
+
+ [Test]
+ public void GivenGitHubFlowWorkflowWithIgnoreConfigurationForPathThenVersionShouldBeCorrect()
+ {
+ using var fixture = new EmptyRepositoryFixture();
+
+ var commitA = fixture.Repository.MakeACommit("A");
+ var commitB = fixture.Repository.MakeACommit("B");
+ fixture.MakeACommit("C");
+ fixture.MakeACommit("D");
+
+ var ignoredPath = fixture.Repository.Diff.Compare(commitA.Tree, commitB.Tree).Select(element => element.Path).First();
+
+ var configuration = GitHubFlowConfigurationBuilder.New
+ .WithIgnoreConfiguration(new IgnoreConfiguration { Paths = { ignoredPath } })
+ .Build();
+
+ // commitB should be ignored, so version should be as if B didn't exist
+ fixture.AssertFullSemver("0.0.1-3", configuration);
+ }
+
+ [Test]
+ public void GivenTrunkBasedWorkflowWithIgnoreConfigurationForTaggedCommitPathThenTagShouldBeIgnored()
+ {
+ using var fixture = new EmptyRepositoryFixture();
+
+ var commitA = fixture.Repository.MakeACommit("A");
+ var commitB = fixture.Repository.MakeACommit("B");
+ fixture.ApplyTag("1.0.0");
+ fixture.MakeACommit("C");
+
+ var ignoredPath = fixture.Repository.Diff.Compare(commitA.Tree, commitB.Tree).Select(element => element.Path).First();
+
+ var configuration = TrunkBasedConfigurationBuilder.New
+ .WithIgnoreConfiguration(new IgnoreConfiguration { Paths = { ignoredPath } })
+ .Build();
+
+ // commitB should be ignored, so version should be as if B didn't exist
+ fixture.AssertFullSemver("0.0.2", configuration);
+ }
+
+ [Test]
+ public void GivenGitHubFlowWorkflowWithIgnoreConfigurationForTaggedCommitPathThenTagShouldBeIgnored()
+ {
+ using var fixture = new EmptyRepositoryFixture();
+
+ var commitA = fixture.Repository.MakeACommit("A");
+ var commitB = fixture.Repository.MakeACommit("B");
+ fixture.ApplyTag("1.0.0");
+ fixture.MakeACommit("C");
+
+ var ignoredPath = fixture.Repository.Diff.Compare(commitA.Tree, commitB.Tree).Select(element => element.Path).First();
+
+ var configuration = GitHubFlowConfigurationBuilder.New
+ .WithIgnoreConfiguration(new IgnoreConfiguration { Paths = { ignoredPath } })
+ .Build();
+
+ // commitB should be ignored, so version should be as if B didn't exist
+ fixture.AssertFullSemver("0.0.1-2", configuration);
+ }
}
diff --git a/src/GitVersion.Core.Tests/VersionCalculation/MinDateVersionFilterTests.cs b/src/GitVersion.Core.Tests/VersionCalculation/MinDateVersionFilterTests.cs
index 86f41c787c..909c77e094 100644
--- a/src/GitVersion.Core.Tests/VersionCalculation/MinDateVersionFilterTests.cs
+++ b/src/GitVersion.Core.Tests/VersionCalculation/MinDateVersionFilterTests.cs
@@ -12,7 +12,7 @@ public void VerifyNullGuard()
var dummy = DateTimeOffset.UtcNow.AddSeconds(1.0);
var sut = new MinDateVersionFilter(dummy);
- Should.Throw(() => sut.Exclude(null!, out _));
+ Should.Throw(() => sut.Exclude((IBaseVersion)null!, out _));
}
[Test]
diff --git a/src/GitVersion.Core.Tests/VersionCalculation/PathFilterTests.cs b/src/GitVersion.Core.Tests/VersionCalculation/PathFilterTests.cs
new file mode 100644
index 0000000000..efffb84e18
--- /dev/null
+++ b/src/GitVersion.Core.Tests/VersionCalculation/PathFilterTests.cs
@@ -0,0 +1,48 @@
+using GitVersion.Core.Tests.Helpers;
+using GitVersion.VersionCalculation;
+
+namespace GitVersion.Core.Tests;
+
+[TestFixture]
+public class PathFilterTests : TestBase
+{
+ [Test]
+ public void VerifyNullGuard()
+ {
+ var sut = new PathFilter([]);
+
+ Should.Throw(() => sut.Exclude((IBaseVersion)null!, out _));
+ }
+
+ [Test]
+ public void WhenPathMatchShouldExcludeWithReason()
+ {
+ var commit = GitRepositoryTestingExtensions.CreateMockCommit(["/path"]);
+ BaseVersion version = new("dummy", new SemanticVersion(1), commit);
+ var sut = new PathFilter(commit.DiffPaths);
+
+ sut.Exclude(version, out var reason).ShouldBeTrue();
+ reason.ShouldNotBeNullOrWhiteSpace();
+ }
+
+ [Test]
+ public void WhenPathMismatchShouldNotExclude()
+ {
+ var commit = GitRepositoryTestingExtensions.CreateMockCommit(["/path"]);
+ BaseVersion version = new("dummy", new SemanticVersion(1), commit);
+ var sut = new PathFilter(["/another_path"]);
+
+ sut.Exclude(version, out var reason).ShouldBeFalse();
+ reason.ShouldBeNull();
+ }
+
+ [Test]
+ public void ExcludeShouldAcceptVersionWithNullCommit()
+ {
+ BaseVersion version = new("dummy", new SemanticVersion(1));
+ var sut = new PathFilter(["/path"]);
+
+ sut.Exclude(version, out var reason).ShouldBeFalse();
+ reason.ShouldBeNull();
+ }
+}
diff --git a/src/GitVersion.Core.Tests/VersionCalculation/ShaVersionFilterTests.cs b/src/GitVersion.Core.Tests/VersionCalculation/ShaVersionFilterTests.cs
index 69b95b9f20..e4d4b219f1 100644
--- a/src/GitVersion.Core.Tests/VersionCalculation/ShaVersionFilterTests.cs
+++ b/src/GitVersion.Core.Tests/VersionCalculation/ShaVersionFilterTests.cs
@@ -12,7 +12,7 @@ public void VerifyNullGuard()
var commit = GitRepositoryTestingExtensions.CreateMockCommit();
var sut = new ShaVersionFilter([commit.Sha]);
- Should.Throw(() => sut.Exclude(null!, out _));
+ Should.Throw(() => sut.Exclude((IBaseVersion)null!, out _));
}
[Test]
diff --git a/src/GitVersion.Core.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs b/src/GitVersion.Core.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs
index eb80a02e3a..1f03f3a9ea 100644
--- a/src/GitVersion.Core.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs
+++ b/src/GitVersion.Core.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs
@@ -204,6 +204,7 @@ private class MockCommit : ICommit
public IObjectId Id => throw new NotImplementedException();
public string Sha => throw new NotImplementedException();
public IReadOnlyList Parents => throw new NotImplementedException();
+ public IReadOnlyList DiffPaths => throw new NotImplementedException();
public DateTimeOffset When => throw new NotImplementedException();
public string Message => throw new NotImplementedException();
}
diff --git a/src/GitVersion.Core/Configuration/EffectiveConfiguration.cs b/src/GitVersion.Core/Configuration/EffectiveConfiguration.cs
index bd16f1f2ba..29f7280f74 100644
--- a/src/GitVersion.Core/Configuration/EffectiveConfiguration.cs
+++ b/src/GitVersion.Core/Configuration/EffectiveConfiguration.cs
@@ -67,7 +67,6 @@ public EffectiveConfiguration(
PatchVersionBumpMessage = configuration.PatchVersionBumpMessage;
NoBumpMessage = configuration.NoBumpMessage;
CommitMessageIncrementing = branchConfiguration.CommitMessageIncrementing.Value;
- VersionFilters = configuration.Ignore.ToFilters();
Ignore = configuration.Ignore;
TracksReleaseBranches = branchConfiguration.TracksReleaseBranches ?? false;
IsReleaseBranch = branchConfiguration.IsReleaseBranch ?? false;
@@ -122,8 +121,6 @@ public EffectiveConfiguration(
public CommitMessageIncrementMode CommitMessageIncrementing { get; }
- public IEnumerable VersionFilters { get; }
-
public IIgnoreConfiguration Ignore { get; }
public string? CommitDateFormat { get; }
diff --git a/src/GitVersion.Core/Configuration/IIgnoreConfiguration.cs b/src/GitVersion.Core/Configuration/IIgnoreConfiguration.cs
index 482b6a6c5f..ea19f6d746 100644
--- a/src/GitVersion.Core/Configuration/IIgnoreConfiguration.cs
+++ b/src/GitVersion.Core/Configuration/IIgnoreConfiguration.cs
@@ -6,5 +6,7 @@ public interface IIgnoreConfiguration
IReadOnlySet Shas { get; }
+ IReadOnlyCollection Paths { get; }
+
bool IsEmpty { get; }
}
diff --git a/src/GitVersion.Core/Configuration/IgnoreConfigurationExtensions.cs b/src/GitVersion.Core/Configuration/IgnoreConfigurationExtensions.cs
index eeaf3a0ded..d4c7b19c07 100644
--- a/src/GitVersion.Core/Configuration/IgnoreConfigurationExtensions.cs
+++ b/src/GitVersion.Core/Configuration/IgnoreConfigurationExtensions.cs
@@ -22,5 +22,5 @@ public static IEnumerable Filter(this IIgnoreConfiguration ignore, ICom
}
private static bool ShouldBeIgnored(ICommit commit, IIgnoreConfiguration ignore)
- => !(commit.When <= ignore.Before) && !ignore.Shas.Contains(commit.Sha);
+ => !ignore.ToFilters().Any(filter => filter.Exclude(commit, out var _));
}
diff --git a/src/GitVersion.Core/Extensions/ConfigurationExtensions.cs b/src/GitVersion.Core/Extensions/ConfigurationExtensions.cs
index 9d87f32726..6f794c91d1 100644
--- a/src/GitVersion.Core/Extensions/ConfigurationExtensions.cs
+++ b/src/GitVersion.Core/Extensions/ConfigurationExtensions.cs
@@ -44,6 +44,7 @@ public static IEnumerable ToFilters(this IIgnoreConfiguration so
if (source.Shas.Count != 0) yield return new ShaVersionFilter(source.Shas);
if (source.Before.HasValue) yield return new MinDateVersionFilter(source.Before.Value);
+ if (source.Paths.Count != 0) yield return new PathFilter(source.Paths.ToList());
}
private static IEnumerable GetBranchConfigurations(IGitVersionConfiguration configuration, string branchName)
diff --git a/src/GitVersion.Core/Git/ICommit.cs b/src/GitVersion.Core/Git/ICommit.cs
index 6d54ecb78d..8d3b225655 100644
--- a/src/GitVersion.Core/Git/ICommit.cs
+++ b/src/GitVersion.Core/Git/ICommit.cs
@@ -7,4 +7,6 @@ public interface ICommit : IEquatable, IComparable, IGitObjec
DateTimeOffset When { get; }
string Message { get; }
+
+ IReadOnlyList DiffPaths { get; }
}
diff --git a/src/GitVersion.Core/Git/ITreeChanges.cs b/src/GitVersion.Core/Git/ITreeChanges.cs
new file mode 100644
index 0000000000..28a4600d68
--- /dev/null
+++ b/src/GitVersion.Core/Git/ITreeChanges.cs
@@ -0,0 +1,6 @@
+namespace GitVersion.Git;
+
+public interface ITreeChanges
+{
+ IReadOnlyList Paths { get; }
+}
diff --git a/src/GitVersion.Core/PublicAPI.Shipped.txt b/src/GitVersion.Core/PublicAPI.Shipped.txt
index 27793f8f08..89e76daf51 100644
--- a/src/GitVersion.Core/PublicAPI.Shipped.txt
+++ b/src/GitVersion.Core/PublicAPI.Shipped.txt
@@ -87,7 +87,6 @@ GitVersion.Configuration.EffectiveConfiguration.TrackMergeMessage.get -> bool
GitVersion.Configuration.EffectiveConfiguration.TrackMergeTarget.get -> bool
GitVersion.Configuration.EffectiveConfiguration.TracksReleaseBranches.get -> bool
GitVersion.Configuration.EffectiveConfiguration.UpdateBuildNumber.get -> bool
-GitVersion.Configuration.EffectiveConfiguration.VersionFilters.get -> System.Collections.Generic.IEnumerable!
GitVersion.Configuration.EffectiveConfiguration.VersionInBranchPattern.get -> string?
GitVersion.Configuration.EffectiveConfiguration.VersionStrategy.get -> GitVersion.VersionCalculation.VersionStrategies
GitVersion.Configuration.IBranchConfiguration
diff --git a/src/GitVersion.Core/PublicAPI.Unshipped.txt b/src/GitVersion.Core/PublicAPI.Unshipped.txt
index 0bcbcd8281..505df687a4 100644
--- a/src/GitVersion.Core/PublicAPI.Unshipped.txt
+++ b/src/GitVersion.Core/PublicAPI.Unshipped.txt
@@ -146,3 +146,8 @@ virtual GitVersion.WixInfo.$() -> GitVersion.WixInfo!
virtual GitVersion.WixInfo.EqualityContract.get -> System.Type!
virtual GitVersion.WixInfo.Equals(GitVersion.WixInfo? other) -> bool
virtual GitVersion.WixInfo.PrintMembers(System.Text.StringBuilder! builder) -> bool
+GitVersion.Configuration.IIgnoreConfiguration.Paths.get -> System.Collections.Generic.IReadOnlyCollection!
+GitVersion.Git.ICommit.DiffPaths.get -> System.Collections.Generic.IReadOnlyList!
+GitVersion.Git.ITreeChanges
+GitVersion.Git.ITreeChanges.Paths.get -> System.Collections.Generic.IReadOnlyList!
+GitVersion.VersionCalculation.IVersionFilter.Exclude(GitVersion.Git.ICommit! commit, out string? reason) -> bool
diff --git a/src/GitVersion.Core/VersionCalculation/Abstractions/IVersionFilter.cs b/src/GitVersion.Core/VersionCalculation/Abstractions/IVersionFilter.cs
index f088734713..65a8d2a7c4 100644
--- a/src/GitVersion.Core/VersionCalculation/Abstractions/IVersionFilter.cs
+++ b/src/GitVersion.Core/VersionCalculation/Abstractions/IVersionFilter.cs
@@ -1,6 +1,9 @@
+using GitVersion.Git;
+
namespace GitVersion.VersionCalculation;
public interface IVersionFilter
{
bool Exclude(IBaseVersion baseVersion, out string? reason);
+ bool Exclude(ICommit commit, out string? reason);
}
diff --git a/src/GitVersion.Core/VersionCalculation/IncrementStrategyFinder.cs b/src/GitVersion.Core/VersionCalculation/IncrementStrategyFinder.cs
index 98c51fe60c..d74f71d4a3 100644
--- a/src/GitVersion.Core/VersionCalculation/IncrementStrategyFinder.cs
+++ b/src/GitVersion.Core/VersionCalculation/IncrementStrategyFinder.cs
@@ -7,7 +7,9 @@
namespace GitVersion.VersionCalculation;
-internal class IncrementStrategyFinder(IRepositoryStore repositoryStore, ITaggedSemanticVersionRepository taggedSemanticVersionRepository)
+internal class IncrementStrategyFinder(
+ IRepositoryStore repositoryStore,
+ ITaggedSemanticVersionRepository taggedSemanticVersionRepository)
: IIncrementStrategyFinder
{
private readonly Dictionary commitIncrementCache = [];
diff --git a/src/GitVersion.Core/VersionCalculation/MinDateVersionFilter.cs b/src/GitVersion.Core/VersionCalculation/MinDateVersionFilter.cs
index b2fce8b7e6..294c5defb9 100644
--- a/src/GitVersion.Core/VersionCalculation/MinDateVersionFilter.cs
+++ b/src/GitVersion.Core/VersionCalculation/MinDateVersionFilter.cs
@@ -1,5 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using GitVersion.Extensions;
+using GitVersion.Git;
namespace GitVersion.VersionCalculation;
@@ -17,4 +18,15 @@ public bool Exclude(IBaseVersion baseVersion, [NotNullWhen(true)] out string? re
reason = "Source was ignored due to commit date being outside of configured range";
return true;
}
+
+ public bool Exclude(ICommit commit, [NotNullWhen(true)] out string? reason)
+ {
+ reason = null;
+
+ if (commit == null || commit.When >= minimum)
+ return false;
+
+ reason = "Source was ignored due to commit date being outside of configured range";
+ return true;
+ }
}
diff --git a/src/GitVersion.Core/VersionCalculation/PathFilter.cs b/src/GitVersion.Core/VersionCalculation/PathFilter.cs
new file mode 100644
index 0000000000..cb801b6351
--- /dev/null
+++ b/src/GitVersion.Core/VersionCalculation/PathFilter.cs
@@ -0,0 +1,57 @@
+using System.Collections.Concurrent;
+using System.Diagnostics.CodeAnalysis;
+using System.Text.RegularExpressions;
+using GitVersion.Git;
+
+namespace GitVersion.VersionCalculation;
+
+internal enum PathFilterMode
+{
+ Inclusive, // All commit paths must match for commit to be excluded
+ //Exclusive // Any commit path must match for commit to be excluded
+}
+
+internal class PathFilter(IReadOnlyList paths, PathFilterMode mode = PathFilterMode.Inclusive) : IVersionFilter
+{
+ private readonly IReadOnlyList pathsRegexes = [.. paths.Select(path => new Regex(path, RegexOptions.Compiled))];
+ private readonly ConcurrentDictionary pathMatchCache = [];
+
+ public bool Exclude(IBaseVersion baseVersion, [NotNullWhen(true)] out string? reason)
+ {
+ ArgumentNullException.ThrowIfNull(baseVersion);
+ return Exclude(baseVersion.BaseVersionSource, out reason);
+ }
+
+ private bool IsMatch(string path)
+ {
+ if (!pathMatchCache.TryGetValue(path, out var isMatch))
+ {
+ isMatch = this.pathsRegexes.Any(regex => regex.IsMatch(path));
+ pathMatchCache[path] = isMatch;
+ }
+ return isMatch;
+ }
+
+ public bool Exclude(ICommit? commit, [NotNullWhen(true)] out string? reason)
+ {
+ reason = null;
+
+ if (commit != null)
+ {
+ switch (mode)
+ {
+ case PathFilterMode.Inclusive:
+ {
+ if (commit.DiffPaths.All(this.IsMatch))
+ {
+ reason = "Source was ignored due to all commit paths matching ignore regex";
+ return true;
+ }
+ break;
+ }
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/src/GitVersion.Core/VersionCalculation/ShaVersionFilter.cs b/src/GitVersion.Core/VersionCalculation/ShaVersionFilter.cs
index 87d4834d15..1f531342e1 100644
--- a/src/GitVersion.Core/VersionCalculation/ShaVersionFilter.cs
+++ b/src/GitVersion.Core/VersionCalculation/ShaVersionFilter.cs
@@ -1,5 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using GitVersion.Extensions;
+using GitVersion.Git;
namespace GitVersion.VersionCalculation;
@@ -22,4 +23,16 @@ public bool Exclude(IBaseVersion baseVersion, [NotNullWhen(true)] out string? re
reason = $"Sha {baseVersion.BaseVersionSource} was ignored due to commit having been excluded by configuration";
return true;
}
+
+ public bool Exclude(ICommit commit, [NotNullWhen(true)] out string? reason)
+ {
+ reason = null;
+
+ if (commit == null
+ || !this.shaList.Any(sha => commit.Sha.StartsWith(sha, StringComparison.OrdinalIgnoreCase)))
+ return false;
+
+ reason = $"Sha {commit} was ignored due to commit having been excluded by configuration";
+ return true;
+ }
}
diff --git a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/ConfiguredNextVersionVersionStrategy.cs b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/ConfiguredNextVersionVersionStrategy.cs
index 275aee185a..129f655733 100644
--- a/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/ConfiguredNextVersionVersionStrategy.cs
+++ b/src/GitVersion.Core/VersionCalculation/VersionSearchStrategies/ConfiguredNextVersionVersionStrategy.cs
@@ -18,7 +18,7 @@ public IEnumerable GetBaseVersions(EffectiveBranchConfiguration con
{
configuration.NotNull();
- if (!Context.Configuration.VersionStrategy.HasFlag(VersionStrategies.ConfiguredNextVersion))
+ if (!this.Context.Configuration.VersionStrategy.HasFlag(VersionStrategies.ConfiguredNextVersion))
yield break;
var nextVersion = Context.Configuration.NextVersion;
diff --git a/src/GitVersion.LibGit2Sharp/Git/Branch.cs b/src/GitVersion.LibGit2Sharp/Git/Branch.cs
index 2cbda65c0e..088f4674c7 100644
--- a/src/GitVersion.LibGit2Sharp/Git/Branch.cs
+++ b/src/GitVersion.LibGit2Sharp/Git/Branch.cs
@@ -10,16 +10,16 @@ internal sealed class Branch : IBranch
private readonly LibGit2Sharp.Branch innerBranch;
- internal Branch(LibGit2Sharp.Branch branch)
+ internal Branch(LibGit2Sharp.Branch branch, LibGit2Sharp.Diff diff)
{
this.innerBranch = branch.NotNull();
Name = new(branch.CanonicalName);
var commit = this.innerBranch.Tip;
- Tip = commit is null ? null : new Commit(commit);
+ Tip = commit is null ? null : new Commit(commit, diff);
var commits = this.innerBranch.Commits;
- Commits = new CommitCollection(commits);
+ Commits = new CommitCollection(commits, diff);
}
public ReferenceName Name { get; }
diff --git a/src/GitVersion.LibGit2Sharp/Git/BranchCollection.cs b/src/GitVersion.LibGit2Sharp/Git/BranchCollection.cs
index a6509d9116..f5edcd38cd 100644
--- a/src/GitVersion.LibGit2Sharp/Git/BranchCollection.cs
+++ b/src/GitVersion.LibGit2Sharp/Git/BranchCollection.cs
@@ -7,11 +7,13 @@ internal sealed class BranchCollection : IBranchCollection
{
private readonly LibGit2Sharp.BranchCollection innerCollection;
private readonly Lazy> branches;
+ private readonly LibGit2Sharp.Diff diff;
- internal BranchCollection(LibGit2Sharp.BranchCollection collection)
+ internal BranchCollection(LibGit2Sharp.BranchCollection collection, LibGit2Sharp.Diff diff)
{
this.innerCollection = collection.NotNull();
- this.branches = new Lazy>(() => [.. this.innerCollection.Select(branch => new Branch(branch))]);
+this.branches = new Lazy>(() => [.. this.innerCollection.Select(branch => new Branch(branch, diff))]);
+ this.diff = diff.NotNull();
}
public IEnumerator GetEnumerator()
@@ -25,7 +27,7 @@ public IBranch? this[string name]
{
name = name.NotNull();
var branch = this.innerCollection[name];
- return branch is null ? null : new Branch(branch);
+ return branch is null ? null : new Branch(branch, this.diff);
}
}
diff --git a/src/GitVersion.LibGit2Sharp/Git/Commit.cs b/src/GitVersion.LibGit2Sharp/Git/Commit.cs
index f9dd9cfc06..95f30e81cc 100644
--- a/src/GitVersion.LibGit2Sharp/Git/Commit.cs
+++ b/src/GitVersion.LibGit2Sharp/Git/Commit.cs
@@ -1,3 +1,4 @@
+using System.Collections.Concurrent;
using GitVersion.Extensions;
using GitVersion.Helpers;
@@ -5,17 +6,20 @@ namespace GitVersion.Git;
internal sealed class Commit : GitObject, ICommit
{
+ private static readonly ConcurrentDictionary> pathsCache = new();
private static readonly LambdaEqualityHelper equalityHelper = new(x => x.Id);
private static readonly LambdaKeyComparer comparerHelper = new(x => x.Sha);
private readonly Lazy> parentsLazy;
private readonly LibGit2Sharp.Commit innerCommit;
+ private readonly LibGit2Sharp.Diff repoDiff;
- internal Commit(LibGit2Sharp.Commit innerCommit) : base(innerCommit)
+ internal Commit(LibGit2Sharp.Commit innerCommit, LibGit2Sharp.Diff repoDiff) : base(innerCommit)
{
this.innerCommit = innerCommit.NotNull();
- this.parentsLazy = new(() => innerCommit.Parents.Select(parent => new Commit(parent)).ToList());
+ this.parentsLazy = new(() => innerCommit.Parents.Select(parent => new Commit(parent, repoDiff)).ToList());
When = innerCommit.Committer.When;
+ this.repoDiff = repoDiff;
}
public int CompareTo(ICommit? other) => comparerHelper.Compare(this, other);
@@ -23,8 +27,21 @@ internal Commit(LibGit2Sharp.Commit innerCommit) : base(innerCommit)
public IReadOnlyList Parents => this.parentsLazy.Value;
public DateTimeOffset When { get; }
public string Message => this.innerCommit.Message;
+ public IReadOnlyList DiffPaths
+ {
+ get
+ {
+ if (!pathsCache.TryGetValue(this.Sha, out var paths))
+ {
+ paths = this.CommitChanges?.Paths ?? [];
+ pathsCache[this.Sha] = paths;
+ }
+ return paths;
+ }
+ }
public override bool Equals(object? obj) => Equals(obj as ICommit);
public override int GetHashCode() => equalityHelper.GetHashCode(this);
public override string ToString() => $"'{Id.ToString(7)}' - {this.innerCommit.MessageShort}";
public static implicit operator LibGit2Sharp.Commit(Commit d) => d.innerCommit;
+ private TreeChanges CommitChanges => new(this.repoDiff.Compare(this.innerCommit.Tree, this.innerCommit.Parents.FirstOrDefault()?.Tree));
}
diff --git a/src/GitVersion.LibGit2Sharp/Git/CommitCollection.cs b/src/GitVersion.LibGit2Sharp/Git/CommitCollection.cs
index c2e33588a4..570c1dd426 100644
--- a/src/GitVersion.LibGit2Sharp/Git/CommitCollection.cs
+++ b/src/GitVersion.LibGit2Sharp/Git/CommitCollection.cs
@@ -7,11 +7,13 @@ internal sealed class CommitCollection : ICommitCollection
{
private readonly ICommitLog innerCollection;
private readonly Lazy> commits;
+ private readonly LibGit2Sharp.Diff diff;
- internal CommitCollection(ICommitLog collection)
+ internal CommitCollection(ICommitLog collection, LibGit2Sharp.Diff diff)
{
this.innerCollection = collection.NotNull();
- this.commits = new Lazy>(() => [.. this.innerCollection.Select(commit => new Commit(commit))]);
+ this.commits = new Lazy>(() => [.. this.innerCollection.Select(commit => new Commit(commit, diff))]);
+ this.diff = diff.NotNull();
}
public IEnumerator GetEnumerator()
@@ -34,7 +36,7 @@ public IEnumerable QueryBy(CommitFilter commitFilter)
SortBy = (LibGit2Sharp.CommitSortStrategies)commitFilter.SortBy
};
var commitLog = ((IQueryableCommitLog)this.innerCollection).QueryBy(filter);
- return new CommitCollection(commitLog);
+ return new CommitCollection(commitLog, this.diff);
static object? GetReacheableFrom(object? item) =>
item switch
diff --git a/src/GitVersion.LibGit2Sharp/Git/GitRepository.cs b/src/GitVersion.LibGit2Sharp/Git/GitRepository.cs
index aea0217adc..3d2fd756ed 100644
--- a/src/GitVersion.LibGit2Sharp/Git/GitRepository.cs
+++ b/src/GitVersion.LibGit2Sharp/Git/GitRepository.cs
@@ -16,17 +16,16 @@ private IRepository RepositoryInstance
return lazy.Value;
}
}
-
public string Path => RepositoryInstance.Info.Path;
public string WorkingDirectory => RepositoryInstance.Info.WorkingDirectory;
public bool IsHeadDetached => RepositoryInstance.Info.IsHeadDetached;
public bool IsShallow => RepositoryInstance.Info.IsShallow;
- public IBranch Head => new Branch(RepositoryInstance.Head);
+ public IBranch Head => new Branch(RepositoryInstance.Head, RepositoryInstance.Diff);
- public ITagCollection Tags => new TagCollection(RepositoryInstance.Tags);
+ public ITagCollection Tags => new TagCollection(RepositoryInstance.Tags, RepositoryInstance.Diff);
public IReferenceCollection Refs => new ReferenceCollection(RepositoryInstance.Refs);
- public IBranchCollection Branches => new BranchCollection(RepositoryInstance.Branches);
- public ICommitCollection Commits => new CommitCollection(RepositoryInstance.Commits);
+ public IBranchCollection Branches => new BranchCollection(RepositoryInstance.Branches, RepositoryInstance.Diff);
+ public ICommitCollection Commits => new CommitCollection(RepositoryInstance.Commits, RepositoryInstance.Diff);
public IRemoteCollection Remotes => new RemoteCollection(RepositoryInstance.Network.Remotes);
public void DiscoverRepository(string? gitDirectory)
@@ -49,7 +48,7 @@ public void DiscoverRepository(string? gitDirectory)
var first = (Commit)commit;
var second = (Commit)otherCommit;
var mergeBase = RepositoryInstance.ObjectDatabase.FindMergeBase(first, second);
- return mergeBase == null ? null : new Commit(mergeBase);
+ return mergeBase == null ? null : new Commit(mergeBase, RepositoryInstance.Diff);
});
}
@@ -88,7 +87,7 @@ private int GetUncommittedChangesCountInternal()
}
// gets all changes of the last commit vs Staging area and WT
- var changes = RepositoryInstance.Diff.Compare(RepositoryInstance.Head.Tip.Tree,
+ var changes = RepositoryInstance.Diff.Compare(RepositoryInstance.Head.Tip.Tree,
DiffTargets.Index | DiffTargets.WorkingDirectory);
return changes.Count;
diff --git a/src/GitVersion.LibGit2Sharp/Git/Tag.cs b/src/GitVersion.LibGit2Sharp/Git/Tag.cs
index b7af785b56..33302dba3d 100644
--- a/src/GitVersion.LibGit2Sharp/Git/Tag.cs
+++ b/src/GitVersion.LibGit2Sharp/Git/Tag.cs
@@ -9,12 +9,14 @@ internal sealed class Tag : ITag
private static readonly LambdaEqualityHelper equalityHelper = new(x => x.Name.Canonical);
private static readonly LambdaKeyComparer comparerHelper = new(x => x.Name.Canonical);
private readonly LibGit2Sharp.Tag innerTag;
+ private readonly LibGit2Sharp.Diff diff;
private readonly Lazy commitLazy;
- internal Tag(LibGit2Sharp.Tag tag)
+ internal Tag(LibGit2Sharp.Tag tag, LibGit2Sharp.Diff diff)
{
this.innerTag = tag.NotNull();
this.commitLazy = new(PeeledTargetCommit);
+ this.diff = diff.NotNull();
Name = new(this.innerTag.CanonicalName);
}
@@ -33,7 +35,7 @@ internal Tag(LibGit2Sharp.Tag tag)
target = annotation.Target;
}
- return target is LibGit2Sharp.Commit commit ? new Commit(commit) : null;
+ return target is LibGit2Sharp.Commit commit ? new Commit(commit, this.diff) : null;
}
public override bool Equals(object? obj) => Equals(obj as ITag);
diff --git a/src/GitVersion.LibGit2Sharp/Git/TagCollection.cs b/src/GitVersion.LibGit2Sharp/Git/TagCollection.cs
index bf88136398..bac1b4f790 100644
--- a/src/GitVersion.LibGit2Sharp/Git/TagCollection.cs
+++ b/src/GitVersion.LibGit2Sharp/Git/TagCollection.cs
@@ -6,10 +6,10 @@ internal sealed class TagCollection : ITagCollection
{
private readonly Lazy> tags;
- internal TagCollection(LibGit2Sharp.TagCollection collection)
+ internal TagCollection(LibGit2Sharp.TagCollection collection, LibGit2Sharp.Diff diff)
{
collection = collection.NotNull();
- this.tags = new Lazy>(() => [.. collection.Select(tag => new Tag(tag))]);
+ this.tags = new Lazy>(() => [.. collection.Select(tag => new Tag(tag, diff))]);
}
public IEnumerator GetEnumerator()
diff --git a/src/GitVersion.LibGit2Sharp/Git/TreeChanges.cs b/src/GitVersion.LibGit2Sharp/Git/TreeChanges.cs
new file mode 100644
index 0000000000..9ee9385a7e
--- /dev/null
+++ b/src/GitVersion.LibGit2Sharp/Git/TreeChanges.cs
@@ -0,0 +1,8 @@
+namespace GitVersion.Git;
+
+internal sealed class TreeChanges(LibGit2Sharp.TreeChanges innerTreeChanges) : ITreeChanges
+{
+ private readonly LibGit2Sharp.TreeChanges innerTreeChanges = innerTreeChanges ?? throw new ArgumentNullException(nameof(innerTreeChanges));
+
+ public IReadOnlyList Paths => [.. this.innerTreeChanges.Select(element => element.Path)];
+}