Skip to content
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

Add the ability to create a TreeRevFilter in LogCommand #149

Open
Jonathing opened this issue Mar 12, 2025 · 0 comments
Open

Add the ability to create a TreeRevFilter in LogCommand #149

Jonathing opened this issue Mar 12, 2025 · 0 comments

Comments

@Jonathing
Copy link
Contributor

Jonathing commented Mar 12, 2025

Description

Name entails. Currently, LogCommand only allows consumers to add/exclude paths and to add rev filters. These filters are tested in an inherent AND context which is normally fine, but I would like the ability to test them in OR context so that only one or the other filter would need to succeed in order for the commit to be included in the log.

My proposal is simply to allow some way for consumers to have the log command use a TreeRevFilter that uses the tree filter present in the log command (see line 115).

Motivation

I admit this is a strange use case, but this is a part of an end goal of mine to cut down on the amount of individual Git repositories used per individual project. A lot of projects I make are small, but are not necessarily inherently related to each other, and thus need individual version numbers. To account for this, I created Git Version which is a framework-agnostic tool that allows me to calculate version numbers for individual projects based on pre-defined tag prefixes, project paths, and additional filters for tags in general.

As a part of tag-based versioning, we create a new tag to show that a new version (usually a major.minor) has been created. This unfortunately throws a small wrench into path-based project versioning, as the tag could be created on a commit that does not modify the path for the project. My solution for this is to use an OR filter where either a) the commit modifies the project path or b) the commit is tagged with a tag that starts with the tag prefix.

Alternatives considered

There is currently no way to do this with LogCommand natively, so I'm using an implementation detail that depends on the result of #call returning a RevWalk that is casted to an Iterable<RevCommit>. I would prefer not to do this, so I am writing this feature request as a way to begin discussions on how this could be solved with JGit. If the solution was simple, I would've gone straight to making a GerritHub merge request like last time.

Here's what I'm doing in Git Version, to account for this:

var walk = (RevWalk) log.call();
if (!hasFilters || StringUtils.isEmptyOrNull(tagPrefix) || commitsToTags == null || commitsToTags.isEmpty()) return walk;

walk.setRevFilter(OrRevFilter.create(new TreeRevFilter(walk, walk.getTreeFilter()), new RevFilter() {
    @Override
    public boolean include(RevWalk walker, RevCommit cmit) throws StopWalkException {
        return commitsToTags.getOrDefault(ObjectId.toString(cmit), "").startsWith(tagPrefix);
    }

    @Override
    public RevFilter clone() {
        throw new UnsupportedOperationException();
    }
}));
walk.setTreeFilter(null);

return walk;

Here's some additional context:

  • hasFilters - if I am using path filters (set using #addPath and #excludePath
  • commitsToTags - a Map<String, String> mapped by commit object ID to tag name
  • tagPrefix - the prefix of the tag I am filtering for

To make this TreeRevFilter, I am using the walker's tree filter as the tree filter for the object. I then unset the walker's tree filter so that it only uses the rev filter that inherently contains the tree filter.

Additional context

I'm more than willing to make a merge request through GerritHub like I did when I added DescribeCommand#setExcludes.

Potential Solution no. 1

My first thought on trying to solve this was to give LogCommand a new private attribute of type Function<TreeRevFilter, RevFilter> filter. This variable would be used in #call to replace the tree filter that the walker would be using.

public void setRevFilter(Function<TreeRevFilter, RevFilter> filter) {
    this.treeRevFilter = filter;
}

public Iterable<RevCommit> call() {
    // ...
    if (this.treeRevFilter != null) {
        walk.setFilter(this.treeRevFilter.accept(new TreeRevFilter(walk, walk.getTreeFilter()));
        walk.setTreeFilter(null);
    }
    // ...
}

This is a very primitive solution but I think it does a good job of describing what I'm trying to achieve, along with the workaround I provided above.

Jonathing added a commit to MinecraftForge/GitVersion that referenced this issue Mar 12, 2025
Previously, tags that were created for a subproject needed to include a
commit that modified a file within the path. This is no longer required
and as long as the tag is created for the project's tag prefix, it will
be counted as part of the project.

For example, for project hash-utils with tag prefix 'hash', we have
three commits:
1. An empty commit tagged 'hash-0.3'
2. A commit that modifies a file in the 'hash-utils' directory
3. A commit that does not modify any files in 'hash-utils'

Commits 1 and 2 would be counted, but 3 would not. The resulting
version number will be 0.3.1.

This is currently using an implementation detail regarding how JGit's
LogCommand returns its result. See eclipse-jgit/jgit#149
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant