How do I set up a TeamCity build job to execute a maven job with no pom - maven

We have an in-house developed MOJO that generates content and doesn't require you to have an existing project or POM. Think of the maven archetype plugin, where you can just run mvn [mojo]:[goal] and have maven just execute that goal without a POM.
This MOJO connects to a specific database instance in a specific environment, and generates some metadata for the contents of the database, so our testers can inspect the metadata and locate production-like data that has certain attributes they need for a given test.
When you execute the metadata mojo, maven resolves the MOJO from the available repo's (in our case an Artifactory repo), and it then does its work and returns. It does not create any artifacts or other outputs.
We use TeamCity as our CI server, but it also has metadata generation jobs so with one click a dev can kick of a metadata generation job against a specific database.
The problem with this is the Maven runner in TeamCity requires a POM. If TC hasn't already checked out a project from a VCS, or the project it's checked out doesn't have a POM, the maven runner won't do anything. In this case, there is nothing to check out (the MOJO is resolved from Artifactory) so there is no POM.
I can set up the TC job to use the Command Line runner and have it execute, say, mvn com.example:metadata-generate -DenvironmentName=UAT1, but then it's impossible to specify the maven settings file that maven should use.
So my question is, how do I do this? Is it possible to have the maven runner execute an arbitrary maven command without needing a POM? Alternatively, using the Command line runner, is it possible to have a TC job copy a specific maven settings file to the build agent so it can be referenced in the maven command as mvn com.example:metadata-generate -DenvironmentName=UAT1 -s {path-to-settings-file}?

So its turns out that TC handles pom-less maven builds just fine. My problem was that the MOJO was not declared to not require a project.
Comparing my MOJO with the MavenArchetypePlugin source, I needed to declare my MOJO with the class level javadoc tag #requiresProject false.
Once I had that in place, TC ran my pom-less job perfectly well. All I had to do was clear the Path to POM file: field in the TC build configuration and leave it blank.

You can customize the name of the pom file that you use as an argument into the maven build-step in the teamcity and use this as the second "build step".Lets call the parameter as pom.file.name
In the first step , resolve all the in-house dependencies that you have and set the name of the pom file you want to execute into the variable pom.file.name
If you want to know more about how to change tha value of a variable in teamcity, you can read about it here

Related

How to run a maven plugin without a POM in Jenkins?

I have a plugin which can run either using a pom.xml or without (depends upon the version of the artifact we're building: new versions go without a pom. Strange, I know).
I want to have that plugin run in Jenkins.
But when creating a maven project, I have to set a pom (or as a default, Jenkins suppose there is one in the base folder given).
Question: Is it possible to configure Jenkins to not use a pom when there is none?
As per my comment, you should use a Jenkins freestyle project build in this case, in order to have more flexibility and avoid the default assumptions of a Jenkins Maven build.
In such a build, you can then configure a build step executing a shell or a Windows command (depending on the Jenkins server OS).
Indeed, in the Jenkins Maven build, a pom file is always required, as mentioned in the help support of the Configuration > Build > Root Pom entry
If your workspace has the top-level pom.xml in somewhere other than the 1st module's root directory, specify the path (relative to the module root) here, such as parent/pom.xml.
If left empty, defaults to pom.xml

how to clean jacoco.exec after running integration tests in a multi-module project

I have a multimodule Maven project, it is analyzed using the Sonar Maven runner and coverage is done with Jacoco. For our integration tests we want to see the coverage across all modules (because they are integration tests after all).
Therefore we configure the jacoco-it.exec file to be in ${user.dir}, with the appendproperty to true. This way all modules append their information to the same location and coverage is calculated over all modules.
But since append is true the file will still be there on a next run, since it isn't placed in a directory that maven cleans. This leads to incorrect coverage reports.
What is the best way to clean up this file after a sonar run? Ideally I would like to configure this in the same pom profile as our jacoco/sonar configuration, so that no other projects need to remember to set a clean step in Jenkins or whereever. The sonar/jacoco configuration is in a company wide parent pom file.
Since you are using Maven, you could try and use the maven-antrun-plugin to delete the file.
I don't know how you run Sonar Maven, but you can either bind the maven-antrun-plugin task to a phase after the one the Sonar Maven Runner is bound to (and you would have the file deleted automatically and the end of each run) or you can call the maven-antrun-plugin from the command line.

What is the purpose of the # symbol in <groupId>#project.groupId#</groupId>?

I'm trying to run 'mvn clean install' in a sub-module of a multi-module project. The project is Jacoco but I assume it's more an issue of me not understanding how Maven is being used here than an issue with Jacoco itself.
https://github.com/jacoco/jacoco/blob/master/jacoco-maven-plugin.test/it/it-site/pom.xml
I get the following error:
[ERROR] Plugin #project.groupId#:jacoco-maven-plugin:#project.version#
or one of its dependencies could not be resolved: Failed to read
artifact descriptor for
#project.groupId#:jacoco-maven-plugin:jar:#project.version#
I see the following in the pom:
<groupId>#project.groupId#</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
I'm not familiar with using the # symbol in #project.groupId# although i assume it is somehow supposed to get substituted at runtime.
I can run Maven from the top level pom and I even see [INFO] Building: it-site/pom.xml in the log but a target directory is not created there.
A nudge in the right direction would be appreciated.
This probably has something to do with the pom file here: https://github.com/jacoco/jacoco/blob/master/jacoco-maven-plugin.test/pom.xml
It is using a plugin called the maven invoker.
The Invoker Plugin is used to run a set of Maven projects. The plugin can determine whether each project execution is successful, and optionally can verify the output generated from a given project execution.
And if you read about filtering files with this plugin, it mentions:
POM files selected by the include/exclude patterns. The tokens to be filtered must be enclosed in #...# to avoid interferences with Maven's normal POM interpolation, i.e. use #project.version# instead of ${project.version}.
Regarding why the Invoker Plugin and filtering is being used here...
The Spring Boot documentation provides some relevant background on why that is. Although the docs are for Spring Boot, i think it applies to testing all plugins (which Jacoco is).
Multi-module Maven builds cannot directly include maven plugins that
are part of the reactor unless they have previously been built. ...
The standard build works around this restriction by launching the
samples via the maven-invoker-plugin so that they are not part of the
reactor.
The sample application are used as integration tests during the build
(when you mvn install). Due to the fact that they make use of the
spring-boot-maven-plugin they cannot be called directly, and so
instead are launched via the maven-invoker-plugin.

Access Maven build properties in Jenkins post-build script to retrieve deployed artifact

I've got a Maven project that Jenkins builds and deploys to a remote repository. I then need to copy the deployed .war to an external location. I've been trying to do this with a post-build shell script but I don't see any way to get the build information from maven (for example, the URL of the deployed artifact). Is there a way to get it, or a way to do this that's more integrated into maven? I can calculate the deployment path using Jenkins build parameters but it seems like a hack.
Thanks,
Steve
After a maven build you should always find the build artifact at
target/<artifactId>-<version>.<packaging>
You can access this path within the maven pom.xml by using the maven properties (see pom reference)
${project.build.directory}/${project.artifactId}-${project.version}.${project.packaging}
To copy the artifact to another location after the build you can use several approaches described e.g. in this thread.

How to add files to a maven project executing generate goal (mvn archetype:generate)?

I'm building a maven archetype project. As parameter (serviceDescriptor), I'm passing path to an xml file. When the generate goal is successfully executed, I would like to have the serviceDescriptor file in src/main/resources. Based on maven archetype documentation, it seems that is not possible but, there should be a way to do it.
I have spent couple of days on this and I think that I have found a reasonable solution.
As I mention in the question, I'm passing the file path as required property to the archetype:generate.
I had to implement a simple plug-in that is executed after archetype generate is finishing. This plug-in is coping the file into src/main/resources, read some data from the file and update the pom.xml setting some properties. In order to be able to modify the pom.xml file I'm using maven-model-2.0 archetype as dependency in maven plug-in. It offers Maven MvenXpp3Reader and MavenXpp3Writer classes that allows to safe modify pom.xml.
In order to tell to archetype project to execute plug-in at the end of generate phase of archetype:
mvn archetype:generate -goals=plugin_groupId:plugin_artifactId:goal
The downside is that the plug-in should be available in a accessible repository or local repo.

Resources