Skip to content

Commit 67a17ea

Browse files
authored
Merge pull request #171 from ajoberstar/next
Next version of Reckon
2 parents c2a4738 + 98eb3bb commit 67a17ea

File tree

13 files changed

+314
-40
lines changed

13 files changed

+314
-40
lines changed

README.md

+22
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,30 @@ plugins {
125125
reckon {
126126
scopeFromProp()
127127
stageFromProp('milestone', 'rc', 'final')
128+
128129
// alternative to stageFromProp
129130
// snapshotFromProp()
131+
132+
// omit this to use the default of 'minor'
133+
defaultInferredScope = 'patch'
134+
135+
// omit to use default remote
136+
remote = 'other-remote'
137+
138+
// omit this to use the default of parsing tag names of the form 1.2.3 or v1.2.3
139+
// this is a String to Optional<Version> function
140+
// return an empty optional for tags you don't consider a relevant version
141+
tagParser = tagName -> java.util.Optional.of(tagName)
142+
.filter(name -> name.startsWith("project-a/"))
143+
.map(name -> name.replace("project-a/", ""))
144+
.flatMap(name -> org.ajoberstar.reckon.core.Version.parse(name))
145+
146+
// omit this to use the default of writing tag names of the form 1.2.3
147+
// this is a Version to String function
148+
tagWriter = version -> "project-a/" + version
149+
150+
// omit this to use the default of tag messages including just the raw version, e.g. "1.2.3"
151+
tagMessage = version.map(v -> "Version " + v)
130152
}
131153
```
132154

reckon-core/src/main/java/org/ajoberstar/reckon/core/GitInventorySupplier.java

+12-20
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import java.util.Map;
99
import java.util.Optional;
1010
import java.util.Set;
11-
import java.util.function.Function;
1211
import java.util.stream.Collectors;
1312
import java.util.stream.Stream;
1413

@@ -39,18 +38,11 @@ final class GitInventorySupplier implements VcsInventorySupplier {
3938
private static final Logger logger = LoggerFactory.getLogger(GitInventorySupplier.class);
4039

4140
private final Repository repo;
42-
private final Function<Ref, Optional<Version>> tagParser;
41+
private final VersionTagParser tagParser;
4342

44-
public GitInventorySupplier(Repository repo) {
45-
this(repo, tagName -> Optional.of(tagName.replaceAll("^v", "")));
46-
}
47-
48-
public GitInventorySupplier(Repository repo, Function<String, Optional<String>> tagSelector) {
43+
public GitInventorySupplier(Repository repo, VersionTagParser tagParser) {
4944
this.repo = repo;
50-
this.tagParser = ref -> {
51-
String tagName = Repository.shortenRefName(ref.getName());
52-
return tagSelector.apply(tagName).flatMap(Version::parse);
53-
};
45+
this.tagParser = tagParser;
5446
}
5547

5648
@Override
@@ -60,7 +52,7 @@ public VcsInventory getInventory() {
6052
// saves on some performance as we don't really need the commit bodys
6153
walk.setRetainBody(false);
6254

63-
ObjectId headObjectId = repo.getRefDatabase().getRef("HEAD").getObjectId();
55+
ObjectId headObjectId = repo.getRefDatabase().findRef("HEAD").getObjectId();
6456

6557
if (headObjectId == null) {
6658
logger.debug("No HEAD commit. Presuming repo is empty.");
@@ -88,8 +80,7 @@ public VcsInventory getInventory() {
8880
Set<RevCommit> taggedCommits = taggedVersions.stream().map(TaggedVersion::getCommit).collect(Collectors.toSet());
8981
Set<Version> parallelVersions = parallelCandidates.stream()
9082
.map(version -> findParallel(walk, headCommit, version, taggedCommits))
91-
// TODO Java 9 Optional::stream
92-
.flatMap(opt -> opt.isPresent() ? Stream.of(opt.get()) : Stream.empty())
83+
.flatMap(Optional::stream)
9384
.collect(Collectors.toSet());
9485

9586
Set<Version> claimedVersions = taggedVersions.stream().map(TaggedVersion::getVersion).collect(Collectors.toSet());
@@ -121,12 +112,15 @@ private boolean isClean() {
121112
private Set<TaggedVersion> getTaggedVersions(RevWalk walk) throws IOException {
122113
Set<TaggedVersion> versions = new HashSet<>();
123114

124-
for (Ref ref : repo.getRefDatabase().getRefs(Constants.R_TAGS).values()) {
125-
Ref tag = repo.peel(ref);
115+
for (Ref ref : repo.getRefDatabase().getRefsByPrefix(Constants.R_TAGS)) {
116+
117+
Ref tag = repo.getRefDatabase().peel(ref);
126118
// only annotated tags return a peeled object id
127119
ObjectId objectId = tag.getPeeledObjectId() == null ? tag.getObjectId() : tag.getPeeledObjectId();
128120
RevCommit commit = walk.parseCommit(objectId);
129-
tagParser.apply(tag).ifPresent(version -> {
121+
122+
String tagName = Repository.shortenRefName(ref.getName());
123+
tagParser.parse(tagName).ifPresent(version -> {
130124
versions.add(new TaggedVersion(version, commit));
131125
});
132126
}
@@ -198,9 +192,7 @@ private Optional<Version> findParallel(RevWalk walk, RevCommit head, TaggedVersi
198192
walk.reset();
199193
walk.setRevFilter(RevFilter.ALL);
200194
boolean taggedSinceMergeBase = RevWalkUtils.find(walk, head, mergeBase).stream()
201-
.filter(tagged::contains)
202-
.findAny()
203-
.isPresent();
195+
.anyMatch(tagged::contains);
204196

205197
if (mergeBase != null
206198
&& !taggedSinceMergeBase

reckon-core/src/main/java/org/ajoberstar/reckon/core/Reckoner.java

+25-4
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,16 @@ public final class Reckoner {
3232
private final VcsInventorySupplier inventorySupplier;
3333
private final Function<VcsInventory, Optional<String>> scopeCalc;
3434
private final BiFunction<VcsInventory, Version, Optional<String>> stageCalc;
35+
private final Scope defaultInferredScope;
3536
private final Set<String> stages;
3637
private final String defaultStage;
3738

38-
private Reckoner(Clock clock, VcsInventorySupplier inventorySupplier, Function<VcsInventory, Optional<String>> scopeCalc, BiFunction<VcsInventory, Version, Optional<String>> stageCalc, Set<String> stages, String defaultStage) {
39+
private Reckoner(Clock clock, VcsInventorySupplier inventorySupplier, Function<VcsInventory, Optional<String>> scopeCalc, BiFunction<VcsInventory, Version, Optional<String>> stageCalc, Scope defaultInferredScope, Set<String> stages, String defaultStage) {
3940
this.clock = clock;
4041
this.inventorySupplier = inventorySupplier;
4142
this.scopeCalc = scopeCalc;
4243
this.stageCalc = stageCalc;
44+
this.defaultInferredScope = defaultInferredScope;
4345
this.stages = stages;
4446
this.defaultStage = defaultStage;
4547
}
@@ -83,7 +85,7 @@ private Version reckonNormal(VcsInventory inventory) {
8385
logger.debug("Using provided scope value: {}", scope);
8486
} else {
8587
Optional<Scope> inferredScope = Scope.infer(inventory.getBaseNormal(), inventory.getBaseVersion());
86-
scope = inferredScope.orElse(Scope.MINOR);
88+
scope = inferredScope.orElse(defaultInferredScope);
8789
logger.debug("Inferred scope from base version: {}", scope);
8890
}
8991

@@ -154,6 +156,7 @@ public static final class Builder {
154156
private VcsInventorySupplier inventorySupplier;
155157
private Function<VcsInventory, Optional<String>> scopeCalc;
156158
private BiFunction<VcsInventory, Version, Optional<String>> stageCalc;
159+
private Scope defaultInferredScope = Scope.MINOR;
157160
private Set<String> stages;
158161
private String defaultStage;
159162

@@ -174,10 +177,22 @@ Builder vcs(VcsInventorySupplier inventorySupplier) {
174177
* @return this builder
175178
*/
176179
public Builder git(Repository repo) {
180+
return git(repo, null);
181+
}
182+
183+
/**
184+
* Use the given JGit repository to infer the state of Git.
185+
*
186+
* @param repo repository that the version should be inferred from
187+
* @param tagParser a parser used to find versions from tag names
188+
* @return this builder
189+
*/
190+
public Builder git(Repository repo, VersionTagParser tagParser) {
177191
if (repo == null) {
178192
this.inventorySupplier = () -> new VcsInventory(null, false, null, null, null, 0, Collections.emptySet(), Collections.emptySet());
179193
} else {
180-
this.inventorySupplier = new GitInventorySupplier(repo);
194+
var realParser = Optional.ofNullable(tagParser).orElse(VersionTagParser.getDefault());
195+
this.inventorySupplier = new GitInventorySupplier(repo, realParser);
181196
}
182197
return this;
183198
}
@@ -193,6 +208,11 @@ public Builder scopeCalc(Function<VcsInventory, Optional<String>> scopeCalc) {
193208
return this;
194209
}
195210

211+
public Builder defaultInferredScope(Scope defaultInferredScope) {
212+
this.defaultInferredScope = defaultInferredScope;
213+
return this;
214+
}
215+
196216
/**
197217
* Use the given stages as valid options during inference.
198218
*
@@ -248,9 +268,10 @@ public Reckoner build() {
248268
Clock clock = Optional.ofNullable(this.clock).orElseGet(Clock::systemUTC);
249269
Objects.requireNonNull(inventorySupplier, "Must provide a vcs.");
250270
Objects.requireNonNull(scopeCalc, "Must provide a scope supplier.");
271+
Objects.requireNonNull(defaultInferredScope, "Must provide a default inferred scope");
251272
Objects.requireNonNull(stages, "Must provide set of stages.");
252273
Objects.requireNonNull(stageCalc, "Must provide a stage supplier.");
253-
return new Reckoner(clock, inventorySupplier, scopeCalc, stageCalc, stages, defaultStage);
274+
return new Reckoner(clock, inventorySupplier, scopeCalc, stageCalc, defaultInferredScope, stages, defaultStage);
254275
}
255276
}
256277
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.ajoberstar.reckon.core;
2+
3+
import java.util.Optional;
4+
5+
@FunctionalInterface
6+
public interface VersionTagParser {
7+
Optional<Version> parse(String tagName);
8+
9+
static VersionTagParser getDefault() {
10+
return tagName -> Version.parse(tagName.replaceAll("^v", ""));
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package org.ajoberstar.reckon.core;
2+
3+
@FunctionalInterface
4+
public interface VersionTagWriter {
5+
String write(Version version);
6+
7+
static VersionTagWriter getDefault() {
8+
return Version::toString;
9+
}
10+
}

reckon-core/src/test/groovy/org/ajoberstar/reckon/core/GitInventorySupplierTest.groovy

+2-2
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ class GitInventorySupplierTest extends Specification {
146146
def 'if no commits, all results are empty'() {
147147
given:
148148
def emptyGrgit = Grgit.init(dir: Files.createTempDirectory('repo2').toFile())
149-
def emptySupplier = new GitInventorySupplier(emptyGrgit.repository.jgit.repository)
149+
def emptySupplier = new GitInventorySupplier(emptyGrgit.repository.jgit.repository, VersionTagParser.getDefault())
150150
expect:
151151
emptySupplier.getInventory() == new VcsInventory(null, true, null, null, null, 0, null, null)
152152
}
@@ -230,7 +230,7 @@ class GitInventorySupplierTest extends Specification {
230230
}
231231

232232
def setup() {
233-
supplier = new GitInventorySupplier(grgit.repository.jgit.repository)
233+
supplier = new GitInventorySupplier(grgit.repository.jgit.repository, VersionTagParser.getDefault())
234234
}
235235

236236
private void commit() {

reckon-core/src/test/groovy/org/ajoberstar/reckon/core/ReckonerTest.groovy

+25
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,31 @@ class ReckonerTest extends Specification {
281281
reckonStage(inventory, null, 'final') == '1.3.0'
282282
}
283283

284+
def 'if supplier returns empty, scope defaults to provided default inferred scope if base version is base normal'() {
285+
given:
286+
def inventory = new VcsInventory(
287+
'abcdef',
288+
true,
289+
null,
290+
Version.valueOf('1.2.2'),
291+
Version.valueOf('1.2.2'),
292+
1,
293+
[] as Set,
294+
[] as Set
295+
)
296+
expect:
297+
Reckoner.builder()
298+
.clock(CLOCK)
299+
.vcs { -> inventory }
300+
.defaultInferredScope(Scope.PATCH)
301+
.scopeCalc { i -> Optional.empty() }
302+
.stages('beta', 'milestone', 'rc', 'final')
303+
.stageCalc { i, v -> Optional.of('final') }
304+
.build()
305+
.reckon()
306+
.toString() == '1.2.3'
307+
}
308+
284309
def 'if supplier returns empty, scope defaults to scope used by base version'() {
285310
given:
286311
def inventory = new VcsInventory(

0 commit comments

Comments
 (0)