axion-release-plugin
axion-release-plugin copied to clipboard
Need to be able to force increment a release
With the new support for monorepos, there is an issue when a submodule depends on another module but there are no code changes within the dependent module, in that the dependent module does not have its version incremented.
For example, given a project with modules mod_a and mod_b, where both mod_a and mod_b are to be published as artifacts and also where mod_b is dependent on project(":mod_a"), then a change within mod_a will result in the version of mod_a being incremented, but the version of mod_b will not.
Within the Releaser class (https://github.com/allegro/axion-release-plugin/blob/master/src/main/java/pl/allegro/tech/build/axion/release/domain/Releaser.java#L31), there is a check to see if there are changes and if not (i.e. the version is not a snapshot) then the version will not increment. There does not appear to me to be an easy way to request that mod_b's version be incremented too (as opposed to forcing it to be a specific version via -Prelease.forceVersion=x.y.z).
Gradle has a buildNeeded and buildDependents task (c.g. docs here), where, for the example above, I could call :mod_a:buildDependents and :mod_a:build and :mod_b:build would be called.
Ideally, I think under CI/CD it would be nice to just call ./gradlew release and have the version(s) of the modules that changed be incremented (where we count a dependency between the modules as being a material change in the dependent module), even if there were no code changes to the code actually within the dependent modules.
I think this is loosely related to #314.
Whilst this sort of logic does not necessarily need to reside inside this plugin, it would be nice to document within the project how this sort of functionality could be achieved.
@adamdubiel, @kboom and @sradi, what are your thoughts here please?
Our setup currently doesn't have this issue, as our repository is split into independent builds, which don't reference each other and are only connected through a composite build configuration.
But in another build I have the requirement to build and publish only JARs of those modules, that actually changed. I think the key to achieve this is, to have all inputs of the jar task unchanged, so that it's skipped with 'UP-TO-DATE'. One important input is the version of the module, but other inputs are the dependencies and the module's output directory.
In my opinion, this feature cannot be accomplished with the axion-release plugin, as long as it is focused on changes in git. This feature needs some sort of dynamic version calculation, where the decision, if the version needs to be incremented, is based on the jar task's inputs. @john-tipper does this sound related to your goal or am I completely off track?
I recently started a discussion with gradle about my requirement. If there are any suggestions, they can provide, I am going to share them with you.
I've gone through what the Java plugin does to resolve this and I think we can at least support incrementing the version across dependent modules. Here's what I propose, covering this issue and #314 .
For this issue:
- Add a check of a boolean
forceIncrementVersionparameter within theifinReleaserand if it is set to true then return a version, same as ifversionContext.isSnapshot()is true at present. The parameter will be passed to therelease()andreleaseAndPush()methods. - I don't think we want to lose the idempotency of the release tasks (repeated calls don't repeatedly generate new releases), so we just change the way
Releaseris called from aReleaseTaskorCreateReleaseTasksuch that the parameter is passed in toReleaserby these tasks (i.e. user cannot specify this config directly, it would only happen if one of the tasks mentioned below is called, see below for details).
For #314, follow the approach taken by the Gradle core Java plugin:
-
Create 2 new tasks,
createReleaseDependentsandreleaseDependents, wherecreateXXXdepends oncreateReleaseandreleaseXXXdepend onrelease, respectively. This will be done as per the java plugin, here: https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/java/org/gradle/api/plugins/JavaPlugin.java#L396-L411 -
Add a downstream dependency on projects that refers to their
createReleaseDependents/releaseDependentstasks, as per https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/java/org/gradle/api/plugins/JavaPlugin.java#L508-L523, i.e. callingreleaseDependentson a project will call (viadependsOn) thereleasetask in that project and then alsoreleaseDependentswithin all projects that depend on that project, in dependency order, i.e. thereleasetask will be cascaded down the dependency tree. -
CreateReleaseTaskandReleaseTaskneed to be configured such that their internalforceIncrementVersionproperty is set to true (i.e. even if there are no direct code changes within a submodule, these tasks will still increment the version by callingReleaser.release()orReleaser.releaseAndPush()withforceIncrementVersion=true). We will have a helper task calledconfigureReleaseTasksthat will be configured as a dependency oncreateReleaseDependents/releaseDependentsand set to run beforeCreateReleaseTaskandReleaseTaskwhich will set theforceIncrementVersionproperty on those tasks (e.g. execution order forreleaseDependentswould beconfigureReleaseTasks,release,releaseDependents. Doing this means we don't need to change the behaviour ofreleasevia configuration: we inject this value only ifreleaseDependentsis called, but because of the task dependency ordering,releaseDependentswill occur afterrelease, hence we need to have a different task that will fire beforereleasethat will actually inject ourforceIncrementVersioninto the appropriate task (CreateReleaseTaskandReleaseTask).
This proposal would result in no breaking changes to any existing project. Only if the new tasks (createReleaseDependents/releaseDependents) are called would there be any new behaviour and this behaviour would not require any new complexity via further configuration changes.
Does anyone have any objections to this approach and are you happy for me to put together a PR for people to have a look at?
I have managed to come up with a working implementation. It differs in implementation somewhat from the description above, in that I discovered that the version incrementing is performed by VersionFactory, hence it needs to have a flag passed to it that indicates that the version should be incremented, even if there are no changes within that submodule.
The code is non-breaking and retains the idempotency of the release process, i.e. multiple calls to release do not result in multiple releases being created, even across submodules. Details are in PR #326.
@john-tipper Was this ever resolved as I have the same issue