Skip to content

Commit 249e312

Browse files
committed
Add experimental "include" and "exclude" config options
Allows adding multiple paths that may be included or excluded from a subproject's version number or changelog calculation. It does *not* affect how other projects calculate their version numbers, unlike how projects automatically exclude all subprojects from version number calculation. ```toml [gradlePlugin] path = "gradle-plugin" include = [ "settings.gradle" ] exclude = [ "gradle-plugin/build.gradle" ] ``` Open to feedback. As a reminder, Git Version has not reached 1.0.0 yet and is thus still effectively a beta.
1 parent 3ef7d1d commit 249e312

File tree

6 files changed

+168
-50
lines changed

6 files changed

+168
-50
lines changed

src/main/java/net/minecraftforge/gitver/api/GitVersion.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -280,12 +280,22 @@ sealed interface Info extends Serializable permits GitVersionInternal.Info {
280280
String getRelativePath(boolean fromRoot, File file);
281281

282282

283-
/* SUBPROJECTS */
283+
/* MANUAL PATHS */
284284

285-
/** @return The declared subprojects of this path. */
286-
@Unmodifiable Collection<File> getSubprojects();
285+
@Unmodifiable Collection<File> getIncludes();
286+
287+
@Unmodifiable Collection<File> getExcludes();
287288

288289

290+
/* SUBPROJECTS */
291+
292+
/**
293+
* Gets the subprojects declared relative to this project. Subprojects are ignored from the version number and
294+
* changelog generation.
295+
*
296+
* @return The declared subprojects of this path.
297+
*/
298+
@Unmodifiable Collection<File> getSubprojects();
289299

290300

291301
/* REPOSITORY */
@@ -307,6 +317,8 @@ interface Output extends Serializable {
307317
@Nullable String rootPath();
308318
@Nullable String projectPath();
309319

320+
List<String> includePaths();
321+
List<String> excludePaths();
310322
@Nullable String tagPrefix();
311323
List<String> filters();
312324
List<String> subprojectPaths();

src/main/java/net/minecraftforge/gitver/api/GitVersionConfig.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ static GitVersionConfig parse(@UnknownNullability File config) {
5656
sealed interface Project permits GitVersionConfigInternal.Project {
5757
String getPath();
5858

59+
String[] getIncludePaths();
60+
61+
String[] getExcludePaths();
62+
5963
String getTagPrefix();
6064

6165
String[] getFilters();

src/main/java/net/minecraftforge/gitver/internal/GitVersionConfigImpl.java

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import java.util.List;
2121
import java.util.Map;
2222
import java.util.Objects;
23+
import java.util.function.Predicate;
24+
import java.util.function.Supplier;
2325

2426
@NotNullByDefault
2527
public record GitVersionConfigImpl(
@@ -69,28 +71,44 @@ public static GitVersionConfig parse(@UnknownNullability File config) throws IOE
6971

7072
public record ProjectImpl(
7173
@Override String getPath,
74+
@Override String[] getIncludePaths,
75+
@Override String[] getExcludePaths,
7276
@Override String getTagPrefix,
7377
@Override String[] getFilters
7478
) implements GitVersionConfigInternal.Project {
75-
private static final ProjectImpl DEFAULT_ROOT = new ProjectImpl("", "", new String[0]);
79+
private static final ProjectImpl DEFAULT_ROOT = new ProjectImpl("", new String[0], new String[0], "", new String[0]);
7680
private static final List<GitVersionConfig.Project> DEFAULT_ROOT_LIST = List.of(DEFAULT_ROOT);
7781

82+
private static String getString(TomlTable table, String key) {
83+
return Objects.requireNonNullElse(table.getString(key), "");
84+
}
85+
86+
private static String getString(TomlTable table, String key, Supplier<String> orElse) {
87+
return Objects.requireNonNullElseGet(table.getString(key), orElse);
88+
}
89+
90+
private static String[] getStringArray(TomlTable table, String key) {
91+
return table.getArrayOrEmpty(key).toList().stream().map(String.class::cast).filter(Predicate.not(String::isBlank)).toArray(String[]::new);
92+
}
93+
7894
private static GitVersionConfig.Project parse(TomlParseResult toml) {
7995
var root = toml.getTableOrEmpty("root");
8096
if (root.isEmpty()) return DEFAULT_ROOT;
8197

82-
var tagPrefix = root.contains("tag") ? root.getString("tag") : "";
83-
var filters = root.getArrayOrEmpty("filters").toList().stream().map(String.class::cast).filter(s -> !s.isBlank()).toArray(String[]::new);
84-
//noinspection DataFlowIssue - TomlTable#getString checked by #contains
85-
return new ProjectImpl("", tagPrefix, filters);
98+
var includePaths = getStringArray(root, "include");
99+
var excludePaths = getStringArray(root, "exclude");
100+
var tagPrefix = getString(root, "tag");
101+
var filters = getStringArray(root, "filters");
102+
return new ProjectImpl("", includePaths, excludePaths, tagPrefix, filters);
86103
}
87104

88105
private static GitVersionConfig.Project parse(String key, TomlTable table) {
89106
var project = Objects.requireNonNullElse(table.getString("path"), key);
90-
var tagPrefix = table.contains("tag") ? table.getString("tag") : project.replace("/", "-");
91-
var filters = table.getArrayOrEmpty("filters").toList().stream().map(String.class::cast).filter(s -> !s.isBlank()).toArray(String[]::new);
92-
//noinspection DataFlowIssue - TomlTable#getString checked by #contains
93-
return new ProjectImpl(project, tagPrefix, filters);
107+
var includePaths = getStringArray(table, "include");
108+
var excludePaths = getStringArray(table, "exclude");
109+
var tagPrefix = getString(table, "tag", () -> project.replace("/", "-"));
110+
var filters = getStringArray(table, "filters");
111+
return new ProjectImpl(project, includePaths, excludePaths, tagPrefix, filters);
94112
}
95113

96114
@Override

src/main/java/net/minecraftforge/gitver/internal/GitVersionConfigInternal.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,5 @@ static GitVersionConfig parse(@UnknownNullability File config) {
1919
}
2020
}
2121

22-
non-sealed interface Project extends GitVersionConfig.Project {
23-
String getPath();
24-
25-
String getTagPrefix();
26-
27-
String[] getFilters();
28-
}
22+
non-sealed interface Project extends GitVersionConfig.Project { }
2923
}

src/main/java/net/minecraftforge/gitver/internal/GitVersionImpl.java

Lines changed: 99 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,14 @@
2121
import java.io.File;
2222
import java.io.IOException;
2323
import java.util.ArrayList;
24+
import java.util.Arrays;
2425
import java.util.Collection;
2526
import java.util.Collections;
27+
import java.util.HashSet;
2628
import java.util.List;
2729
import java.util.Objects;
2830
import java.util.Set;
31+
import java.util.function.Function;
2932
import java.util.function.Predicate;
3033

3134
public final class GitVersionImpl implements GitVersionInternal {
@@ -44,10 +47,20 @@ public final class GitVersionImpl implements GitVersionInternal {
4447

4548
// Config
4649
// NOTE: These are not calculated lazily because they are used in both info gen and changelog gen
50+
private final List<File> includes;
51+
private final List<File> excludes;
4752
private final String tagPrefix;
4853
private final List<String> filters;
4954
private final List<File> subprojects;
5055

56+
// Internal Config
57+
private final List<String> includesPaths;
58+
private final List<String> excludesPaths;
59+
private final List<String> subprojectPaths;
60+
61+
private final Set<String> allIncludingPaths;
62+
private final Set<String> allExcludingPaths;
63+
5164
public GitVersionImpl(File gitDir, File root, File project, GitVersionConfig config, boolean strict) {
5265
this.strict = strict;
5366

@@ -69,9 +82,20 @@ public GitVersionImpl(File gitDir, File root, File project, GitVersionConfig con
6982
this.localPath = GitVersionInternal.super.getProjectPath();
7083
var projectConfig = Objects.requireNonNull(config.getProject(this.localPath));
7184

85+
this.includesPaths = makePaths(this.includes = parsePaths(Arrays.asList(projectConfig.getIncludePaths())));
86+
this.excludesPaths = makePaths(this.excludes = parsePaths(Arrays.asList(projectConfig.getExcludePaths())));
7287
this.tagPrefix = this.makeTagPrefix(projectConfig.getTagPrefix());
7388
this.filters = this.makeFilters(projectConfig.getFilters());
74-
this.subprojects = this.makeSubprojects(config.getAllProjects());
89+
this.subprojectPaths = makePaths(this.subprojects = parsePaths(config.getAllProjects(), GitVersionConfig.Project::getPath));
90+
91+
var allIncludingPaths = new HashSet<>(includesPaths);
92+
if (!this.localPath.isEmpty())
93+
allIncludingPaths.add(this.localPath);
94+
this.allIncludingPaths = allIncludingPaths;
95+
96+
var allExcludingPaths = new HashSet<>(excludesPaths);
97+
allExcludingPaths.addAll(this.subprojectPaths);
98+
this.allExcludingPaths = allExcludingPaths;
7599
}
76100

77101

@@ -245,18 +269,16 @@ public String getProjectPath() {
245269
return this.localPath;
246270
}
247271

248-
249-
/* SUBPROJECTS */
250-
251-
@Override
252-
public @Unmodifiable Collection<File> getSubprojects() {
253-
return this.subprojects;
272+
private @Unmodifiable List<File> parsePaths(Collection<String> paths) {
273+
return parsePaths(paths, Function.identity());
254274
}
255275

256-
private @Unmodifiable List<File> makeSubprojects(Collection<GitVersionConfig.Project> projects) {
257-
var ret = new ArrayList<File>(projects.size());
258-
for (var project : projects) {
259-
var file = new File(this.root, project.getPath()).getAbsoluteFile();
276+
private @Unmodifiable <T> List<File> parsePaths(Collection<T> paths, Function<T, String> mapper) {
277+
var ret = new ArrayList<File>(paths.size());
278+
for (var o : paths) {
279+
var p = mapper.apply(o);
280+
281+
var file = new File(this.root, p).getAbsoluteFile();
260282
var path = GitUtils.getRelativePath(this.project, file);
261283
if (path.startsWith("../") || path.equals("..")) continue;
262284

@@ -265,34 +287,63 @@ public String getProjectPath() {
265287
return Collections.unmodifiableList(ret);
266288
}
267289

290+
private @Unmodifiable List<String> makePaths(Collection<? extends File> files) {
291+
var ret = new ArrayList<String>(files.size());
292+
for (var file : files) {
293+
var path = GitUtils.getRelativePath(this.getRoot(), file);
294+
if (path.isBlank()) continue;
295+
296+
ret.add(path);
297+
}
298+
return Collections.unmodifiableList(ret);
299+
}
300+
301+
302+
/* MANUAL PATHS */
303+
304+
@Override
305+
public @Unmodifiable Collection<File> getIncludes() {
306+
return this.includes;
307+
}
308+
309+
@Override
310+
public @Unmodifiable Collection<File> getExcludes() {
311+
return this.excludes;
312+
}
313+
314+
@Override
315+
public @Unmodifiable Collection<String> getIncludesPaths() {
316+
return this.includesPaths;
317+
}
318+
319+
@Override
320+
public @Unmodifiable Collection<String> getExcludesPaths() {
321+
return this.excludesPaths;
322+
}
323+
324+
325+
/* SUBPROJECTS */
326+
327+
@Override
328+
public @Unmodifiable Collection<File> getSubprojects() {
329+
return this.subprojects;
330+
}
331+
268332
/** The default implementation of {@link CommitCountProvider}, ignoring subprojects */
269333
private int getSubprojectCommitCount(Git git, String tag) {
270-
var excludePaths = this.getSubprojectPaths();
271-
if (this.localPath.isEmpty() && excludePaths.isEmpty()) return -1;
334+
if (this.localPath.isEmpty() && this.allExcludingPaths.isEmpty()) return -1;
272335

273-
var includePaths = !this.localPath.isEmpty() ? Collections.singleton(this.localPath) : Set.<String>of();
274336
try {
275-
int count = GitUtils.countCommits(git, tag, this.tagPrefix, includePaths, excludePaths);
337+
int count = GitUtils.countCommits(git, tag, this.tagPrefix, this.allIncludingPaths, this.allExcludingPaths);
276338
return Math.max(count, 0);
277339
} catch (GitAPIException | IOException e) {
278-
throw new GitVersionExceptionInternal("Failed to count commits with the following parameters: Tag %s, Include Paths [%s], Exclude Paths [%s]".formatted(tag, String.join(", ", includePaths), String.join(", ", excludePaths)));
340+
throw new GitVersionExceptionInternal("Failed to count commits with the following parameters: Tag %s, Include Paths [%s], Exclude Paths [%s]".formatted(tag, String.join(", ", this.allIncludingPaths), String.join(", ", this.allExcludingPaths)));
279341
}
280342
}
281343

282-
private final Lazy<List<String>> subprojectPathsFromRoot = Lazy.of(() -> this.makeSubprojectPaths(true));
283-
private final Lazy<List<String>> subprojectPathsFromProject = Lazy.of(() -> this.makeSubprojectPaths(false));
284-
285-
private List<String> makeSubprojectPaths(boolean fromRoot) {
286-
return this.getSubprojects()
287-
.stream()
288-
.map(dir -> GitUtils.getRelativePath(fromRoot ? this.getRoot() : this.getProject(), dir))
289-
.filter(Predicate.not(String::isBlank))
290-
.toList();
291-
}
292-
293344
@Override
294-
public Collection<String> getSubprojectPaths(boolean fromRoot) {
295-
return fromRoot ? this.subprojectPathsFromRoot.get() : this.subprojectPathsFromProject.get();
345+
public @Unmodifiable Collection<String> getSubprojectPaths() {
346+
return this.subprojectPaths;
296347
}
297348

298349

@@ -371,13 +422,31 @@ public File getProject() {
371422
throw new GitVersionExceptionInternal("Cannot get project directory without a project");
372423
}
373424

425+
@Override public @Unmodifiable Collection<File> getIncludes() {
426+
throw new GitVersionExceptionInternal("Cannot get include paths from an empty repository");
427+
}
428+
429+
@Override public @Unmodifiable Collection<File> getExcludes() {
430+
throw new GitVersionExceptionInternal("Cannot get exclude paths from an empty repository");
431+
}
432+
433+
@Override
434+
public @Unmodifiable Collection<String> getIncludesPaths() {
435+
throw new GitVersionExceptionInternal("Cannot get include paths from an empty repository");
436+
}
437+
438+
@Override
439+
public @Unmodifiable Collection<String> getExcludesPaths() {
440+
throw new GitVersionExceptionInternal("Cannot get exclude paths from an empty repository");
441+
}
442+
374443
@Override
375444
public @Unmodifiable Collection<File> getSubprojects() {
376445
throw new GitVersionExceptionInternal("Cannot get subprojects from an empty repository");
377446
}
378447

379448
@Override
380-
public Collection<String> getSubprojectPaths(boolean fromRoot) {
449+
public Collection<String> getSubprojectPaths() {
381450
throw new GitVersionExceptionInternal("Cannot get subprojects from an empty repository");
382451
}
383452

src/main/java/net/minecraftforge/gitver/internal/GitVersionInternal.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.jetbrains.annotations.NotNullByDefault;
1212
import org.jetbrains.annotations.Nullable;
1313
import org.jetbrains.annotations.UnknownNullability;
14+
import org.jetbrains.annotations.Unmodifiable;
1415

1516
import java.io.File;
1617
import java.util.ArrayList;
@@ -215,6 +216,18 @@ private static boolean isGitRoot(File dir) {
215216
}
216217

217218

219+
/* MANUAL PATHS */
220+
221+
@Unmodifiable Collection<String> getIncludesPaths();
222+
223+
@Unmodifiable Collection<String> getExcludesPaths();
224+
225+
226+
/* SUBPROJECTS */
227+
228+
@Unmodifiable Collection<String> getSubprojectPaths();
229+
230+
218231
/* SERIALIZATION */
219232

220233
default String toJson() {
@@ -229,6 +242,8 @@ record Output(
229242
@Nullable String rootPath,
230243
@Nullable String projectPath,
231244

245+
List<String> includePaths,
246+
List<String> excludePaths,
232247
@Nullable String tagPrefix,
233248
List<String> filters,
234249
List<String> subprojectPaths
@@ -241,6 +256,8 @@ public Output(
241256
@Nullable File root,
242257
@Nullable File project,
243258

259+
@Nullable Collection<String> includePaths,
260+
@Nullable Collection<String> excludePaths,
244261
@Nullable String tagPrefix,
245262
@Nullable Collection<String> filters,
246263
@Nullable Collection<String> subprojectPaths
@@ -253,13 +270,15 @@ public Output(
253270
root != null ? root.getAbsolutePath() : null,
254271
project != null ? project.getAbsolutePath() : null,
255272

273+
includePaths != null ? List.copyOf(includePaths) : List.of(),
274+
excludePaths != null ? List.copyOf(excludePaths) : List.of(),
256275
tagPrefix,
257276
filters != null ? List.copyOf(filters) : List.of(),
258277
subprojectPaths != null ? List.copyOf(subprojectPaths) : List.of()
259278
);
260279
}
261280

262-
public Output(GitVersion gitVersion) {
281+
public Output(GitVersionInternal gitVersion) {
263282
this(
264283
gitVersion.getInfo(),
265284
gitVersion.getUrl(),
@@ -268,6 +287,8 @@ public Output(GitVersion gitVersion) {
268287
Util.tryOrNull(gitVersion::getRoot),
269288
Util.tryOrNull(gitVersion::getProject),
270289

290+
Util.tryOrNull(gitVersion::getIncludesPaths),
291+
Util.tryOrNull(gitVersion::getExcludesPaths),
271292
Util.tryOrNull(gitVersion::getTagPrefix),
272293
Util.tryOrNull(gitVersion::getFilters),
273294
Util.tryOrNull(gitVersion::getSubprojectPaths)

0 commit comments

Comments
 (0)