Skip to content

Commit

Permalink
Tag selector (#141)
Browse files Browse the repository at this point in the history
Added support to configure a tagSelector closure to select among multiple tags on a commit. Defaults back to selecting the last tag found in the list of tags returned from git, same behavior as before, i.e. when there were no list and the tag for a commit was overwritten.
  • Loading branch information
levsa authored and adamdubiel committed Jun 1, 2016
1 parent 6ad80bb commit 1de6a06
Show file tree
Hide file tree
Showing 12 changed files with 101 additions and 37 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
*.ipr
*.iws

# Eclipse project files
.classpath
.project
.settings/
bin/

# gradle config
.gradle

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

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

class TagNameSerializationConfig {

Expand All @@ -20,10 +21,16 @@ class TagNameSerializationConfig {
Closure deserialize = TagNameSerializer.DEFAULT.deserializer

Closure initialVersion = defaultInitialVersion()

Closure tagSelector = defaultTagSelector()

private static Closure defaultInitialVersion() {
return { TagProperties rules, ScmPosition position ->
return '0.1.0'
}
}

private static Closure defaultTagSelector() {
return ScmRepository.LAST_TAG_SELECTOR
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ import pl.allegro.tech.build.axion.release.domain.scm.ScmPosition
import pl.allegro.tech.build.axion.release.domain.scm.ScmRepository

class VersionResolver {

private final ScmRepository repository

private final VersionFactory versionFactory

VersionResolver(ScmRepository repository, VersionFactory versionFactory) {
this.repository = repository
this.versionFactory = versionFactory
}

VersionWithPosition resolveVersion(VersionProperties versionRules, TagProperties tagRules, NextVersionProperties nextVersionRules) {
Map positions = readPositions(tagRules, nextVersionRules)

Expand All @@ -29,27 +29,27 @@ class VersionResolver {
if(positions.currentPosition.nextVersionTag) {
position = position.asNotOnTagPosition()
}

return new VersionWithPosition(currentVersion, previousVersion, position)
}


private Map readPositions(TagProperties tagRules, NextVersionProperties nextVersionRules) {
ScmPosition currentPosition = repository.currentPosition(~/^${tagRules.prefix}.*(|${nextVersionRules.suffix})$/)
ScmPosition currentPosition = repository.currentPosition(~/^${tagRules.prefix}.*(|${nextVersionRules.suffix})$/, tagRules.tagSelector)
ScmPositionContext currentPositionContext = new ScmPositionContext(currentPosition, nextVersionRules)

ScmPosition lastReleasePosition
if(currentPositionContext.nextVersionTag) {
lastReleasePosition = repository.currentPosition(~/^${tagRules.prefix}.*/, ~/.*${nextVersionRules.suffix}$/).asOnTagPosition()
lastReleasePosition = repository.currentPosition(~/^${tagRules.prefix}.*/, ~/.*${nextVersionRules.suffix}$/, tagRules.tagSelector).asOnTagPosition()
}
else {
lastReleasePosition = currentPosition.asOnTagPosition()
}

return [
currentPosition: currentPositionContext,
lastReleasePosition: new ScmPositionContext(lastReleasePosition, nextVersionRules)
]
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ class TagProperties {

final Closure<String> initialVersion

final Closure<String> tagSelector

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ package pl.allegro.tech.build.axion.release.domain.scm

import java.util.regex.Pattern

import groovy.lang.Closure;

interface ScmRepository {
public static final Closure<String> LAST_TAG_SELECTOR = { List<String> tags ->
tags && tags.size() > 0 ? tags[-1] : null
}

void fetchTags(ScmIdentity identity, String remoteName)

Expand All @@ -17,8 +22,10 @@ interface ScmRepository {
String currentBranch()

ScmPosition currentPosition(Pattern tagPattern)

ScmPosition currentPosition(Pattern tagPattern, Pattern inversePattern)

ScmPosition currentPosition(Pattern tagPattern, Closure<String> tagSelector)

ScmPosition currentPosition(Pattern tagPattern, Pattern inversePattern, Closure<String> tagSelector)

boolean remoteAttached(String remoteName);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import pl.allegro.tech.build.axion.release.domain.scm.ScmRepository
import java.util.regex.Pattern

class DryRepository implements ScmRepository {

private static final ReleaseLogger logger = ReleaseLogger.Factory.logger(DryRepository)

private final ScmRepository delegateRepository
Expand Down Expand Up @@ -50,15 +50,20 @@ class DryRepository implements ScmRepository {
}

@Override
ScmPosition currentPosition(Pattern tagPattern, Pattern inversePattern) {
return currentPosition(tagPattern)
ScmPosition currentPosition(Pattern tagPattern, Closure<String> tagSelector) {
ScmPosition position = delegateRepository.currentPosition(tagPattern, tagSelector)
log("scm position: $position")
return position
}


@Override
ScmPosition currentPosition(Pattern tagPattern, Pattern inversePattern, Closure<String> tagSelector) {
return currentPosition(tagPattern, tagSelector)
}

@Override
ScmPosition currentPosition(Pattern tagPattern) {
ScmPosition position = delegateRepository.currentPosition(tagPattern)
log("scm position: $position")
return position
return currentPosition(tagPattern, LAST_TAG_SELECTOR)
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class DummyRepository implements ScmRepository {

DummyRepository() {
}

private void log(String commandName) {
logger.quiet("Couldn't perform $commandName command on uninitialized repository")
}
Expand Down Expand Up @@ -54,9 +54,14 @@ class DummyRepository implements ScmRepository {
logger.quiet("Could not resolve current position on uninitialized repository, returning default")
return ScmPosition.defaultPosition()
}


@Override
ScmPosition currentPosition(Pattern tagPattern, Closure tagSelector) {
return currentPosition(tagPattern)
}

@Override
ScmPosition currentPosition(Pattern tagPattern, Pattern inversePattern) {
ScmPosition currentPosition(Pattern tagPattern, Pattern inversePattern, Closure tagSelector) {
return currentPosition(tagPattern)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ class TagPropertiesFactory {
versionSeparator: config.versionSeparator,
serialize: config.serialize,
deserialize: config.deserialize,
initialVersion: config.initialVersion
initialVersion: config.initialVersion,
tagSelector: config.tagSelector
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ class GitRepository implements ScmRepository {
private static final String GIT_TAG_PREFIX = 'refs/tags/'

private final TransportConfigFactory transportConfigFactory = new TransportConfigFactory()

private final File repositoryDir

private final Grgit repository

private final ScmProperties properties
Expand Down Expand Up @@ -159,38 +159,47 @@ class GitRepository implements ScmRepository {

@Override
ScmPosition currentPosition(Pattern pattern) {
return currentPosition(pattern, Pattern.compile('$a^'))
return currentPosition(pattern, Pattern.compile('$a^'), LAST_TAG_SELECTOR)
}

@Override
ScmPosition currentPosition(Pattern pattern, Pattern inversePattern) {
ScmPosition currentPosition(Pattern pattern, Closure<String> tagSelector) {
return currentPosition(pattern, Pattern.compile('$a^'), tagSelector)
}

@Override
ScmPosition currentPosition(Pattern pattern, Pattern inversePattern, Closure<String> tagSelector) {
if(!hasCommits()) {
return ScmPosition.defaultPosition()
}

Map tags = repository.tag.list()
.grep({ def tag = it.fullName.substring(GIT_TAG_PREFIX.length()); tag ==~ pattern && !(tag ==~ inversePattern) })
.inject([:], { map, entry -> map[entry.commit.id] = entry.fullName.substring(GIT_TAG_PREFIX.length()); return map; })
.inject([:].withDefault {p -> []}, { map, entry ->
map[entry.commit.id] << entry.fullName.substring(GIT_TAG_PREFIX.length())
return map
})

ObjectId headId = repository.repository.jgit.repository.resolve(Constants.HEAD)
String branch = repository.branch.current.name

RevWalk walk = new RevWalk(repository.repository.jgit.repository)
walk.sort(RevSort.TOPO)
walk.sort(RevSort.COMMIT_TIME_DESC, true)
RevCommit head = walk.parseCommit(headId)

String tagName = null
List<String> tagNameList = null

walk.markStart(head)
RevCommit commit
for (commit = walk.next(); commit != null; commit = walk.next()) {
tagName = tags[commit.id.name()]
if (tagName != null) {
tagNameList = tags[commit.id.name()]
if (tagNameList) {
break
}
}
walk.dispose()

String tagName = tagSelector(tagNameList)
boolean onTag = (commit == null) ? null : commit.id.name() == headId.name()
return new ScmPosition(branch, tagName, onTag, checkUncommittedChanges())
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package pl.allegro.tech.build.axion.release.domain.properties

import pl.allegro.tech.build.axion.release.domain.TagNameSerializer
import pl.allegro.tech.build.axion.release.domain.scm.ScmRepository;

class TagPropertiesBuilder {

Expand All @@ -17,7 +18,8 @@ class TagPropertiesBuilder {
deserialize: TagNameSerializer.DEFAULT.deserializer,
prefix: 'release',
versionSeparator: '-',
initialVersion: { r, p -> '0.1.0' }
initialVersion: { r, p -> '0.1.0' },
tagSelector: ScmRepository.LAST_TAG_SELECTOR
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class DryRepositoryTest extends Specification {
def "should return currentPosition from real scm"() {
given:
ScmPosition expectedPosition = new ScmPosition("master", "latest", true)
scm.currentPosition(_) >> expectedPosition
scm.currentPosition(_, _) >> expectedPosition

when:
ScmPosition currentPosition = dryRepository.currentPosition(~/^release.*/)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ class GitRepositoryTest extends Specification {
void setup() {
Project remoteProject = ProjectBuilder.builder().build()
remoteRawRepository = GitProjectBuilder.gitProject(remoteProject).withInitialCommit().build()[Grgit]

project = ProjectBuilder.builder().build()
Map repositories = GitProjectBuilder.gitProject(project, remoteProject).build()

rawRepository = repositories[Grgit]
repository = repositories[GitRepository]
}
Expand Down Expand Up @@ -111,10 +111,30 @@ class GitRepositoryTest extends Specification {
!position.onTag
}

def "should use the given closure to select one of multiple tags on the same commit"() {
given:
repository.tag('release-1.0.0-rc1')
repository.commit(['*'], "commit after release")
repository.tag('release-1.0.0-rc2')
repository.tag('release-1.0.0')

Closure<String> tagSelector = { tags ->
assert tags == ['release-1.0.0', 'release-1.0.0-rc2']
return 'release-1.0.0'
}

when:
ScmPosition position = repository.currentPosition(~/^release.*/, tagSelector)

then:
position.latestTag == 'release-1.0.0'
position.onTag
}

def "should return default position when no commit in repository"() {
given:
GitRepository commitlessRepository = GitProjectBuilder.gitProject(ProjectBuilder.builder().build()).build()[GitRepository]

when:
ScmPosition position = commitlessRepository.currentPosition(~/^release.*/)

Expand Down Expand Up @@ -215,7 +235,7 @@ class GitRepositoryTest extends Specification {
def "should not push commits if the pushTagsOnly flag is set to true"() {
repository.tag('release-push')
repository.commit(['*'], 'commit after release-push')

when:
repository.push(ScmIdentity.defaultIdentity(), new ScmPushOptions(remote: 'origin', pushTagsOnly: true))

Expand Down

0 comments on commit 1de6a06

Please sign in to comment.