At its core semantic-release is a set of conventions that gives you entirely automated, semver-compliant package publishing. Coincidentally these conventions make sense on their own – like meaningful commit messages.
This removes the immediate connection between human emotions and version numbers, so strictly following the SemVer spec is not a problem anymore – and that’s ultimately semantic-release’s goal.
“We fail to follow SemVer – and why it needn’t matter”
JSConf Budapest 2015
This talk gives you a complete introduction to the underlying concepts of this module
-- semantic release
How does it work?
Instead of writing meaningless commit messages, we can take our time to think about the changes in the codebase and write them down. Following formalized conventions it this then possible to generate a helpful changelog and to derive the next semantic version number from them.
When semantic-release got setup it will do that after every successful continuous integration build of your master branch (or any other branch you specify) and publish the new version for you. That way no human is directly involved in the release process and your releases are guaranteed to be unromantic and unsentimental.
Under the hood this plugin uses gradle-git's release-base plugin and configures it to automatically increment the major, minor or patch version depending on the commit messages since the last release. Releases are only performed on certain branches (/master/ and /(?:release[-/])?\d+(?:.\d+)?.x/ by default). On other branches only SNAPSHOT versions are built. On these branches the branch name is automatically appended to the version.
When doing a final release -- in addition to the default behavior of gradle-git to tag the release and push the tag -- if the origin repository is a github repository, the plugin generates a changelog and creates a release on GitHub.
Setup
Apply the plugin in the rootProject (and only there) of your gradle build.
Gradle >= 2.1
plugins {
id 'de.gliderpilot.semantic-release' version '1.0.0'
}
There is a new release task, which automatically dependsOn the build task and is finalizedBy the publish task
(and the uploadArchives task, if you use the old publishing mechanism).
Uploading SNAPSHOT and releases to different repositories
Because the release task does automatically execute the publish task, you must take care of configuring only valid
repositories.
Develop features on branches branched from master. Once a feature is merged back to master, a version is released.
Configuration
You can tweak the default behavior of the plugin using two extensions.
Semantic Release extension
semanticRelease {
changeLog {
changeScope = { org.ajoberstar.grgit.Commit->// return org.ajoberstar.gradle.git.release.semver.ChangeScope// return MAJOR, MINOR or PATH to create a release// return null, if this commit is not relevant (e.g. only doc)
[...]
}
changeLog = { List<Commit>commits, org.ajoberstar.gradle.git.release.base.ReleaseVersionversion->"""\ Release of $version.version [...]""".stripIndent()
}
}
releaseBranches {
include 'stable'
}
branchNames {
// feature branches are dev/... instead of feature/...// the version on branch dev/foo should be 1.0.0-foo-SNAPSHOT// and not 1.0.0-dev-foo-SNAPSHOT
replace ~/^dev\/(.*)$/, '$1'
}
}
Version Strategies
Since this plugin uses gradle-git under the cover, you can configure this plugin as described in their wiki.
The plugin does configure gradle-git with one versionStrategy and one defaultVersionStrategy. The defaultVersionStrategy is responsible for building SNAPSHOT versions. The semantic-release versionStrategy is only used, if there are
relevant changes (features with or without BREAKING CHANGES, bugfixes or performance improvements)
the branch is master or a release branch
the task release was used and
the workspace is clean
The gradle-semantic-release-plugin defines it's own extension semanticRelease. When configuring gradle-git, you must not use the VersionStrategies defined by gradle-git directly, but you must use the releaseStrategy or snapshotStrategy of the semanticRelease extension as a base and use copyWith. Otherwise the version will not be inferred based on the commit messages.
importorg.ajoberstar.gradle.git.release.semver.*importorg.ajoberstar.gradle.git.release.opinion.Strategies
release {
// replace the default strategy to add '-FINAL' to the version
versionStrategy semanticRelease.releaseStrategy.copyWith{
preReleaseStrategy: { it.copyWith(inferredPreRelease: 'FINAL') }
}
// add a second strategy to create release candidates from 'rc/.*' branches
versionStrategy semanticRelease.releaseStrategy.copyWith(
// the type is important, without type you would again replace the default strategytype: 'rc',
selector: { SemVerStrategyStatestate->!state.repoDirty && state.currentBranch.name ==~/rc\/.*/&&
semanticRelease.semanticStrategy.canRelease(state) && project.gradle.startParameter.taskNames.find { it =='release' }
},
preReleaseStrategy: StrategyUtil.all({ it.copyWith(inferredPreRelease: 'rc') } asPartialSemVerStrategy, Strategies.PreRelease.COUNT_INCREMENTED)
)
}
ITYMFAQLT
I think you might frequently ask questions like these
Is there a way to preview which version would currently get published?
If you run ./gradlew locally, the version that would be build gets logged (just remove -SNAPSHOT).
Can I run this on my own machine rather than on a CI server?
Of course you can, but this doesn't necessarily mean you should. Running your tests on an independent machine before releasing software is a crucial part of this workflow. Also it is a pain to set this up locally, with tokens lying around and everything.
Can I manually trigger the release of a specific version?
You can trigger a release by pushing to your GitHub repository. You deliberately cannot trigger a specific version release, because this is the whole point of semantic-release. Start your packages with 1.0.0 and semver on. You can however prevent an accidental major version bump by using a branch pattern release/\d+\.x. And you can prevent an accidental minor version bump by using a branch pattern release/\d+\.\d+\.x. Using these two branchname patterns, you can also manually trigger a version bump without a correspondent commit message.
Is it really a good idea to release on every push?
It is indeed a great idea because it forces you to follow best practices. If you don't feel comfortable making every passing feature or fix on your master branch addressable you might not treat your master right. Have a look at branch workflows. If you still think you should have control over the exact point in time of your release, e.g. because you are following a release schedule, you can release only on the release branch and push your code there in certain intervals.
Why should I trust semantic-release with my releases?
gradle-semantic-release-plugin has a full unit- and integration-test-suite. Additionally we eat our own dogfood and release using our own plugin -- A new version won't get published if there is an error.
请发表评论