Skip to content

Feature/pathfilter #2862

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/GitVersion.Core/Core/Abstractions/IRepositoryStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,7 @@ public interface IRepositoryStore
VersionField? DetermineIncrementedField(BaseVersion baseVersion, GitVersionContext context);

int GetNumberOfUncommittedChanges();

public IGitRepository Repository { get; }
}
}
2 changes: 1 addition & 1 deletion src/GitVersion.Core/Core/GitVersionContextFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public GitVersionContext Create(GitVersionOptions? gitVersionOptions)
var currentCommitTaggedVersion = this.repositoryStore.GetCurrentCommitTaggedVersion(currentCommit, effectiveConfiguration);
var numberOfUncommittedChanges = this.repositoryStore.GetNumberOfUncommittedChanges();

return new GitVersionContext(currentBranch, currentCommit, configuration, effectiveConfiguration, currentCommitTaggedVersion, numberOfUncommittedChanges);
return new GitVersionContext(currentBranch, currentCommit, configuration, effectiveConfiguration, currentCommitTaggedVersion, numberOfUncommittedChanges, this.repositoryStore.Repository);
}
}
}
1 change: 1 addition & 0 deletions src/GitVersion.Core/Core/RepositoryStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -491,5 +491,6 @@ private ICommit GetForwardMerge(ICommit? commitToFindCommonBase, ICommit? findMe
public ICommit FindMergeBase(ICommit commit, ICommit mainlineTip) => this.repository.FindMergeBase(commit, mainlineTip);

public int GetNumberOfUncommittedChanges() => this.repository.GetNumberOfUncommittedChanges();
public IGitRepository Repository => this.repository;
}
}
4 changes: 4 additions & 0 deletions src/GitVersion.Core/Git/IGitRepository.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System.Collections.Generic;

namespace GitVersion
{
public interface IGitRepository
Expand All @@ -14,5 +16,7 @@ public interface IGitRepository

ICommit FindMergeBase(ICommit commit, ICommit otherCommit);
int GetNumberOfUncommittedChanges();

IEnumerable<string> DiffPathChanges(ICommit commitFrom, ICommit commitTo);
}
}
13 changes: 12 additions & 1 deletion src/GitVersion.Core/Model/Configuration/IgnoreConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ namespace GitVersion.Model.Configuration
{
public class IgnoreConfig
{
public IgnoreConfig() => ShAs = Enumerable.Empty<string>();
public IgnoreConfig()
{
ShAs = Enumerable.Empty<string>();
PathFilters = new PathFilterConfig();
}

[YamlMember(Alias = "commits-before")]
public DateTimeOffset? Before { get; set; }
Expand All @@ -20,10 +24,17 @@ public class IgnoreConfig
public virtual bool IsEmpty => Before == null
&& (ShAs == null || ShAs.Any() == false);

[YamlMember(Alias = "paths")]
public PathFilterConfig PathFilters { get; set; }

public virtual IEnumerable<IVersionFilter> ToFilters()
{
if (ShAs.Any()) yield return new ShaVersionFilter(ShAs);
if (Before.HasValue) yield return new MinDateVersionFilter(Before.Value);
foreach (var filter in PathFilters.ToFilters())
{
yield return filter;
}
}
}
}
28 changes: 28 additions & 0 deletions src/GitVersion.Core/Model/Configuration/PathFilterConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Collections.Generic;
using System.Linq;
using GitVersion.VersionCalculation;
using YamlDotNet.Serialization;

namespace GitVersion.Model.Configuration
{
public class PathFilterConfig
{
public PathFilterConfig()
{
Include = Enumerable.Empty<string>();
Exclude = Enumerable.Empty<string>();
}

[YamlMember(Alias = "exclude")]
public IEnumerable<string> Exclude { get; set; }

[YamlMember(Alias = "include")]
public IEnumerable<string> Include { get; set; }

public virtual IEnumerable<IVersionFilter> ToFilters()
{
if (Include.Any()) yield return new PathFilter(Include, PathFilter.PathFilterMode.Inclusive);
if (Exclude.Any()) yield return new PathFilter(Exclude, PathFilter.PathFilterMode.Exclusive);
}
}
}
5 changes: 4 additions & 1 deletion src/GitVersion.Core/Model/GitVersionContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ public class GitVersionContext

public int NumberOfUncommittedChanges { get; }

public IGitRepository Repository { get; }

public GitVersionContext()
{
}

public GitVersionContext(IBranch currentBranch, ICommit? currentCommit,
Config configuration, EffectiveConfiguration effectiveConfiguration, SemanticVersion currentCommitTaggedVersion, int numberOfUncommittedChanges)
Config configuration, EffectiveConfiguration effectiveConfiguration, SemanticVersion currentCommitTaggedVersion, int numberOfUncommittedChanges, IGitRepository repository)
{
CurrentCommit = currentCommit;
CurrentBranch = currentBranch;
Expand All @@ -36,6 +38,7 @@ public GitVersionContext(IBranch currentBranch, ICommit? currentCommit,
CurrentCommitTaggedVersion = currentCommitTaggedVersion;

NumberOfUncommittedChanges = numberOfUncommittedChanges;
Repository = repository;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using GitVersion.Common;
using GitVersion.Configuration;
using GitVersion.Logging;
using Polly;

namespace GitVersion.VersionCalculation
{
Expand Down Expand Up @@ -78,6 +79,7 @@ public BaseVersion GetBaseVersion()
throw new Exception("Base version should not be null");

var calculatedBase = new BaseVersion(
this.versionContext.Value,
maxVersion.Version!.Source, maxVersion.Version.ShouldIncrement, maxVersion.Version.SemanticVersion,
baseVersionWithOldestSource.BaseVersionSource, maxVersion.Version.BranchNameOverride);

Expand Down Expand Up @@ -126,6 +128,7 @@ private void FixTheBaseVersionSourceOfMergeMessageStrategyIfReleaseBranchWasMerg
{
var parents = baseVersion.Version.BaseVersionSource!.Parents.ToList();
baseVersion.Version = new BaseVersion(
this.versionContext.Value,
baseVersion.Version.Source,
baseVersion.Version.ShouldIncrement,
baseVersion.Version.SemanticVersion,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ namespace GitVersion.VersionCalculation
{
public class BaseVersion
{
public BaseVersion(string source, bool shouldIncrement, SemanticVersion semanticVersion, ICommit? baseVersionSource, string? branchNameOverride)
public BaseVersion(GitVersionContext context, string source, bool shouldIncrement, SemanticVersion semanticVersion, ICommit? baseVersionSource, string? branchNameOverride)
{
Source = source;
ShouldIncrement = shouldIncrement;
SemanticVersion = semanticVersion;
BaseVersionSource = baseVersionSource;
BranchNameOverride = branchNameOverride;
Context = context;
}

public GitVersionContext Context { get;}

public string Source { get; }

public bool ShouldIncrement { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public override IEnumerable<BaseVersion> GetVersions()
if (nextVersion.IsNullOrEmpty() || Context.IsCurrentCommitTagged)
yield break;
var semanticVersion = SemanticVersion.Parse(nextVersion, Context.Configuration?.GitTagPrefix);
yield return new BaseVersion("NextVersion in GitVersion configuration file", false, semanticVersion, null, null);
yield return new BaseVersion(Context, "NextVersion in GitVersion configuration file", false, semanticVersion, null, null);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public override IEnumerable<BaseVersion> GetVersions()

var baseVersionSource = this.repositoryStore.GetBaseVersionSource(currentBranchTip);

yield return new BaseVersion("Fallback base version", false, new SemanticVersion(minor: 1), baseVersionSource, null);
yield return new BaseVersion(Context, "Fallback base version", false, new SemanticVersion(minor: 1), baseVersionSource, null);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public override IEnumerable<BaseVersion> GetVersions()
var shouldIncrement = Context.Configuration?.PreventIncrementForMergedBranchVersion != true;
return new[]
{
new BaseVersion($"{MergeMessageStrategyPrefix} '{c.Message.Trim()}'", shouldIncrement, mergeMessage.Version, c, null)
new BaseVersion(Context, $"{MergeMessageStrategyPrefix} '{c.Message.Trim()}'", shouldIncrement, mergeMessage.Version, c, null)
};
}
return Enumerable.Empty<BaseVersion>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ internal IEnumerable<BaseVersion> GetTaggedVersions(IBranch? currentBranch, Date
private BaseVersion CreateBaseVersion(GitVersionContext context, VersionTaggedCommit version)
{
var shouldUpdateVersion = version.Commit.Sha != context.CurrentCommit?.Sha;
var baseVersion = new BaseVersion(FormatSource(version), shouldUpdateVersion, version.SemVer, version.Commit, null);
var baseVersion = new BaseVersion(Context, FormatSource(version), shouldUpdateVersion, version.SemVer, version.Commit, null);
return baseVersion;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ private IEnumerable<BaseVersion> ReleaseBranchBaseVersions()
// Need to drop branch overrides and give a bit more context about
// where this version came from
var source1 = "Release branch exists -> " + baseVersion.Source;
return new BaseVersion(source1,
return new BaseVersion(Context,
source1,
baseVersion.ShouldIncrement,
baseVersion.SemanticVersion,
baseVersion.BaseVersionSource,
Expand All @@ -95,7 +96,7 @@ private IEnumerable<BaseVersion> GetReleaseVersion(GitVersionContext context, IB

return this.releaseVersionStrategy
.GetVersions(tagPrefixRegex, releaseBranch)
.Select(b => new BaseVersion(b.Source, true, b.SemanticVersion, baseSource, b.BranchNameOverride));
.Select(b => new BaseVersion(Context, b.Source, true, b.SemanticVersion, baseSource, b.BranchNameOverride));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ internal IEnumerable<BaseVersion> GetVersions(string? tagPrefixRegex, IBranch? c
{
var commitBranchWasBranchedFrom = this.repositoryStore.FindCommitBranchWasBranchedFrom(currentBranch, Context.FullConfiguration);
var branchNameOverride = branchName.RegexReplace("[-/]" + versionInBranch.Item1, string.Empty);
yield return new BaseVersion("Version in branch name", false, versionInBranch.Item2, commitBranchWasBranchedFrom.Commit, branchNameOverride);
yield return new BaseVersion(Context, "Version in branch name", false, versionInBranch.Item2, commitBranchWasBranchedFrom.Commit, branchNameOverride);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ public class IncrementStrategyFinder : IIncrementStrategyFinder
var patchRegex = TryGetRegexOrDefault(context.Configuration?.PatchVersionBumpMessage, DefaultPatchPatternRegex);
var none = TryGetRegexOrDefault(context.Configuration?.NoBumpMessage, DefaultNoBumpPatternRegex);

var pathFilters = context.Configuration.VersionFilters.OfType<PathFilter>();

var increments = commits
.Where(c => !pathFilters.Any(f => f.Exclude(c, context, out _)))
.Select(c => GetIncrementFromCommit(c, majorRegex, minorRegex, patchRegex, none))
.Where(v => v != null)
.Select(v => v!.Value)
Expand Down
86 changes: 86 additions & 0 deletions src/GitVersion.Core/VersionCalculation/PathFilter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace GitVersion.VersionCalculation
{
public class PathFilter : IVersionFilter
{
private readonly static Dictionary<string, IEnumerable<string>> patchsCache = new Dictionary<string, IEnumerable<string>>();

public enum PathFilterMode { Inclusive, Exclusive }

private readonly IEnumerable<string> paths;
private readonly PathFilterMode mode;

public PathFilter(IEnumerable<string> paths, PathFilterMode mode = PathFilterMode.Inclusive)
{
this.paths = paths ?? throw new ArgumentNullException(nameof(paths));
this.mode = mode;
}

public bool Exclude(BaseVersion version, out string reason)
{
if (version == null) throw new ArgumentNullException(nameof(version));

reason = null;
if (version.Source.StartsWith("Fallback") || version.Source.StartsWith("Git tag") || version.Source.StartsWith("NextVersion")) return false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These string matches feel fragile. Is there not something more constant and typesafe we can base this comparison on?


return Exclude(version.BaseVersionSource, version.Context, out reason);
}

public bool Exclude(ICommit commit, GitVersionContext context, out string reason)
{
if (commit == null) throw new ArgumentNullException(nameof(commit));

reason = null;

var match = new System.Text.RegularExpressions.Regex($"^({context.Configuration.GitTagPrefix}).*$", System.Text.RegularExpressions.RegexOptions.Compiled);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a using statement to make the code terser.

Suggested change
var match = new System.Text.RegularExpressions.Regex($"^({context.Configuration.GitTagPrefix}).*$", System.Text.RegularExpressions.RegexOptions.Compiled);
var match = new Regex($"^({context.Configuration.GitTagPrefix}).*$", System.Text.RegularExpressions.RegexOptions.Compiled);




IEnumerable<string> patch = null;
if (!patchsCache.ContainsKey(commit.Sha))
{
//if (!context.Repository.Tags.Any(t => t.Target.Sha == commit.Sha && match.IsMatch(t.FriendlyName)))
//{
// Tree commitTree = commit.Tree; // Main Tree
// Tree parentCommitTree = commit.Parents.FirstOrDefault()?.Tree; // Secondary Tree
// patch = context.Repository.Diff.Compare<Patch>(parentCommitTree, commitTree); // Difference
//}
//patchsCache[commit.Sha] = patch;

if (!context.Repository.Tags.Any(t => t.TargetSha == commit.Sha && match.IsMatch(t.Name.Friendly)))

patch = context.Repository.DiffPathChanges(commit.Parents.FirstOrDefault(), commit);
}
patchsCache[commit.Sha] = patch;


patch = patchsCache[commit.Sha];
if (patch != null)
{
switch (mode)
{
case PathFilterMode.Inclusive:
if (!paths.Any(path => patch.Any(p => p.StartsWith(path, StringComparison.OrdinalIgnoreCase))))
{
reason = "Source was ignored due to commit path is not present";
return true;
}
break;
case PathFilterMode.Exclusive:
if (paths.Any(path => patch.All(p => p.StartsWith(path, StringComparison.OrdinalIgnoreCase))))
{
reason = "Source was ignored due to commit path excluded";
return true;
}
break;
}
}


return false;
}
}
}
11 changes: 11 additions & 0 deletions src/GitVersion.LibGit2Sharp/Git/GitRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,17 @@ public void Fetch(string remote, IEnumerable<string> refSpecs, AuthenticationInf
RepositoryExtensions.RunSafe(() =>
Commands.Fetch((Repository)repositoryInstance, remote, refSpecs, GetFetchOptions(auth), logMessage));

public IEnumerable<string> DiffPathChanges(ICommit commitFrom, ICommit commitTo)
{
var cFrom = this.repositoryInstance.Commits.Single(c => c.Sha == commitFrom.Sha);
var cTo = this.repositoryInstance.Commits.Single(c => c.Sha == commitTo.Sha);


var patch = this.repositoryInstance.Diff.Compare<Patch>(cTo.Parents.FirstOrDefault()?.Tree, cFrom.Tree);

return patch.Select(p => p.Path);
}

internal static string Discover(string? path) => Repository.Discover(path);

private static FetchOptions GetFetchOptions(AuthenticationInfo auth) =>
Expand Down