Skip to content

Commit

Permalink
Implement support for fallback tag prefixes (#793)
Browse files Browse the repository at this point in the history
* Implement support for fallback tag prefixes

* Update docs
  • Loading branch information
radoslaw-panuszewski authored Aug 19, 2024
1 parent 91ce0b9 commit 2508725
Show file tree
Hide file tree
Showing 16 changed files with 185 additions and 72 deletions.
11 changes: 11 additions & 0 deletions docs/configuration/version.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@ calculating current version. Prefix can be set using

Default prefix is `v`.

In case a tag does not match the main prefix, fallback prefixes will be examined. You can use fallback prefixes to migrate from one prefix to another. For example, if you use prefix `my-service-` but want to migrate to prefix `v`, you can configure it like that:

scmVersion {
tag {
prefix.set("v")
fallbackPrefixes.set(listOf("my-service-"))
}
}

Axion will use fallback prefixes to calculate latest version, but the next release tag will be created using the main prefix.

There is also an option to set prefix per-branch (i.e. to use different
version prefix on `legacy-` branches):

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package pl.allegro.tech.build.axion.release.domain

import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.MapProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
Expand All @@ -15,6 +16,7 @@ abstract class TagNameSerializationConfig extends BaseExtension {
deserialize.convention(TagNameSerializer.DEFAULT.deserializer)
initialVersion.convention(defaultInitialVersion())
prefix.convention(TagPrefixConf.defaultPrefix())
fallbackPrefixes.convention(Collections.emptyList())
versionSeparator.convention(TagPrefixConf.defaultSeparator())
}

Expand All @@ -24,6 +26,9 @@ abstract class TagNameSerializationConfig extends BaseExtension {
@Input
abstract MapProperty<String, String> getBranchPrefix()

@Input
abstract ListProperty<String> getFallbackPrefixes()

@Input
abstract Property<String> getVersionSeparator()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,19 @@ import pl.allegro.tech.build.axion.release.domain.scm.ScmPosition
enum TagNameSerializer {

DEFAULT('default',
{ TagProperties rules, String version ->
return rules.prefix ? rules.prefix + rules.versionSeparator + version : version
},
{ TagProperties rules, ScmPosition position, String tagName ->
if (rules.prefix.isEmpty()) {
return tagName
{ TagProperties rules, String version ->
return rules.prefix ? rules.prefix + rules.versionSeparator + version : version
},
{ TagProperties rules, ScmPosition position, String tagName ->
if (rules.prefix.isEmpty()) {
return tagName
}
for (String prefix : rules.allPrefixes) {
if (tagName.matches("^" + prefix + rules.versionSeparator + ".*")) {
return tagName.substring(prefix.length() + rules.versionSeparator.length())
}
return tagName.substring(rules.prefix.length() + rules.versionSeparator.length())
}
}
)

private final String type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,19 @@ class DummyRepository implements ScmRepository {
}

@Override
TagsOnCommit latestTags(Pattern pattern) {
TagsOnCommit latestTags(List<Pattern> patterns) {
logger.quiet("Could not resolve current position on uninitialized repository, returning default")
return new TagsOnCommit(null, [])
}

@Override
TagsOnCommit latestTags(Pattern pattern, String sinceCommit) {
TagsOnCommit latestTags(List<Pattern> patterns, String sinceCommit) {
logger.quiet("Could not resolve current position on uninitialized repository, returning default")
return new TagsOnCommit(null, [])
}

@Override
List<TagsOnCommit> taggedCommits(Pattern pattern) {
List<TagsOnCommit> taggedCommits(List<Pattern> patterns) {
logger.quiet("Could not resolve current position on uninitialized repository, returning default")
return [new TagsOnCommit(null, [])]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,22 +64,22 @@ class NoOpRepository implements ScmRepository {
}

@Override
TagsOnCommit latestTags(Pattern pattern) {
TagsOnCommit tags = delegateRepository.latestTags(pattern)
TagsOnCommit latestTags(List<Pattern> patterns) {
TagsOnCommit tags = delegateRepository.latestTags(patterns)
log("Latest tags: ${tags.tags}")
return tags
}

@Override
TagsOnCommit latestTags(Pattern pattern, String sinceCommit) {
TagsOnCommit tags = delegateRepository.latestTags(pattern, sinceCommit)
TagsOnCommit latestTags(List<Pattern> patterns, String sinceCommit) {
TagsOnCommit tags = delegateRepository.latestTags(patterns, sinceCommit)
log("Latest tags: ${tags.tags}")
return tags
}

@Override
List<TagsOnCommit> taggedCommits(Pattern pattern) {
return delegateRepository.taggedCommits(pattern)
List<TagsOnCommit> taggedCommits(List<Pattern> patterns) {
return delegateRepository.taggedCommits(patterns)
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class TagPropertiesFactory {
static TagProperties create(TagNameSerializationConfig config, String currentBranch) {
return new TagProperties(
findPrefix(config, currentBranch),
config.fallbackPrefixes.get(),
config.versionSeparator.get(),
config.serialize.get(),
config.deserialize.get(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@
import pl.allegro.tech.build.axion.release.domain.scm.ScmRepository;
import pl.allegro.tech.build.axion.release.domain.scm.TaggedCommits;

import java.util.List;
import java.util.regex.Pattern;

import static java.util.stream.Collectors.toList;

/**
* Returned structure is:
* * previousVersion: version read from last release tag
Expand Down Expand Up @@ -65,25 +68,23 @@ private VersionInfo readVersions(
ScmPosition latestChangePosition
) {

String releaseTagPatternString = tagProperties.getPrefix();
if (!releaseTagPatternString.isEmpty()) {
releaseTagPatternString += tagProperties.getVersionSeparator();
}

Pattern releaseTagPattern = Pattern.compile("^" + releaseTagPatternString + ".*");
List<Pattern> releaseTagPatterns = tagProperties.getAllPrefixes().stream()
.map(prefix -> prefix.isEmpty() ? "" : prefix + tagProperties.getVersionSeparator())
.map(pattern -> Pattern.compile("^" + pattern + ".*"))
.collect(toList());
Pattern nextVersionTagPattern = Pattern.compile(".*" + nextVersionProperties.getSuffix() + "$");
boolean forceSnapshot = versionProperties.isForceSnapshot();
boolean useHighestVersion = versionProperties.isUseHighestVersion();

TaggedCommits latestTaggedCommit;
TaggedCommits previousTaggedCommit;
if (useHighestVersion) {
TaggedCommits allTaggedCommits = TaggedCommits.fromAllCommits(repository, releaseTagPattern, latestChangePosition);
TaggedCommits allTaggedCommits = TaggedCommits.fromAllCommits(repository, releaseTagPatterns, latestChangePosition);
latestTaggedCommit = allTaggedCommits;
previousTaggedCommit = allTaggedCommits;
} else {
latestTaggedCommit = TaggedCommits.fromLatestCommit(repository, releaseTagPattern, latestChangePosition);
previousTaggedCommit = TaggedCommits.fromLatestCommitBeforeNextVersion(repository, releaseTagPattern, nextVersionTagPattern, latestChangePosition);
latestTaggedCommit = TaggedCommits.fromLatestCommit(repository, releaseTagPatterns, latestChangePosition);
previousTaggedCommit = TaggedCommits.fromLatestCommitBeforeNextVersion(repository, releaseTagPatterns, nextVersionTagPattern, latestChangePosition);
}

VersionSorter.Result currentVersionInfo = versionFromTaggedCommits(latestTaggedCommit, false, nextVersionTagPattern, versionFactory, forceSnapshot);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

import pl.allegro.tech.build.axion.release.domain.scm.ScmPosition;

import java.util.List;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toList;

public class TagProperties {

public interface Serializer {
Expand All @@ -17,19 +22,22 @@ public interface InitialVersionSupplier {
}

private final String prefix;
private final List<String> fallbackPrefixes;
private final String versionSeparator;
private final Serializer serialize;
private final Deserializer deserialize;
private final InitialVersionSupplier initialVersion;

public TagProperties(
String prefix,
List<String> fallbackPrefixes,
String versionSeparator,
Serializer serialize,
Deserializer deserialize,
InitialVersionSupplier initialVersion
) {
this.prefix = prefix;
this.fallbackPrefixes = fallbackPrefixes;
this.versionSeparator = versionSeparator;
this.serialize = serialize;
this.deserialize = deserialize;
Expand All @@ -40,6 +48,17 @@ public final String getPrefix() {
return prefix;
}

public final List<String> getFallbackPrefixes() {
return fallbackPrefixes;
}

public final List<String> getAllPrefixes() {
return Stream.concat(
Stream.of(prefix), // main prefix takes precedence
fallbackPrefixes.stream()
).collect(toList());
}

public final String getVersionSeparator() {
return versionSeparator;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ public interface ScmRepository {

Boolean isIdenticalForPath(String path, String latestChangeRevision, String tagCommitRevision);

TagsOnCommit latestTags(Pattern pattern);
TagsOnCommit latestTags(List<Pattern> patterns);

TagsOnCommit latestTags(Pattern pattern, String sinceCommit);
TagsOnCommit latestTags(List<Pattern> patterns, String sinceCommit);

List<TagsOnCommit> taggedCommits(Pattern pattern);
List<TagsOnCommit> taggedCommits(List<Pattern> patterns);

boolean remoteAttached(String remoteName);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,20 @@ public static TaggedCommits fromListOfCommits(ScmPosition latestTagPosition, Lis
return new TaggedCommits(latestTagPosition, taggedCommits);
}

public static TaggedCommits fromLatestCommit(ScmRepository repository, Pattern tagPattern, ScmPosition latestTagPosition) {
TagsOnCommit latestTags = repository.latestTags(tagPattern);
public static TaggedCommits fromLatestCommit(ScmRepository repository, List<Pattern> relaseTagPatterns, ScmPosition latestTagPosition) {
TagsOnCommit latestTags = repository.latestTags(relaseTagPatterns);
return new TaggedCommits(latestTagPosition, Arrays.asList(latestTags));
}

public static TaggedCommits fromAllCommits(ScmRepository repository, Pattern tagPattern, ScmPosition latestTagPosition) {
List<TagsOnCommit> taggedCommits = repository.taggedCommits(tagPattern);
public static TaggedCommits fromAllCommits(ScmRepository repository, List<Pattern> releaseTagPatterns, ScmPosition latestTagPosition) {
List<TagsOnCommit> taggedCommits = repository.taggedCommits(releaseTagPatterns);
return new TaggedCommits(latestTagPosition, taggedCommits);
}

public static TaggedCommits fromLatestCommitBeforeNextVersion(ScmRepository repository, Pattern releaseTagPattern, Pattern nextVersionTagPattern, ScmPosition latestTagPosition) {
TagsOnCommit previousTags = repository.latestTags(releaseTagPattern);
public static TaggedCommits fromLatestCommitBeforeNextVersion(ScmRepository repository, List<Pattern> releaseTagPatterns, Pattern nextVersionTagPattern, ScmPosition latestTagPosition) {
TagsOnCommit previousTags = repository.latestTags(releaseTagPatterns);
while (previousTags.hasOnlyMatching(nextVersionTagPattern)) {
previousTags = repository.latestTags(releaseTagPattern, previousTags.getCommitId());
previousTags = repository.latestTags(releaseTagPatterns, previousTags.getCommitId());
}
return new TaggedCommits(latestTagPosition, Arrays.asList(previousTags));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -399,26 +399,26 @@ private String branchNameFromGit() {
}

@Override
public TagsOnCommit latestTags(Pattern pattern) {
return latestTagsInternal(pattern, null, true);
public TagsOnCommit latestTags(List<Pattern> patterns) {
return latestTagsInternal(patterns, null, true);
}

@Override
public TagsOnCommit latestTags(Pattern pattern, String sinceCommit) {
return latestTagsInternal(pattern, sinceCommit, false);
public TagsOnCommit latestTags(List<Pattern> patterns, String sinceCommit) {
return latestTagsInternal(patterns, sinceCommit, false);
}

private TagsOnCommit latestTagsInternal(Pattern pattern, String maybeSinceCommit, boolean inclusive) {
List<TagsOnCommit> taggedCommits = taggedCommitsInternal(pattern, maybeSinceCommit, inclusive, true);
private TagsOnCommit latestTagsInternal(List<Pattern> patterns, String maybeSinceCommit, boolean inclusive) {
List<TagsOnCommit> taggedCommits = taggedCommitsInternal(patterns, maybeSinceCommit, inclusive, true);
return taggedCommits.isEmpty() ? TagsOnCommit.empty() : taggedCommits.get(0);
}

@Override
public List<TagsOnCommit> taggedCommits(Pattern pattern) {
return taggedCommitsInternal(pattern, null, true, false);
public List<TagsOnCommit> taggedCommits(List<Pattern> patterns) {
return taggedCommitsInternal(patterns, null, true, false);
}

private List<TagsOnCommit> taggedCommitsInternal(Pattern pattern, String maybeSinceCommit, boolean inclusive, boolean stopOnFirstTag) {
private List<TagsOnCommit> taggedCommitsInternal(List<Pattern> patterns, String maybeSinceCommit, boolean inclusive, boolean stopOnFirstTag) {
List<TagsOnCommit> taggedCommits = new ArrayList<>();
if (!hasCommits()) {
return taggedCommits;
Expand All @@ -440,7 +440,7 @@ private List<TagsOnCommit> taggedCommitsInternal(Pattern pattern, String maybeSi
walk.next();
}

Map<String, List<String>> allTags = tagsMatching(pattern, walk);
Map<String, List<String>> allTags = tagsMatching(patterns, walk);

while (true) {
RevCommit currentCommit = walk.next();
Expand Down Expand Up @@ -484,15 +484,15 @@ private RevWalk walker(ObjectId startingCommit) throws IOException {
return walk;
}

private Map<String, List<String>> tagsMatching(Pattern pattern, RevWalk walk) throws GitAPIException {
private Map<String, List<String>> tagsMatching(List<Pattern> patterns, RevWalk walk) throws GitAPIException {
List<Ref> tags = jgitRepository.tagList().call();

return tags.stream()
.map(tag -> new TagNameAndId(
tag.getName().substring(GIT_TAG_PREFIX.length()),
parseCommitSafe(walk, tag.getObjectId())
))
.filter(t -> pattern.matcher(t.name).matches())
.filter(t -> patterns.stream().anyMatch(pattern -> pattern.matcher(t.name).matches()))
.collect(
HashMap::new,
(m, t) -> m.computeIfAbsent(t.id, (s) -> new ArrayList<>()).add(t.name),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class NextVersionMarkerTest extends RepositoryBasedTest {
nextVersionMarker.markNextVersion(rules, tagRules, config)

then:
repository.latestTags(~/.*/).tags == [fullPrefix() + '2.0.0-alpha']
repository.latestTags(List.of(~/.*/)).tags == [fullPrefix() + '2.0.0-alpha']
}

def "should create next version with default incrementer"() {
Expand All @@ -56,7 +56,7 @@ class NextVersionMarkerTest extends RepositoryBasedTest {
nextVersionMarker.markNextVersion(rules, tagRules, config)

then:
repository.latestTags(~/.*/).tags == [fullPrefix() + '0.1.1-alpha']
repository.latestTags(List.of(~/.*/)).tags == [fullPrefix() + '0.1.1-alpha']
}

def "should create next version with major incrementer"() {
Expand All @@ -70,6 +70,6 @@ class NextVersionMarkerTest extends RepositoryBasedTest {
nextVersionMarker.markNextVersion(rules, tagRules, config)

then:
repository.latestTags(~/.*/).tags == [fullPrefix() + '1.0.0-alpha']
repository.latestTags(List.of(~/.*/)).tags == [fullPrefix() + '1.0.0-alpha']
}
}
Loading

0 comments on commit 2508725

Please sign in to comment.