tschulte / gradle-semantic-release-plugin

Gradle implementation of semantic release (https://github.com/semantic-release/semantic-release)
Apache License 2.0
88 stars 11 forks source link

-SNAPSHOT build on master branch #22

Open nbrauer opened 7 years ago

nbrauer commented 7 years ago

I am having issues finding a good way to fail a build that takes place with the snapshot version strategy on the master branch. If I am building on the master branch and I am not using the release version strategy, then I want to fail the build.

This condition will occur when committers forget to use Angular commit message conventions. When these commits get merged to master, a build is initiated, gradle-semantic-release won't see a change since the previous release. The release task will still get executed and uploadArchives will be invoked.

If I customize the snapshotReleaseStrategy to not execute on the master branch, then I will get an gradle erro the first time I reference project.version in my build.gradle. That will fail the build, but it won't be immediately obvious to the person checking the build logs what happened. Ex:

release {

    versionStrategy semanticRelease.snapshotStrategy.copyWith(
        selector: { SemVerStrategyState state ->
            state.currentBranch.name != "master" }
        }
}

If I shoe horn a check into the release task, then the finalizers for release will get invoked, which includes uploadArchives.

project.getTasksByName('release', false).first().doFirst {

    if(grgit.branch.getCurrent().name == "master" && version.toString().endsWith('-SNAPSHOT') && 
        project.gradle.startParameter.taskNames.find { it == 'release' }) {
            throw new GradleException('SNAPSHOT build on master is bad')
    }
}

The only good way that I have found to do this is to put an explicit check in the prepare task:

prepare.doFirst  {
    //We get grgit for free because we are using semantic-release
    if(grgit.branch.getCurrent().name == "master" && version.toString().endsWith('-SNAPSHOT') && project.gradle.startParameter.taskNames.find { it == 'release' }) {
        println """We are on the master branch, but the version is ending in -SNAPSHOT. The version only gets -SNAPSHOT dropped if:
* We are on the master branch
* The repo is clean
* There is a commit prefixed with 'fix:' or 'feat:' since the last release

If none of those things happened on the master branch then we will still land in the snapshot version strategy and have a version number with -SNAPSHOT. 

See here for more details:

https://github.com/tschulte/gradle-semantic-release-plugin
        """
        throw new GradleException('Releasing -SNAPSHOT version on master branch')
    }
}

I am wondering if I am just missing something about the behavior of gradle-semantic-release. If I am not, then hopefully I will save other users some time when they venture down this path as well.

Danke schön!

tschulte commented 7 years ago

Your use case is not in the scope of the plugin. For the plugin it is completely OK to do a documentation update on master that does not result in a new final version. In that case it is OK to get a new SNAPSHOT version. In my projects I do so and just switch the publishing e.g.

if (!version.toString().endsWith('-SNAPSHOT'))
    publish.dependsOn publishPlugins, bintrayUpload
else if ((System.getenv('TRAVIS_PULL_REQUEST') ?: "false") == "false")
    publish.dependsOn artifactoryPublish

I understand your requirement to fail the build when a push to master does not trigger a new version -- opposed to having a successful build without a new version. You want a message for why the build does not result in a new version.

I'm not sure if this should be part of the plugin or not, maybe as optional parameter in the plugin's extension.

But maybe you should prevent the merge (or the push of the merge) altogether. For this there should maybe be some additional tasks. Maybe one task might already do the trick: generateChangelog so you can check before pushing if your commit message is OK. If not you can amend your commit before pushing. That way you could create a pre-push hook that generates the changelog and aborts the push if it is empty when on master.

grv87 commented 7 years ago

+1 for verbose output why SNAPSHOT version is used and why no new version detected. I see that as logger with low LogLevel