axion-release-plugin icon indicating copy to clipboard operation
axion-release-plugin copied to clipboard

Need to be able to force increment a release

Open john-tipper opened this issue 5 years ago • 4 comments

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?

john-tipper avatar Jan 27 '20 12:01 john-tipper

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.

sradi avatar Jan 27 '20 20:01 sradi

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:

  1. Add a check of a boolean forceIncrementVersion parameter within the if in Releaser and if it is set to true then return a version, same as if versionContext.isSnapshot() is true at present. The parameter will be passed to the release() and releaseAndPush() methods.
  2. 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 Releaser is called from a ReleaseTask or CreateReleaseTask such that the parameter is passed in to Releaser by 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:

  1. Create 2 new tasks, createReleaseDependents and releaseDependents, where createXXX depends on createRelease and releaseXXX depend on release, 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

  2. Add a downstream dependency on projects that refers to their createReleaseDependents/releaseDependents tasks, as per https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/java/org/gradle/api/plugins/JavaPlugin.java#L508-L523, i.e. calling releaseDependents on a project will call (via dependsOn) the release task in that project and then also releaseDependents within all projects that depend on that project, in dependency order, i.e. the release task will be cascaded down the dependency tree.

  3. CreateReleaseTask and ReleaseTask need to be configured such that their internal forceIncrementVersion property 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 calling Releaser.release() or Releaser.releaseAndPush() with forceIncrementVersion=true). We will have a helper task called configureReleaseTasks that will be configured as a dependency on createReleaseDependents/releaseDependents and set to run before CreateReleaseTask and ReleaseTask which will set the forceIncrementVersion property on those tasks (e.g. execution order for releaseDependents would be configureReleaseTasks, release, releaseDependents. Doing this means we don't need to change the behaviour of release via configuration: we inject this value only if releaseDependents is called, but because of the task dependency ordering, releaseDependents will occur after release, hence we need to have a different task that will fire before release that will actually inject our forceIncrementVersion into the appropriate task (CreateReleaseTask and ReleaseTask).

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?

john-tipper avatar Jan 27 '20 23:01 john-tipper

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 avatar Jan 29 '20 00:01 john-tipper

@john-tipper Was this ever resolved as I have the same issue

TabraizChel avatar May 10 '22 17:05 TabraizChel