Skip to content

Commit

Permalink
resolving #18 - added option to create empty commit to mark release
Browse files Browse the repository at this point in the history
  • Loading branch information
adamdubiel committed Nov 24, 2014
1 parent cab90ad commit 262cb85
Show file tree
Hide file tree
Showing 12 changed files with 209 additions and 35 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
axion-release-plugin changelog
====


* **0.9.3** (16.10.2014)
* added predefined version creators
* **0.9.2** (06.10.2014)
Expand Down
25 changes: 22 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ axion-release-plugin
Releasing versions in Gradle is very different from releasing in Maven. Maven came with
[maven-release-plugin](http://maven.apache.org/maven-release/maven-release-plugin/) which
did all the dirty work. Gradle has no such tool and probably doesn't need it anyway. Evolution of software craft came
to the point, when we start thinking about SCM as ultimate source of truth about project version. No longer version
to the point, when we start thinking about SCM as ultimate source of truth about project version. Version should not be
hardcoded in **pom.xml** or **build.gradle**.

**axion-release-plugin** embraces this philosophy. Instead of reading project version from buildfile, it is derived
Expand Down Expand Up @@ -38,7 +38,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath group: 'pl.allegro.tech.build', name: 'axion-release-plugin', version: '0.9.3'
classpath group: 'pl.allegro.tech.build', name: 'axion-release-plugin', version: '0.9.5'
}
}
Expand All @@ -55,7 +55,8 @@ scmVersion {
project.version = scmVersion.version
```

**Warning** Order of definitions in `build.gradle` file does matter! First you apply plugin, then comes `scmVersion { }` closure if configuration is needed and only then you can use `scmVersion.version` to extract current version.
**Warning** Order of definitions in `build.gradle` file does matter! First you apply plugin, then comes `scmVersion { }`
closure if configuration is needed and only then you can use `scmVersion.version` to extract current version.

### Multi-project builds

Expand Down Expand Up @@ -180,6 +181,9 @@ scmVersion {
versionCreator { version, position -> /* ... */ } // creates version visible for Gradle from raw version and current position in scm
versionCreator 'versionWithBrach' // use one of predefined version creators
createReleaseCommit true // should create empty commit to annotate release in commit history, false by default
releaseCommitMessage { version, position -> /* ... */ } // custom commit message if commits are created
branchVersionCreators = [
'feature/.*': { version, position -> /* ... */ },
'bugfix/.*': { version, position -> /* ... */ }
Expand Down Expand Up @@ -246,6 +250,21 @@ $ ./gradlew cV
release-0.1.0-feature-some_feature-SNAPSHOT
```

#### Create commit on release

By default **axion-release-plugin** operates on tags only and does not mess with commit history. However, in some cases it
might be useful to create additional commit to mark release. Use `createReleaseCommit` option to change this behavior.

Default commit message is created using closure:

```groovy
{ version, position ->
"release version: $version"
}
```

It can be changed by overriding `releaseCommitMessage` property with own closure.

## Publishing released version

Publishing release version is simple with **axion-release-plugin**. Since release does not increase version unless
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ class ReleasePlugin implements Plugin<Project> {

@Override
void apply(Project project) {
VersionConfig config = project.extensions.create(VERSION_EXTENSION, VersionConfig, project)
config.versionService = ComponentFactory.versionService(project, config)
VersionConfig config = ComponentFactory.versionConfig(project, VERSION_EXTENSION)

Task verifyReleaseTask = project.tasks.create(VERIFY_RELEASE_TASK, VerifyReleaseTask)
verifyReleaseTask.group = 'Release'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.tasks.TaskAction
import pl.allegro.tech.build.axion.release.domain.LocalOnlyResolver
import pl.allegro.tech.build.axion.release.domain.Releaser
import pl.allegro.tech.build.axion.release.domain.VersionConfig
import pl.allegro.tech.build.axion.release.domain.VersionService
import pl.allegro.tech.build.axion.release.domain.VersionWithPosition
Expand All @@ -18,11 +19,15 @@ class ReleaseTask extends DefaultTask {

private final VersionConfig versionConfig

private final ScmRepository repository
private final Releaser releaser

ReleaseTask() {
this.versionConfig = project.extensions.getByType(VersionConfig)
this.repository = createRepository(project, versionConfig)
this.releaser = new Releaser(
createRepository(project, versionConfig),
new LocalOnlyResolver(versionConfig, project),
logger
)
}

private ScmRepository createRepository(Project project, VersionConfig versionConfig) {
Expand All @@ -32,27 +37,6 @@ class ReleaseTask extends DefaultTask {

@TaskAction
void release() {
LocalOnlyResolver localOnlyResolver = new LocalOnlyResolver(versionConfig, project)
VersionWithPosition positionedVersion = versionConfig.getRawVersion()
Version version = positionedVersion.version

if (version.preReleaseVersion == VersionService.SNAPSHOT) {
version = version.setPreReleaseVersion(null)
String tagName = versionConfig.tag.serialize(versionConfig.tag, version.toString())

project.logger.quiet("Creating tag: $tagName")
repository.tag(tagName)

if(!localOnlyResolver.localOnly(repository.remoteAttached(versionConfig.remote))) {
project.logger.quiet("Pushing all to remote: ${versionConfig.remote}")
repository.push(versionConfig.remote)
}
else {
project.logger.quiet("Changes made to local repository only")
}
}
else {
project.logger.quiet("Working on released version ${versionConfig.version}, nothing to do here.")
}
releaser.release(versionConfig)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package pl.allegro.tech.build.axion.release.domain

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

enum PredefinedReleaseCommitMessageCreator {

DEFAULT('default', { String version, ScmPosition position ->
return "release version: $version"
});

private final String type

final Closure commitMessageCreator

private PredefinedReleaseCommitMessageCreator(String type, Closure c) {
this.type = type
this.commitMessageCreator = c
}

static Closure commitMessageCreatorFor(String type) {
PredefinedReleaseCommitMessageCreator creator = PredefinedReleaseCommitMessageCreator.values().find { it.type == type }
if (creator == null) {
throw new IllegalArgumentException("There is no predefined commit message creator with $type type. " +
"You can choose from: ${PredefinedReleaseCommitMessageCreator.values().collect { it.type }}");
}
return creator.commitMessageCreator
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package pl.allegro.tech.build.axion.release.domain

import com.github.zafarkhaja.semver.Version
import org.gradle.api.logging.Logger
import pl.allegro.tech.build.axion.release.domain.scm.ScmRepository

class Releaser {

private final ScmRepository repository

private final LocalOnlyResolver localOnlyResolver

private final Logger logger

Releaser(ScmRepository repository, LocalOnlyResolver localOnlyResolver, Logger logger) {
this.repository = repository
this.localOnlyResolver = localOnlyResolver
this.logger = logger
}

void release(VersionConfig versionConfig) {
VersionWithPosition positionedVersion = versionConfig.getRawVersion()
Version version = positionedVersion.version

if (version.preReleaseVersion == VersionService.SNAPSHOT) {
version = version.setPreReleaseVersion(null)
String tagName = versionConfig.tag.serialize(versionConfig.tag, version.toString())

if(versionConfig.createReleaseCommit) {
logger.quiet("Creating release commit")
repository.commit(versionConfig.releaseCommitMessage(version.toString(), positionedVersion.position))
}

logger.quiet("Creating tag: $tagName")
repository.tag(tagName)

if(!localOnlyResolver.localOnly(repository.remoteAttached(versionConfig.remote))) {
logger.quiet("Pushing all to remote: ${versionConfig.remote}")
repository.push(versionConfig.remote)
}
else {
logger.quiet("Changes made to local repository only")
}
}
else {
logger.quiet("Working on released version ${versionConfig.version}, nothing to do here.")
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,16 @@ class VersionConfig {

boolean sanitizeVersion = true

boolean createReleaseCommit = false

Closure releaseCommitMessage = PredefinedReleaseCommitMessageCreator.DEFAULT.commitMessageCreator

VersionService versionService

private String resolvedVersion = null

private VersionWithPosition rawVersion = null

private static Closure defaultVersionCreator() {
return { String versionFromTag, ScmPosition position ->
return versionFromTag.toString()
}
}

@Inject
VersionConfig(Project project) {
this.project = project
Expand All @@ -57,6 +55,14 @@ class VersionConfig {
this.versionCreator = PredefinedVersionCreator.versionCreatorFor(type)
}

void releaseCommitMessage(Closure c) {
releaseCommitMessage = c
}

void createReleaseCommit(boolean createReleaseCommit) {
this.createReleaseCommit = createReleaseCommit
}

void versionCreator(Closure c) {
this.versionCreator = c
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ interface ScmRepository {

boolean checkAheadOfRemote()

List<String> lastLogMessages(int messageCount)
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ class ComponentFactory {

private static ScmRepository repository

static VersionConfig versionConfig(Project project, String extensionName) {
VersionConfig config = project.extensions.create(extensionName, VersionConfig, project)
config.versionService = ComponentFactory.versionService(project, config)

return config
}

static VersionService versionService(Project project, VersionConfig versionConfig) {
ScmRepository repository = scmRepository(project, versionConfig)
return new VersionService(new VersionResolver(repository))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ class DryRepository implements ScmRepository {
return aheadOfRemote
}

@Override
List<String> lastLogMessages(int messageCount) {
return delegateRepository.lastLogMessages(messageCount)
}

private void log(String msg) {
logger.quiet("DRY-RUN: $msg")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,4 +199,11 @@ class GitRepository implements ScmRepository {
void checkoutBranch(String branchName) {
repository.repository.jgit.checkout().setName(branchName).setCreateBranch(true).call()
}

@Override
List<String> lastLogMessages(int messageCount) {
ensureRepositoryExists()

return repository.log(maxCommits: messageCount)*.fullMessage
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package pl.allegro.tech.build.axion.release.domain

import org.ajoberstar.grgit.Grgit
import org.gradle.api.Project
import org.gradle.testfixtures.ProjectBuilder
import pl.allegro.tech.build.axion.release.domain.scm.ScmRepository
import pl.allegro.tech.build.axion.release.infrastructure.ComponentFactory
import spock.lang.Specification

class ReleaserTest extends Specification {

Project project

ScmRepository repository

Releaser releaser

VersionConfig config

def setup() {
project = ProjectBuilder.builder().build()

Grgit.init(dir: project.rootDir)

config = ComponentFactory.versionConfig(project, 'scmVersion')
repository = ComponentFactory.scmRepository(project, config)

repository.commit('initial commit')

releaser = new Releaser(repository, new LocalOnlyResolver(config, project), project.logger)
}

def "should release new version when not on tag"() {
given:
project.extensions.extraProperties.set('release.forceVersion', '2.0.0')

when:
releaser.release(config)

then:
config.getVersion() == '2.0.0'
}

def "should not release version when on tag"() {
given:
repository.tag('release-1.0.0')

when:
releaser.release(config)

then:
config.getVersion() == '1.0.0'
}

def "should create release commit if configured"() {
given:
project.extensions.extraProperties.set('release.forceVersion', '3.0.0')
config.createReleaseCommit = true

when:
releaser.release(config)

then:
config.getVersion() == '3.0.0'
repository.lastLogMessages(1) == ['release version: 3.0.0']
}
}

0 comments on commit 262cb85

Please sign in to comment.