From 2f6ac33152c86604fd7cd346e9cbe4c350d18544 Mon Sep 17 00:00:00 2001 From: roeil Date: Wed, 21 May 2025 08:16:46 +0300 Subject: [PATCH 01/11] feat(paths-filter): follow pr --- docs/input/docs/workflows/GitFlow/v1.yml | 1 + docs/input/docs/workflows/GitHubFlow/v1.yml | 1 + .../docs/workflows/TrunkBased/preview1.yml | 1 + ...riteOutEffectiveConfiguration.approved.txt | 1 + .../Workflows/approved/GitFlow/v1.yml | 1 + .../Workflows/approved/GitHubFlow/v1.yml | 1 + .../approved/TrunkBased/preview1.yml | 1 + .../IgnoreConfiguration.cs | 9 +++- .../MinDateVersionFilterTests.cs | 2 +- .../VersionCalculation/PathFilterTests.cs | 11 ++++ .../ShaVersionFilterTests.cs | 2 +- .../MergeMessageBaseVersionStrategyTests.cs | 1 + .../Configuration/EffectiveConfiguration.cs | 3 -- .../Configuration/IIgnoreConfiguration.cs | 4 +- .../IgnoreConfigurationExtensions.cs | 2 +- .../Extensions/ConfigurationExtensions.cs | 3 +- src/GitVersion.Core/Git/ICommit.cs | 1 + src/GitVersion.Core/Git/ITreeChanges.cs | 6 +++ src/GitVersion.Core/PublicAPI.Shipped.txt | 1 - src/GitVersion.Core/PublicAPI.Unshipped.txt | 5 ++ .../Abstractions/IVersionFilter.cs | 3 ++ .../IncrementStrategyFinder.cs | 4 +- .../MinDateVersionFilter.cs | 12 +++++ .../VersionCalculation/PathFilter.cs | 51 +++++++++++++++++++ .../VersionCalculation/ShaVersionFilter.cs | 13 +++++ .../ConfiguredNextVersionVersionStrategy.cs | 2 +- src/GitVersion.LibGit2Sharp/Git/Branch.cs | 6 +-- .../Git/BranchCollection.cs | 8 +-- src/GitVersion.LibGit2Sharp/Git/Commit.cs | 20 +++++++- .../Git/CommitCollection.cs | 8 +-- .../Git/GitRepository.cs | 15 +++--- src/GitVersion.LibGit2Sharp/Git/Tag.cs | 6 ++- .../Git/TagCollection.cs | 4 +- .../Git/TreeChanges.cs | 8 +++ 34 files changed, 183 insertions(+), 34 deletions(-) create mode 100644 src/GitVersion.Core.Tests/VersionCalculation/PathFilterTests.cs create mode 100644 src/GitVersion.Core/Git/ITreeChanges.cs create mode 100644 src/GitVersion.Core/VersionCalculation/PathFilter.cs create mode 100644 src/GitVersion.LibGit2Sharp/Git/TreeChanges.cs 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/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..636571e2a8 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; @@ -24,5 +25,11 @@ public string? BeforeString public HashSet Shas { get; init; } = []; [JsonIgnore] - public bool IsEmpty => Before == null && Shas.Count == 0; + public bool IsEmpty => Before == null && Shas.Count == 0 && Paths.Count == 0; + + IReadOnlyCollection IIgnoreConfiguration.Paths => Paths; + + [JsonPropertyName("paths")] + [JsonPropertyDescription("A sequence of file paths to be excluded from the version calculations.")] + public Collection Paths { get; init; } = []; } 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..8c8286458c --- /dev/null +++ b/src/GitVersion.Core.Tests/VersionCalculation/PathFilterTests.cs @@ -0,0 +1,11 @@ +using GitVersion.Core.Tests.Helpers; +using GitVersion.VersionCalculation; + +namespace GitVersion.Core.Tests; + +[TestFixture] +public class PathFilterTests : TestBase +{ + [Test] + public void VerifyNullGuard() => Should.Throw(() => new PathFilter(null!)); +} 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..bc67a4e604 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 IEnumerable 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..d94c778fb1 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; } - bool IsEmpty { get; } + IReadOnlyCollection Paths { get; } + + bool IsEmpty => Before == null && Shas.Count == 0 && Paths.Count == 0; } 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..c8c0cb4fd1 100644 --- a/src/GitVersion.Core/Extensions/ConfigurationExtensions.cs +++ b/src/GitVersion.Core/Extensions/ConfigurationExtensions.cs @@ -25,7 +25,7 @@ public static EffectiveConfiguration GetEffectiveConfiguration( { fallbackConfiguration = parentConfiguration; } - return new EffectiveConfiguration(configuration, branchConfiguration, fallbackConfiguration); + return new EffectiveConfiguration(configuration, branchConfiguration, fallbackConfiguration: fallbackConfiguration); } public static IBranchConfiguration GetBranchConfiguration(this IGitVersionConfiguration configuration, IBranch branch) @@ -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); } 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..bf16c9cc9a 100644 --- a/src/GitVersion.Core/Git/ICommit.cs +++ b/src/GitVersion.Core/Git/ICommit.cs @@ -7,4 +7,5 @@ public interface ICommit : IEquatable, IComparable, IGitObjec DateTimeOffset When { get; } string Message { get; } + IEnumerable DiffPaths { get; } } diff --git a/src/GitVersion.Core/Git/ITreeChanges.cs b/src/GitVersion.Core/Git/ITreeChanges.cs new file mode 100644 index 0000000000..469caf9db8 --- /dev/null +++ b/src/GitVersion.Core/Git/ITreeChanges.cs @@ -0,0 +1,6 @@ +namespace GitVersion.Git; + +public interface ITreeChanges +{ + IEnumerable 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..dfceb7c7e7 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.IEnumerable! +GitVersion.Git.ITreeChanges +GitVersion.Git.ITreeChanges.Paths.get -> System.Collections.Generic.IEnumerable! +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..8a0543a3ea --- /dev/null +++ b/src/GitVersion.Core/VersionCalculation/PathFilter.cs @@ -0,0 +1,51 @@ +using System.Diagnostics.CodeAnalysis; +using System.Text.RegularExpressions; +using GitVersion.Git; + +namespace GitVersion.VersionCalculation; + +internal class PathFilter( IEnumerable paths) : IVersionFilter +{ + private readonly List pathsRegexes = paths.Select(path => new Regex(path, RegexOptions.IgnoreCase | RegexOptions.Compiled)).ToList(); + private readonly Dictionary pathMatchCache = []; + + public bool Exclude(IBaseVersion baseVersion, [NotNullWhen(true)] out string? reason) + { + ArgumentNullException.ThrowIfNull(baseVersion); + + reason = null; + if (baseVersion.Source.StartsWith("Fallback") || baseVersion.Source.StartsWith("Git tag") || baseVersion.Source.StartsWith("NextVersion")) return false; + + return Exclude(baseVersion.BaseVersionSource, out reason); + } + + public bool Exclude(ICommit? commit, [NotNullWhen(true)] out string? reason) + { + reason = null; + + if (commit != null) + { + var patchPaths = commit.DiffPaths; + + if (patchPaths != null) + { + foreach (var path in patchPaths) + { + if (!pathMatchCache.TryGetValue(path, out var isMatch)) + { + isMatch = this.pathsRegexes.Any(regex => regex.IsMatch(path)); + pathMatchCache[path] = isMatch; + } + + if (isMatch) + { + reason = "Source was ignored due to commit path matching ignore regex"; + return true; + } + } + } + } + + 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..e453f4bf98 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,20 @@ internal Commit(LibGit2Sharp.Commit innerCommit) : base(innerCommit) public IReadOnlyList Parents => this.parentsLazy.Value; public DateTimeOffset When { get; } public string Message => this.innerCommit.Message; + // TODO implement tag prefix filtering before returning the paths. + public IEnumerable DiffPaths + { + get + { + if (pathsCache.TryGetValue(this.Sha, out var paths)) + return paths; + else + return this.CommitChanges?.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 ITreeChanges CommitChanges => new TreeChanges(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..231fef0e85 100644 --- a/src/GitVersion.LibGit2Sharp/Git/GitRepository.cs +++ b/src/GitVersion.LibGit2Sharp/Git/GitRepository.cs @@ -1,3 +1,4 @@ +using System.Collections.Concurrent; using GitVersion.Extensions; using GitVersion.Helpers; using LibGit2Sharp; @@ -7,6 +8,7 @@ namespace GitVersion.Git; internal sealed partial class GitRepository { private Lazy? repositoryLazy; + private readonly ConcurrentDictionary?> patchPathsCache = new(); private IRepository RepositoryInstance { @@ -16,17 +18,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 +50,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 +89,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..48089a6cb5 --- /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 IEnumerable Paths => this.innerTreeChanges.Select(element => element.Path); +} From 73904a1ff314a521fefbf5c66f67ced34688f5ae Mon Sep 17 00:00:00 2001 From: roeil Date: Wed, 21 May 2025 08:33:58 +0300 Subject: [PATCH 02/11] pr --- .../IgnoreConfiguration.cs | 6 ++-- .../MergeMessageBaseVersionStrategyTests.cs | 2 +- .../Configuration/IIgnoreConfiguration.cs | 2 +- .../Extensions/ConfigurationExtensions.cs | 4 +-- src/GitVersion.Core/Git/ICommit.cs | 2 +- src/GitVersion.Core/Git/ITreeChanges.cs | 2 +- src/GitVersion.Core/PublicAPI.Unshipped.txt | 4 +-- .../VersionCalculation/PathFilter.cs | 30 +++++++++---------- src/GitVersion.LibGit2Sharp/Git/Commit.cs | 14 +++++---- .../Git/GitRepository.cs | 2 -- .../Git/TreeChanges.cs | 2 +- 11 files changed, 34 insertions(+), 36 deletions(-) diff --git a/src/GitVersion.Configuration/IgnoreConfiguration.cs b/src/GitVersion.Configuration/IgnoreConfiguration.cs index 636571e2a8..4ea9d6d86e 100644 --- a/src/GitVersion.Configuration/IgnoreConfiguration.cs +++ b/src/GitVersion.Configuration/IgnoreConfiguration.cs @@ -24,12 +24,12 @@ public string? BeforeString [JsonPropertyDescription("A sequence of SHAs to be excluded from the version calculations.")] public HashSet Shas { get; init; } = []; - [JsonIgnore] - public bool IsEmpty => Before == null && Shas.Count == 0 && Paths.Count == 0; - 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 && Paths.Count == 0; } diff --git a/src/GitVersion.Core.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs b/src/GitVersion.Core.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs index bc67a4e604..1f03f3a9ea 100644 --- a/src/GitVersion.Core.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs +++ b/src/GitVersion.Core.Tests/VersionCalculation/Strategies/MergeMessageBaseVersionStrategyTests.cs @@ -204,7 +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 IEnumerable DiffPaths => 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/IIgnoreConfiguration.cs b/src/GitVersion.Core/Configuration/IIgnoreConfiguration.cs index d94c778fb1..ea19f6d746 100644 --- a/src/GitVersion.Core/Configuration/IIgnoreConfiguration.cs +++ b/src/GitVersion.Core/Configuration/IIgnoreConfiguration.cs @@ -8,5 +8,5 @@ public interface IIgnoreConfiguration IReadOnlyCollection Paths { get; } - bool IsEmpty => Before == null && Shas.Count == 0 && Paths.Count == 0; + bool IsEmpty { get; } } diff --git a/src/GitVersion.Core/Extensions/ConfigurationExtensions.cs b/src/GitVersion.Core/Extensions/ConfigurationExtensions.cs index c8c0cb4fd1..6f794c91d1 100644 --- a/src/GitVersion.Core/Extensions/ConfigurationExtensions.cs +++ b/src/GitVersion.Core/Extensions/ConfigurationExtensions.cs @@ -25,7 +25,7 @@ public static EffectiveConfiguration GetEffectiveConfiguration( { fallbackConfiguration = parentConfiguration; } - return new EffectiveConfiguration(configuration, branchConfiguration, fallbackConfiguration: fallbackConfiguration); + return new EffectiveConfiguration(configuration, branchConfiguration, fallbackConfiguration); } public static IBranchConfiguration GetBranchConfiguration(this IGitVersionConfiguration configuration, IBranch branch) @@ -44,7 +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); + 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 bf16c9cc9a..d0c5d666e2 100644 --- a/src/GitVersion.Core/Git/ICommit.cs +++ b/src/GitVersion.Core/Git/ICommit.cs @@ -7,5 +7,5 @@ public interface ICommit : IEquatable, IComparable, IGitObjec DateTimeOffset When { get; } string Message { get; } - IEnumerable DiffPaths { get; } + IReadOnlyList DiffPaths { get; } } diff --git a/src/GitVersion.Core/Git/ITreeChanges.cs b/src/GitVersion.Core/Git/ITreeChanges.cs index 469caf9db8..28a4600d68 100644 --- a/src/GitVersion.Core/Git/ITreeChanges.cs +++ b/src/GitVersion.Core/Git/ITreeChanges.cs @@ -2,5 +2,5 @@ namespace GitVersion.Git; public interface ITreeChanges { - IEnumerable Paths { get; } + IReadOnlyList Paths { get; } } diff --git a/src/GitVersion.Core/PublicAPI.Unshipped.txt b/src/GitVersion.Core/PublicAPI.Unshipped.txt index dfceb7c7e7..505df687a4 100644 --- a/src/GitVersion.Core/PublicAPI.Unshipped.txt +++ b/src/GitVersion.Core/PublicAPI.Unshipped.txt @@ -147,7 +147,7 @@ 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.IEnumerable! +GitVersion.Git.ICommit.DiffPaths.get -> System.Collections.Generic.IReadOnlyList! GitVersion.Git.ITreeChanges -GitVersion.Git.ITreeChanges.Paths.get -> System.Collections.Generic.IEnumerable! +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/PathFilter.cs b/src/GitVersion.Core/VersionCalculation/PathFilter.cs index 8a0543a3ea..a10bc22c5c 100644 --- a/src/GitVersion.Core/VersionCalculation/PathFilter.cs +++ b/src/GitVersion.Core/VersionCalculation/PathFilter.cs @@ -1,13 +1,14 @@ +using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using System.Text.RegularExpressions; using GitVersion.Git; namespace GitVersion.VersionCalculation; -internal class PathFilter( IEnumerable paths) : IVersionFilter +internal class PathFilter(IReadOnlyList paths) : IVersionFilter { - private readonly List pathsRegexes = paths.Select(path => new Regex(path, RegexOptions.IgnoreCase | RegexOptions.Compiled)).ToList(); - private readonly Dictionary pathMatchCache = []; + private readonly List pathsRegexes = [.. paths.Select(path => new Regex(path, RegexOptions.IgnoreCase | RegexOptions.Compiled))]; + private readonly ConcurrentDictionary pathMatchCache = []; public bool Exclude(IBaseVersion baseVersion, [NotNullWhen(true)] out string? reason) { @@ -27,21 +28,18 @@ public bool Exclude(ICommit? commit, [NotNullWhen(true)] out string? reason) { var patchPaths = commit.DiffPaths; - if (patchPaths != null) + foreach (var path in patchPaths) { - foreach (var path in patchPaths) + if (!pathMatchCache.TryGetValue(path, out var isMatch)) { - if (!pathMatchCache.TryGetValue(path, out var isMatch)) - { - isMatch = this.pathsRegexes.Any(regex => regex.IsMatch(path)); - pathMatchCache[path] = isMatch; - } - - if (isMatch) - { - reason = "Source was ignored due to commit path matching ignore regex"; - return true; - } + isMatch = this.pathsRegexes.Any(regex => regex.IsMatch(path)); + pathMatchCache[path] = isMatch; + } + + if (isMatch) + { + reason = "Source was ignored due to commit path matching ignore regex"; + return true; } } } diff --git a/src/GitVersion.LibGit2Sharp/Git/Commit.cs b/src/GitVersion.LibGit2Sharp/Git/Commit.cs index e453f4bf98..91e08df0a7 100644 --- a/src/GitVersion.LibGit2Sharp/Git/Commit.cs +++ b/src/GitVersion.LibGit2Sharp/Git/Commit.cs @@ -28,19 +28,21 @@ internal Commit(LibGit2Sharp.Commit innerCommit, LibGit2Sharp.Diff repoDiff) : b public DateTimeOffset When { get; } public string Message => this.innerCommit.Message; // TODO implement tag prefix filtering before returning the paths. - public IEnumerable DiffPaths + public IReadOnlyList DiffPaths { get { - if (pathsCache.TryGetValue(this.Sha, out var paths)) - return paths; - else - return this.CommitChanges?.Paths ?? []; + 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 ITreeChanges CommitChanges => new TreeChanges(this.repoDiff.Compare(this.innerCommit.Tree, this.innerCommit.Parents.FirstOrDefault()?.Tree)); + private TreeChanges CommitChanges => new TreeChanges(this.repoDiff.Compare(this.innerCommit.Tree, this.innerCommit.Parents.FirstOrDefault()?.Tree)); } diff --git a/src/GitVersion.LibGit2Sharp/Git/GitRepository.cs b/src/GitVersion.LibGit2Sharp/Git/GitRepository.cs index 231fef0e85..3d2fd756ed 100644 --- a/src/GitVersion.LibGit2Sharp/Git/GitRepository.cs +++ b/src/GitVersion.LibGit2Sharp/Git/GitRepository.cs @@ -1,4 +1,3 @@ -using System.Collections.Concurrent; using GitVersion.Extensions; using GitVersion.Helpers; using LibGit2Sharp; @@ -8,7 +7,6 @@ namespace GitVersion.Git; internal sealed partial class GitRepository { private Lazy? repositoryLazy; - private readonly ConcurrentDictionary?> patchPathsCache = new(); private IRepository RepositoryInstance { diff --git a/src/GitVersion.LibGit2Sharp/Git/TreeChanges.cs b/src/GitVersion.LibGit2Sharp/Git/TreeChanges.cs index 48089a6cb5..9ee9385a7e 100644 --- a/src/GitVersion.LibGit2Sharp/Git/TreeChanges.cs +++ b/src/GitVersion.LibGit2Sharp/Git/TreeChanges.cs @@ -4,5 +4,5 @@ internal sealed class TreeChanges(LibGit2Sharp.TreeChanges innerTreeChanges) : I { private readonly LibGit2Sharp.TreeChanges innerTreeChanges = innerTreeChanges ?? throw new ArgumentNullException(nameof(innerTreeChanges)); - public IEnumerable Paths => this.innerTreeChanges.Select(element => element.Path); + public IReadOnlyList Paths => [.. this.innerTreeChanges.Select(element => element.Path)]; } From f8f1a245268f2660caa405a78b2929814076f2cb Mon Sep 17 00:00:00 2001 From: Artur Stolear Date: Wed, 21 May 2025 06:12:56 +0000 Subject: [PATCH 03/11] Docs changes --- docs/input/docs/reference/configuration.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) 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: From 5a83413a6c080863fffe97417539f4095cc7546d Mon Sep 17 00:00:00 2001 From: roeil Date: Sun, 1 Jun 2025 18:51:51 +0300 Subject: [PATCH 04/11] test --- .../GitRepositoryTestingExtensions.cs | 7 ++ .../IntegrationTests/IgnoreCommitScenarios.cs | 106 +++++++++++++++++- .../VersionCalculation/PathFilterTests.cs | 52 ++++++++- .../VersionCalculation/PathFilter.cs | 10 +- src/GitVersion.LibGit2Sharp/Git/Commit.cs | 2 +- 5 files changed, 165 insertions(+), 12 deletions(-) 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/PathFilterTests.cs b/src/GitVersion.Core.Tests/VersionCalculation/PathFilterTests.cs index 8c8286458c..5fab3e78f1 100644 --- a/src/GitVersion.Core.Tests/VersionCalculation/PathFilterTests.cs +++ b/src/GitVersion.Core.Tests/VersionCalculation/PathFilterTests.cs @@ -7,5 +7,55 @@ namespace GitVersion.Core.Tests; public class PathFilterTests : TestBase { [Test] - public void VerifyNullGuard() => Should.Throw(() => new PathFilter(null!)); + 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 WhenCommitSourceStartsWithCommitTagShouldNotBeExcluded() + { + var commit = GitRepositoryTestingExtensions.CreateMockCommit(["/path"]); + BaseVersion version = new("Git tag: v1.0.0", new SemanticVersion(1), commit); + var sut = new PathFilter(commit.DiffPaths); + + var result = sut.Exclude(version, out var reason); + + result.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/VersionCalculation/PathFilter.cs b/src/GitVersion.Core/VersionCalculation/PathFilter.cs index a10bc22c5c..6201ebf478 100644 --- a/src/GitVersion.Core/VersionCalculation/PathFilter.cs +++ b/src/GitVersion.Core/VersionCalculation/PathFilter.cs @@ -7,16 +7,12 @@ namespace GitVersion.VersionCalculation; internal class PathFilter(IReadOnlyList paths) : IVersionFilter { - private readonly List pathsRegexes = [.. paths.Select(path => new Regex(path, RegexOptions.IgnoreCase | RegexOptions.Compiled))]; + private readonly List 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); - - reason = null; - if (baseVersion.Source.StartsWith("Fallback") || baseVersion.Source.StartsWith("Git tag") || baseVersion.Source.StartsWith("NextVersion")) return false; - return Exclude(baseVersion.BaseVersionSource, out reason); } @@ -26,9 +22,7 @@ public bool Exclude(ICommit? commit, [NotNullWhen(true)] out string? reason) if (commit != null) { - var patchPaths = commit.DiffPaths; - - foreach (var path in patchPaths) + foreach (var path in commit.DiffPaths) { if (!pathMatchCache.TryGetValue(path, out var isMatch)) { diff --git a/src/GitVersion.LibGit2Sharp/Git/Commit.cs b/src/GitVersion.LibGit2Sharp/Git/Commit.cs index 91e08df0a7..3984244f58 100644 --- a/src/GitVersion.LibGit2Sharp/Git/Commit.cs +++ b/src/GitVersion.LibGit2Sharp/Git/Commit.cs @@ -44,5 +44,5 @@ public IReadOnlyList DiffPaths 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 TreeChanges(this.repoDiff.Compare(this.innerCommit.Tree, this.innerCommit.Parents.FirstOrDefault()?.Tree)); + private TreeChanges CommitChanges => new(this.repoDiff.Compare(this.innerCommit.Tree, this.innerCommit.Parents.FirstOrDefault()?.Tree)); } From da879a10e486c3a9a67334c6605b9a4611f615ce Mon Sep 17 00:00:00 2001 From: roeil Date: Wed, 4 Jun 2025 08:28:03 +0300 Subject: [PATCH 05/11] misc --- src/GitVersion.Core/Git/ICommit.cs | 1 + src/GitVersion.Core/VersionCalculation/PathFilter.cs | 2 +- src/GitVersion.LibGit2Sharp/Git/Commit.cs | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/GitVersion.Core/Git/ICommit.cs b/src/GitVersion.Core/Git/ICommit.cs index d0c5d666e2..8d3b225655 100644 --- a/src/GitVersion.Core/Git/ICommit.cs +++ b/src/GitVersion.Core/Git/ICommit.cs @@ -7,5 +7,6 @@ public interface ICommit : IEquatable, IComparable, IGitObjec DateTimeOffset When { get; } string Message { get; } + IReadOnlyList DiffPaths { get; } } diff --git a/src/GitVersion.Core/VersionCalculation/PathFilter.cs b/src/GitVersion.Core/VersionCalculation/PathFilter.cs index 6201ebf478..efb20b7cc2 100644 --- a/src/GitVersion.Core/VersionCalculation/PathFilter.cs +++ b/src/GitVersion.Core/VersionCalculation/PathFilter.cs @@ -7,7 +7,7 @@ namespace GitVersion.VersionCalculation; internal class PathFilter(IReadOnlyList paths) : IVersionFilter { - private readonly List pathsRegexes = [.. paths.Select(path => new Regex(path, RegexOptions.Compiled))]; + 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) diff --git a/src/GitVersion.LibGit2Sharp/Git/Commit.cs b/src/GitVersion.LibGit2Sharp/Git/Commit.cs index 3984244f58..95f30e81cc 100644 --- a/src/GitVersion.LibGit2Sharp/Git/Commit.cs +++ b/src/GitVersion.LibGit2Sharp/Git/Commit.cs @@ -27,7 +27,6 @@ internal Commit(LibGit2Sharp.Commit innerCommit, LibGit2Sharp.Diff repoDiff) : b public IReadOnlyList Parents => this.parentsLazy.Value; public DateTimeOffset When { get; } public string Message => this.innerCommit.Message; - // TODO implement tag prefix filtering before returning the paths. public IReadOnlyList DiffPaths { get From 34bb84decfe50e89cd1ac5e1c12811ee72eef43d Mon Sep 17 00:00:00 2001 From: roeil Date: Thu, 5 Jun 2025 20:28:21 +0300 Subject: [PATCH 06/11] refactor: paths filter --- .../VersionCalculation/PathFilterTests.cs | 13 ------ .../VersionCalculation/PathFilter.cs | 40 +++++++++++++------ 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/GitVersion.Core.Tests/VersionCalculation/PathFilterTests.cs b/src/GitVersion.Core.Tests/VersionCalculation/PathFilterTests.cs index 5fab3e78f1..efffb84e18 100644 --- a/src/GitVersion.Core.Tests/VersionCalculation/PathFilterTests.cs +++ b/src/GitVersion.Core.Tests/VersionCalculation/PathFilterTests.cs @@ -36,19 +36,6 @@ public void WhenPathMismatchShouldNotExclude() reason.ShouldBeNull(); } - [Test] - public void WhenCommitSourceStartsWithCommitTagShouldNotBeExcluded() - { - var commit = GitRepositoryTestingExtensions.CreateMockCommit(["/path"]); - BaseVersion version = new("Git tag: v1.0.0", new SemanticVersion(1), commit); - var sut = new PathFilter(commit.DiffPaths); - - var result = sut.Exclude(version, out var reason); - - result.ShouldBeFalse(); - reason.ShouldBeNull(); - } - [Test] public void ExcludeShouldAcceptVersionWithNullCommit() { diff --git a/src/GitVersion.Core/VersionCalculation/PathFilter.cs b/src/GitVersion.Core/VersionCalculation/PathFilter.cs index efb20b7cc2..cb801b6351 100644 --- a/src/GitVersion.Core/VersionCalculation/PathFilter.cs +++ b/src/GitVersion.Core/VersionCalculation/PathFilter.cs @@ -5,7 +5,13 @@ namespace GitVersion.VersionCalculation; -internal class PathFilter(IReadOnlyList paths) : IVersionFilter +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 = []; @@ -16,25 +22,33 @@ public bool Exclude(IBaseVersion baseVersion, [NotNullWhen(true)] out string? re 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) { - foreach (var path in commit.DiffPaths) + switch (mode) { - if (!pathMatchCache.TryGetValue(path, out var isMatch)) - { - isMatch = this.pathsRegexes.Any(regex => regex.IsMatch(path)); - pathMatchCache[path] = isMatch; - } - - if (isMatch) - { - reason = "Source was ignored due to commit path matching ignore regex"; - return true; - } + case PathFilterMode.Inclusive: + { + if (commit.DiffPaths.All(this.IsMatch)) + { + reason = "Source was ignored due to all commit paths matching ignore regex"; + return true; + } + break; + } } } From b603346b2b9a8e26d8501033f2e62a9d5934d40c Mon Sep 17 00:00:00 2001 From: roeil Date: Thu, 5 Jun 2025 20:28:32 +0300 Subject: [PATCH 07/11] fix: new-cli --- .../GitVersion.Core.Libgit2Sharp.csproj | 3 +++ 1 file changed, 3 insertions(+) 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 From 5a2f6fa86733ebd055d7326a43bc80dbfca1d284 Mon Sep 17 00:00:00 2001 From: roeil Date: Thu, 5 Jun 2025 20:28:54 +0300 Subject: [PATCH 08/11] docs: add ignore paths to configuration docs --- docs/input/docs/reference/configuration.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/input/docs/reference/configuration.md b/docs/input/docs/reference/configuration.md index eb6302ab7b..6b4b0db808 100644 --- a/docs/input/docs/reference/configuration.md +++ b/docs/input/docs/reference/configuration.md @@ -624,6 +624,24 @@ Date and time in the format `yyyy-MM-ddTHH:mm:ss` (eg `commits-before: 2015-10-23T12:23:15`) to setup an exclusion range. Effectively any commit before `commits-before` will be ignored. +#### paths +A sequence of regular expressions that represent paths in the repository. Commits that modify these paths will be excluded from version calculations. For example, to filter out commits that belong to `docs`: +```yaml +ignore: + paths: + - ^docs\/ +``` +This ignore config can also be used to filter only those commits that belong to a specific project in a monorepo. For GitVersion to consider only commits that are part of subdirectory called `projectA`, use a regex that matches all paths except those starting with `ProjectA`: +```yaml +ignore: + paths: + - ^(?!ProjectA).*$ +``` + +::: {.alert .alert-warning} +A commit is ignored by the `ignore.paths` configuration only if **all paths** changed in that commit match one of the specified regular expressions. If any file in the commit does not match an ignore pattern, the commit will be included in version calculations. +::: + ### merge-message-formats Custom merge message formats to enable identification of merge messages that do not From 4d15893e898fb751c439547e0ab1b2cfc27c7725 Mon Sep 17 00:00:00 2001 From: Artur Stolear Date: Thu, 5 Jun 2025 17:39:00 +0000 Subject: [PATCH 09/11] Docs changes --- docs/input/docs/reference/configuration.md | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/docs/input/docs/reference/configuration.md b/docs/input/docs/reference/configuration.md index 6b4b0db808..eb6302ab7b 100644 --- a/docs/input/docs/reference/configuration.md +++ b/docs/input/docs/reference/configuration.md @@ -624,24 +624,6 @@ Date and time in the format `yyyy-MM-ddTHH:mm:ss` (eg `commits-before: 2015-10-23T12:23:15`) to setup an exclusion range. Effectively any commit before `commits-before` will be ignored. -#### paths -A sequence of regular expressions that represent paths in the repository. Commits that modify these paths will be excluded from version calculations. For example, to filter out commits that belong to `docs`: -```yaml -ignore: - paths: - - ^docs\/ -``` -This ignore config can also be used to filter only those commits that belong to a specific project in a monorepo. For GitVersion to consider only commits that are part of subdirectory called `projectA`, use a regex that matches all paths except those starting with `ProjectA`: -```yaml -ignore: - paths: - - ^(?!ProjectA).*$ -``` - -::: {.alert .alert-warning} -A commit is ignored by the `ignore.paths` configuration only if **all paths** changed in that commit match one of the specified regular expressions. If any file in the commit does not match an ignore pattern, the commit will be included in version calculations. -::: - ### merge-message-formats Custom merge message formats to enable identification of merge messages that do not From e7398522341f65665cd3fa2d5590e5d202a29416 Mon Sep 17 00:00:00 2001 From: roeil Date: Wed, 11 Jun 2025 20:36:03 +0300 Subject: [PATCH 10/11] docs --- docs/input/docs/reference/configuration.md | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/docs/input/docs/reference/configuration.md b/docs/input/docs/reference/configuration.md index eb6302ab7b..68e757edc5 100644 --- a/docs/input/docs/reference/configuration.md +++ b/docs/input/docs/reference/configuration.md @@ -624,6 +624,40 @@ Date and time in the format `yyyy-MM-ddTHH:mm:ss` (eg `commits-before: 2015-10-23T12:23:15`) to setup an exclusion range. Effectively any commit before `commits-before` will be ignored. +#### paths +A sequence of regular expressions that represent paths in the repository. Commits that modify these paths will be excluded from version calculations. For example, to filter out commits that belong to `docs`: +```yaml +ignore: + paths: + - ^docs\/ +``` +##### *Monorepo* +This ignore config can be used to filter only those commits that belong to a specific project in a monorepo. +As an example, consider a monorepo consisting of subdirectories for `ProjectA`, `ProjectB` and a shared `LibraryC`. For GitVersion to consider only commits that are part of `projectA` and shared library `LibraryC`, a regex that matches all paths except those starting with `ProjectA` or `LibraryC` can be used. Either one of the following configs would filter out `ProjectB`. +* Specific match on `/ProjectB/*`: +```yaml +ignore: + paths: + - `^\/ProductB\/.*` +``` +* Negative lookahead on anything other than `/ProjectA/*` and `/LibraryC/*`: +```yaml +ignore: + paths: + - `^(?!\/ProductA\/|\/LibraryC\/).*` +``` +A commit having changes only in `/ProjectB/*` path would be ignored. A commit having changes in the following paths wouldn't be ignored: +* `/ProductA/*` +* `/LibraryC/*` +* `/ProductA/*` and `/LibraryC/*` +* `/ProductA/*` and `/ProductB/*` +* `/LibraryC/*` and `/ProductB/*` +* `/ProductA/*` and `/ProductB/*` and `/LibraryC/*` + +::: {.alert .alert-warning} +A commit is ignored by the `ignore.paths` configuration only if **all paths** changed in that commit match one or more of the specified regular expressions. If a path in a commit does not match any one of the ignore patterns, that commit will be included in version calculations. +::: + ### merge-message-formats Custom merge message formats to enable identification of merge messages that do not From f330944632ada9910f90c76becebaaecad68fe6d Mon Sep 17 00:00:00 2001 From: Artur Stolear Date: Wed, 11 Jun 2025 17:44:49 +0000 Subject: [PATCH 11/11] Docs changes --- docs/input/docs/reference/configuration.md | 34 ---------------------- 1 file changed, 34 deletions(-) diff --git a/docs/input/docs/reference/configuration.md b/docs/input/docs/reference/configuration.md index 68e757edc5..eb6302ab7b 100644 --- a/docs/input/docs/reference/configuration.md +++ b/docs/input/docs/reference/configuration.md @@ -624,40 +624,6 @@ Date and time in the format `yyyy-MM-ddTHH:mm:ss` (eg `commits-before: 2015-10-23T12:23:15`) to setup an exclusion range. Effectively any commit before `commits-before` will be ignored. -#### paths -A sequence of regular expressions that represent paths in the repository. Commits that modify these paths will be excluded from version calculations. For example, to filter out commits that belong to `docs`: -```yaml -ignore: - paths: - - ^docs\/ -``` -##### *Monorepo* -This ignore config can be used to filter only those commits that belong to a specific project in a monorepo. -As an example, consider a monorepo consisting of subdirectories for `ProjectA`, `ProjectB` and a shared `LibraryC`. For GitVersion to consider only commits that are part of `projectA` and shared library `LibraryC`, a regex that matches all paths except those starting with `ProjectA` or `LibraryC` can be used. Either one of the following configs would filter out `ProjectB`. -* Specific match on `/ProjectB/*`: -```yaml -ignore: - paths: - - `^\/ProductB\/.*` -``` -* Negative lookahead on anything other than `/ProjectA/*` and `/LibraryC/*`: -```yaml -ignore: - paths: - - `^(?!\/ProductA\/|\/LibraryC\/).*` -``` -A commit having changes only in `/ProjectB/*` path would be ignored. A commit having changes in the following paths wouldn't be ignored: -* `/ProductA/*` -* `/LibraryC/*` -* `/ProductA/*` and `/LibraryC/*` -* `/ProductA/*` and `/ProductB/*` -* `/LibraryC/*` and `/ProductB/*` -* `/ProductA/*` and `/ProductB/*` and `/LibraryC/*` - -::: {.alert .alert-warning} -A commit is ignored by the `ignore.paths` configuration only if **all paths** changed in that commit match one or more of the specified regular expressions. If a path in a commit does not match any one of the ignore patterns, that commit will be included in version calculations. -::: - ### merge-message-formats Custom merge message formats to enable identification of merge messages that do not