001/* 002 * JDrupes GitVersioning 003 * Copyright (C) 2025 Michael N. Lipp 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Affero General Public License as 007 * published by the Free Software Foundation, either version 3 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Affero General Public License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along with this program. If not, see <https://www.gnu.org/licenses/>. 017 */ 018 019package org.jdrupes.gitversioning.api; 020 021import java.nio.file.Path; 022import java.util.Objects; 023import java.util.ServiceLoader; 024import java.util.ServiceLoader.Provider; 025import java.util.stream.Stream; 026import org.eclipse.jgit.lib.Repository; 027 028/** 029 * Configurable version evaluator for a Git repository. 030 * 031 * <p>By default, all files in the work tree are considered when evaluating 032 * the version. Restrict the scope using the {@code matching*} methods or 033 * {@link #subDirectory(java.nio.file.Path)}. Multiple matchers are combined 034 * with a logical OR. 035 * 036 * <p>Obtain an instance via {@link #forRepository(Repository)} 037 * or {@link #forRepository(Repository, ClassLoader)}. 038 */ 039public interface VersionEvaluator { 040 041 /** 042 * Creates a version evaluator for the given repository. The 043 * implementation is looked up using the {@link ServiceLoader} mechanism 044 * with the given class loader. 045 * 046 * @param repository the repository 047 * @param classLoader the class loader to use for service loading 048 * @return the version evaluator 049 * @throws java.util.NoSuchElementException if no 050 * {@link VersionEvaluatorProvider} is available 051 */ 052 static VersionEvaluator forRepository(Repository repository, 053 ClassLoader classLoader) { 054 ServiceLoader<VersionEvaluatorProvider> loader 055 = ServiceLoader.load(VersionEvaluatorProvider.class, classLoader); 056 return loader.findFirst().orElseThrow().repository(repository); 057 } 058 059 /** 060 * Creates a version evaluator for the given repository. The 061 * implementation is looked up using the {@link ServiceLoader} mechanism, 062 * trying the context class loader of the current thread and the class 063 * loader of this class. 064 * 065 * @param repository the repository 066 * @return the version evaluator 067 * @throws java.util.NoSuchElementException if no 068 * {@link VersionEvaluatorProvider} is available 069 */ 070 static VersionEvaluator forRepository(Repository repository) { 071 return Stream.of(Thread.currentThread().getContextClassLoader(), 072 VersionEvaluator.class.getClassLoader()).filter(Objects::nonNull) 073 .map(cl -> ServiceLoader.load(VersionEvaluatorProvider.class, cl) 074 .stream()) 075 .flatMap(s -> s).findFirst().map(Provider::get).orElseThrow() 076 .repository(repository); 077 } 078 079 /** 080 * Returns the evaluator's repository. 081 * 082 * @return the repository 083 */ 084 Repository repository(); 085 086 /** 087 * Sets the tag filter to use. The filter determines which tags are 088 * recognized as version tags and extracts the version string from them. 089 * 090 * @param tagFilter the tag filter 091 * @return this evaluator for chaining 092 */ 093 VersionEvaluator tagFilter(TagFilter tagFilter); 094 095 /** 096 * Sets the tag processor to use. The processor generates the final 097 * version string from the tag name and parsed version. 098 * 099 * @param tagProcessor the tag processor 100 * @return this evaluator for chaining 101 */ 102 VersionEvaluator tagProcessor(TagProcessor tagProcessor); 103 104 /** 105 * Include all files matching the given glob expression when evaluating 106 * the version. 107 * 108 * @param glob the glob expression 109 * @return this evaluator for chaining 110 */ 111 VersionEvaluator matchingGlob(String glob); 112 113 /** 114 * Include all files matching the given regular expression when evaluating 115 * the version. 116 * 117 * @param regex the regular expression 118 * @return this evaluator for chaining 119 */ 120 VersionEvaluator matchingRegex(String regex); 121 122 /** 123 * Include all files matching the given Ant pattern when evaluating 124 * the version. 125 * 126 * @param pattern the Ant pattern 127 * @return this evaluator for chaining 128 */ 129 VersionEvaluator matchingAntPattern(String pattern); 130 131 /** 132 * Include all files under the given sub-directory when evaluating 133 * the version. 134 * 135 * @param subDirectory the sub-directory, relative to the repository work 136 * tree or absolute 137 * @return this evaluator for chaining 138 */ 139 VersionEvaluator subDirectory(Path subDirectory); 140 141 /** 142 * Returns a stream of "dirty" (uncommitted or untracked) files 143 * in the work tree that match the configured file selection. 144 * 145 * @return a stream of paths 146 */ 147 Stream<Path> dirtyFiles(); 148 149 /** 150 * Returns a stream of files modified since the latest version tag 151 * that match the configured file selection. 152 * 153 * @return a stream of paths 154 */ 155 Stream<Path> modifiedFiles(); 156 157 /** 158 * Evaluates and returns the version string for the current repository 159 * state. 160 * 161 * @return the version string 162 */ 163 String version(); 164}