I would like to implement a release system similar to the one used at a large PNW company at which I worked recently. I would like to know if I can model it with Maven (to which I am relatively new).
I have applications A1, A2, ..., An. They depend on library L. I would like to designate the next release of L to be version 2.0. I would like A1 - An to declare dependency on L v2.0.
I would then like to release successive L artifacts, preferably named something like L-[timestamp]-[git-hash] (so that, given an artifact, I can identify the source that created it) as L v2.0. Any subsequent rebuilds of any of A1 - An would build against that newly-released version.
Can I do this with Maven?
Yes, you should be able to accomplish this with Maven.
Have a look at the Versions Maven plugin. It has a goal versions:use-latest-releases that will replace the release version of an artifact in your POM with the latest released version that it finds in the repository.
For example, you could use the Versions plugin to update the L dependency in A's POM before cutting the next release of A using release:perform.
versions:use-latest-releases: http://www.mojohaus.org/versions-maven-plugin/use-latest-releases-mojo.html
release:perform: https://maven.apache.org/maven-release/maven-release-plugin/perform-mojo.html
Related
Assumed we have two projects A and B. A provides artifacts that are consumed by B, i.e. A is some kind of base component where B builds upon.
All projects are git repositories, i.e. each has a main branch. For feature development there may be feature branches.
A feature development may affect
either B only
or A and B
A and B are built with gradle, i.e. there are gradle scripts. The script of B specifies A as a dependency.
The dependency of the B script of the main branch looks like
...
dependencies {
implementation("my.company:a-component:1.0.+")
...
Assume a feature development FEAT1 that affects both projects.
We create feature branches and name them like the features.
gradle builds artifacts of both projects, and we choose to give artifacts the feature name as version.
Then the dependency specification in the gradle script of B on branch FEAT1 looks like
...
dependencies {
implementation("my.company:a-component:FEAT1")
Admittedly this is an unusual version. But who cares, feature development is short-living, such versions (i.e. feature branches) come and go within few days. What finally counts is the main branch and the versions specified there.
Assume FEAT2 affects B only. So the dependency specification is again
...
dependencies {
implementation("my.company:a-component:1.0.+")
since there is no FEAT2 branch (i.e. no FEAT2 version) of A.
Now for the question: can I fetch the dependency from a feature branch if there is one, and otherwise default to main?
In pseudocode something like
...
dependencies {
implementation("my.company.a-component:${if (version FEAT2 of a-component exists) then FEAT2 else 1.0.+}")
Can I achieve that with gradle means?
If so any new feature branch of B would choose the version of its A dependency automatically correctly. That's what I would like to achieve.
I don't have more than basic gradle knowledge, read https://docs.gradle.org/current/userguide/single_versions.html and following, but didn't find an obvious solution.
We are currently using gradle 7.5.1.
The projects are Java/Kotlin projects, the artifacts are jar files.
I am trying to build my Java project into two different version, each one based on different versions on the same dependencies. Specifically, my project A requires a dependency B, which has two different versions (e.g. v1 and v2). I am looking to build project A with each dependency version of B and get as artifact two different jars: A-v1.jar and A-v2.jar. The source code is the same so I wouldn't want to duplicate it into two different Maven projects, as I am looking to scale it when new versions of B will be released.
What I have tried so far: I defined two build profiles v1 and v2 where I have specified the dependency B version. This works fine as I can build the two profiles, but the issue is that I have no idea how to tell Maven to add a version number to the build artifact. It always builds project A into A-1.0.jar, where 1.0 is the project A version in the pom.
One update of my investigation: I have added a finalName element in the build section of my parent pom to override the default artifacts naming. Now the naming will be like ${artifactId}-${project.version.mycustomver}, where project.version.mycustomver property is defined in each build profiles. This seems to generate the correct naming of jars, however maven-install-plugin is changing the artifacts names back to ${artifactId}-${version}. No idea why and how to avoid it.
I appreciate any suggestion. Thanks,
DanP
You can either use classifier which is somehow made for that.
But you should also be able to change the version using a property that is overridden in the profiles.
Since you need two distinct POMs, one per "version" of your project, you in fact need two projects. However, you can have one normal version A. And a second one which is empty but uses dependency management to exclude and replace the dependencies that changes from A-v1 to A-v2.
In my project I have module M1 it use library A. This library have dependency to library B.
And in another module M2 I want to use library B.
And of course I have "root" module which depend on all my modules so versions of library B should be the same across all projects.
So I added B to dependency of my M2 module but don't know how to specify it version because I need exactly same version as library A use.
If I specify current version of library B then when I will upgrade library A to new version I will forget to update version of B in my module.
Also I don't want to put A as dependency of M2 because I need only limited part of it's functionality.
What is best practices for my case?
The maven enforce plugin can break the build if the versions diverge so that yo do not forget to update: see https://maven.apache.org/enforcer/enforcer-rules/dependencyConvergence.html
There are several options some of them you exclude explicitely. Let me mention them for the sake of completeness anyway:
Include B as a dependency in M2.
Advantage: Cleanest solution with respect to adding only those functionality to M2 that's actually needed.
Disadvantage: Version of B in M2 has to be kept in sync with versin of B in A manually.
Include A as a dependency in M2.
Advantage: Central <DependencyManagement> can be used in your parent POM. Hence, Versions of B will always be the same in all sub-projects.
Disadvantage: Functionality of A not needed in M2 is added to M2.
Include M1 as a dependency in M2.
Advantage: M2 always uses the same version of B as A without having to deal with B as a dependency at all.
Disadvantage: Functionality of M1 and of A not needed in M2 is added to M2.
Use <dependency>/.../<exclusion> to exclude B from A in M1.
Advantage: Central <DependencyManagement> can be used in your parent POM. Hence, Versions of B will always be the same in all sub-projects.
Disadvantage: Version of B has to be kept in sync with version of B in A manually.
[Input is welcome in case there's anything else I haven't thought of.]
Try Maven Enforcer Plugin's Dependency Convergence mentioned by Assen Kolov in his answer. If it works for a mixture of direct and transitive dependencies, like in your case, as well, I'd use it in conjunction with 1.
I am working on project to automate maven releases for large set of inter-dependent modules. First the task involves getting the latest versions for internal dependencies. Than order the builds in a way every project is built before it’s needed. Hopefully that combination will get me to my goal of one click bulk release.
However my biggest problem is:
We branch projects from time to time and we do releases/snapshots to Nexus repo manager from that branch. Obviously because the groupId and ArtifactId are the same as the trunk- Snapshots/Releases from trunk and one from branches end up in the same place in nexus.
In a scenario where we have projectA with a trunk version 1.1.x
And projectB → projectA version 1.1.x
So if I use the version-plugin to get the latest dependencies for B, I will get the latest. (perfect)
However if I later branch ProjectA with a version 1.2.0 and add changes that I don’t want projectB to pick up or could potentially break it.
Now next time I run projectB and I use the version plugin to get the latest , The plugin will get the branch version (1.2.0) for ProjectA, as it’s numerically the latest. And there you go, projectB build fails.
I have so far tried adding a classifier to the artifact to distinguish between the two but I later realised the plugin does not act upon the classifier.
This give me so much frustration and will appreciate any hints or advice
Simple use proper/diffrent artifact names for branches. You can automatically create proper artifact names Maven Release plugin
mvn --batch-mode release:branch -DbranchName=my-branch-1.2 -Dproject.rel.org.myCompany:projectA=1.2 -Dproject.dev.org.myCompany:projectA=2.0-SNAPSHOT
The typical approach to solve this problem is to use branch names as version classifiers and that approach works for all scenarios I have seen so far. What problem did you have with this?
I have two multi module projects. One is the main project tree. The other project tree pulls in the artifacts (WARs, JARs, etc) from the first project. They each have their own separate parent pom.
I would like to keep their version numbers identical. Project 2 has a dependency management section that has the artifacts from project 1 in it. The problem with this is that I can't release the project due to snapshots.
For example. The version number (for both projects) is 3.4-SNAPSHOT. I can release a version 3.4 of project 1 and all the pom versions will be set from 3.4-SNAPSHOT to 3.5. When I go into project 2, I want to do the same exact thing. The hitch is that dependencies of project 1 are at 3.4-SNAPSHOT and I can't figure out how to automatically get them to be 3.5. It's like I want the dependencies to be updated to the release version, before actually releasing.
I understand that if I make both trees extend from the same parent pom, the maven release plugin would detect the dependencies as submodules and update them automatically.
I read a little bit about the versions plugin but I didn't like the use-latest-versions part of it (it seems way to dangerous). The Update-properties seemed promising but it upon a second cursory look, it looked like the use-latest-versions plugin packaged slightly different.
Also, I tried just using ${project.version} but that's basically the same as putting 3.4-SNAPSHOT in as the dependency - it'll error saying it can't release due to snapshots since the version actually hasn't been updated yet.
The way you have the projects configured they are totally independent. You might as well be asking for the version of your log4j dependency to be the same as your current project B version.
While it won't be automatic, you should replace the versions of all references to Project A within Project B to use a property that is defined in the parent pom for Project B. Then, when you release Project A, you only have to change one pom so the project.a.version property is now the released version instead of SNAPSHOT. After the release of B you could then change it back to ${project.version} to keep them in sync.
As you admit, the right answer here is to re-arrange your project to have a common parent. Anything else is just a workaround.
However, it looks to me like versions:use-releases might achieve your goal. You can specify an includes list to ensure only project 1 dependencies are updated.
If you wanted this to be automatic, you could consider binding this goal to one of the lifecycle phases prior to compile.
Edit: sadly this looks like its not possible. At least, that's how I understand by the "Executes by direct invocation only" mentioned at the top of the page.