Wiping out Maven local repository on build machine - maven-2

On a CI build server, the local Maven repository fills up the file system repetitively (after a few days).
What strategy are others doing to trim the local repository in such a case?
-Max

The Maven dependency plugin has a purge-local-repository goal that allows you to delete the dependencies for a given project from the local repository, if this is run say once a day on each project the snapshots will not accumulate.
Alternatively there's a more scorched-earth approach you could take. As the problem is typically the timestamped snapshot artifacts, you could use the maven-antrun-plugin to delete all files that match the resource collection pattern.
For example (note this might need some tweaking as I've done it from memory):
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<configuration>
<tasks>
<delete>
<fileset dir="${settings.localRepository}">
<include name="**/*.jar"/>
<exclude name="**/*.pom"/>
<exclude name="**/*.war"/>
<exclude name="**/*.ear"/>
<exclude name="**/*.md5"/>
<exclude name="**/*.sha"/>
<!--any other extensions?...-->
<!--match the timestamp pattern-->
<containsregexp expression="[0-9]{8}.[0-9]{6}-[0-9]+"/>
</fileset>
</delete>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>

If you're using hudson, you can set up a scheduled job to just delete the entire repository once a day or something like that. I've got a job called hudson-maven-repo-clean which has this configuration:
Build / Execute shell: rm -rf ~hudson/.m2/repository
Build Triggers / Build periodically: 0 0 * * *

In addition to purge-local-repository (which reads to me like a nuclear option, as it only offers an excludes configuration as opposed to an explicit includes), take a look at the Remove Project Artifact mojo. I'm looking to implement it now, as my exact use case is to clear out large WAR and EAR snapshots that are being built on my CI (and sometimes workstation) machines.

We use especially for this purpose the build-helper plugin. In our company parent pom is the remove-project-artifact goal embedded in the profile for our hudson builds. This way all old versions of this artifact are removed prior to installing the currently build version.
...
<profile>
<id>hudson</id>
<activation>
<property>
<name>BUILD_TAG</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>remove-old-artifacts</id>
<phase>package</phase>
<goals>
<goal>remove-project-artifact</goal>
</goals>
<configuration>
<removeAll>true</removeAll>
</configuration>
</execution>
</executions>
</plugin>
...
Using removeAll set to true will wipe out all other snapshots except the one your working on. This can be dangerous as it may mean snapshots for a branch will be wiped out as well.
For instance if you have a snapshot 1.0.0.18-SNAPSHOT representing HEAD and snapshot 1.0.1.17-SNAPSHOT representing a branch, running this plugin with 1.0.0.18-SNAPSHOT build will wipe the 1.0.1.17-SNAPSHOt folder.
To get around this scenario the removeAll should be set to false.

We have employed a slightly different (and devious) technique. All artifacts that build "large things" (EARs, WARs, TARs) have their deploy location overriden like so:
<properties>
<discard-me-in-bit-bucket>file://${basedir}/target/_DELETEME</discard-me-in-bit-bucket>
</properties>
<distributionManagement>
<repository>
<id>upload-InternalSite</id>
<name>SoftwareLibrary External</name>
<url>${discard-me-in-bit-bucket}</url>
<layout>legacy</layout>
<uniqueVersion>false</uniqueVersion>
</repository>
<snapshotRepository>
<id>upload-InternalSite</id>
<name>Repository Name</name>
<url>${discard-me-in-bit-bucket}</url>
<layout>legacy</layout>
<uniqueVersion>false</uniqueVersion>
</snapshotRepository>
</distributionManagement>
This strategy causes the deploy goal to put things in the target directory, which of course is destroyed by the next CLEAN operation. To get even more aggressive, we have a postbuild step that does this:
find -type d -name '*_DELETEME' -exec rm -rf '{}' ';' -prune || echo $?
We employ yet one more strategy, too. In Hudson/Jenkins we provide a settings file to place the .m2 repository in the workspace for the job. This allows us to delete the entire repository before or after the job. It also makes artifacts visible in the workspace which aids in debugging some problems.

How big is the file system? We have 10gb allocated to builds and zap snapshots older than 30 days every night. That seems to work
Are you doing builds every X hours or when code changes? Switching to code changes will reduce the number of artifacts without reducing coverage.
Are you installing all snapshots locally? You don't need to do this in all cases. In most cases, just those snapshots that are actively developed dependancies need to be installed locally.
Are you installing EAR/WAR files locally? You probably don't need them either.
How many workspaces are you keeping? We use hudson and keep only the last 5 builds.

Related

Release a SQL artifact in Maven

How do I tell Maven to also publish the SQL artifact for the DBA?
Here's the thing: when we release every new version of our Maven application, we need to publish two artifacts:
The web application (e.g. app-1.2.0.war file) -- for the WebSphere guy.
The database changes for this version (e.g. dba-1.2.0.sql file) -- for the DBA.
The SQL changes file is currently src/main/database/dba.sql, but I can change that dir or file name if necessary.
As of now Maven publishes the war artifact automatically (mvn clean deploy) to the artifact repository, and that's perfect. However, I wanted it to publish the SQL file at the same time, in the same command as well... and it doesn't.
How can I do that?
I see that we can tell Maven to publish extra artifacts (e.g. sources, javadoc) at once, so I guess it should be possible to publish SQL files as well, but this is just a guess.
You can use the Build Helper plugin for that.
But the file name is computed from artifactid, version, type and classifier.
If you need to absolutely push a different name with a different artifactId, you will need either to mvn deploy:deploy-file ... (from a command in your CI or with an ant script in the pom) or create an additional pom file and launch maven against it.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>attach-artifacts</id>
<phase>package</phase>
<goals>
<goal>attach-artifact</goal>
</goals>
<configuration>
<artifacts>
<artifact>
<file>src/main/database/dba.sql</file>
<type>sql</type>
<!-- <classifier>xxx</classifier> -->
</artifact>
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
link to the source: https://www.mojohaus.org/build-helper-maven-plugin/usage.html

How to include a maven launch config in a maven archetype?

I got a liferay-portlet-project with a sample application/portlet that I want to become an archetype. Inside the project there is a folder containing two *.launch files to redeploy the webapp. Both have the following line which I have trouble with:
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc:/rawportlet}"/>
where "rawportlet" is the project's name. If I change it manually to ${artifactId} this variable is not resolved when using the archetype to create a project. Resolving this variable during project-generation would be nice.
Is there a way to achieve this? Or a workaround? Thanks in advance for your help.
Workaround: write a maven goal that the user can run after using the archetype. So the steps would be (for example):
generate project from archetype
mvn archetype:generate -DarchetypeCatalog=local
do some post-generation cleanup (execute in project's base dir)
mvn antrun:run
So my code for this is in "pom.xml" in the archetype:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>default-cli</id>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<replace token= "rawportlet" value="${artifactId}" dir="runConfigs">
<include name="**/*.launch"/>
</replace>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
The "runConfigs" directory is where the *.launch files are stored.
Credits to:
Full search and replace of strings in source files when copying resources
Maven, configure specific goal
I have this same problem, and I used a different solution that works okay (but isn't perfect either).
Use value="${workspace_loc}/${artifactId}" in your launch config.
This will work as long as people do an archetype:gen at the workspace root. This works better for me than the selected answer because running that post processing requires another launch configuration (which somewhat defeats the whole purpose).

Which maven2 lifecycle-phase to choose?

I have a Java EE-web-application and for using my project with oc4j application server it must be patched in my build-lifecycle to avoid several issues. Actually i do this via maven-antrun-plugin which works great. I have to remove, copy some special libraries into WEB-INF/lib and edit the web.xml, to avoid clashes with EL functions and classloading issues.
According to the maven lifecycle phases i chosed the phase prepare-package: this phase is executed before the war file is packaged, but unfortunately also before the (re-)sources are copied into the temporary working dir. I dislike working on the source folders because they're under version control and i don't want to have my coworkers to accidently commit them in cause the build-tool modified them.
So maven copies all the (re-)source stuff to target/__finalName__ where i want to fix the project for the use with oc4j. because this folder is temporary and will be packaged into the war file. Unfortunately the copying and packaging is isolated done in lifecycle package.
So how can i get between the copying of the sources and resources and the real packaging?
Example with prepare-package
This example doesn't work because the ${project.build.directory}/${build.finalName} doesn't exists and the ojdbc14.jar wasn't copied there in this phase.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<id>patch-oc4j</id>
<phase>prepare-package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<echo>Patching distribution for OC4J</echo>
<echo>Deleting the obsolete OJDBC library</echo>
<delete file="${project.build.directory}/${build.finalName}
/WEB-INF/lib/ojdbc14.jar" />
[... more patching ...]
</tasks>
</configuration>
</execution>
</executions>
</plugin>
Couldn't you use a profile for this? Maybe something like this:
<profiles>
<profile>
<id>oc4j</id>
<dependencies>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc14</artifactId>
<version>10.2.0.4.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</profile>
</profiles>
I have to remove, copy some special libraries into WEB-INF/lib and edit the web.xml, to avoid clashes with EL functions and classloading issues.
Sounds like you could, in part at least, do this with Build Profiles instead.. Your motivation for the problem above is a bit short, but if you elaborate we can judge this better..

Simple Mavenization of existing Ant build files

If you have an existing ant file, what is the best way to convert the project to Maven. I've checked out things like fAnt, but if I'm going to mess with this stuff, I might as well go full-bore for Maven. I expected something to exist that can just start the pom.xml for me based on the existing build.xml, but I haven't found anything yet. Suggestions?
I don't know any good automated way to do such a migration because things may just be too different so I would do it manually, step by step, and keep the existing ant build in parallel of the future new one until the whole migration is done (from both technical and human points of view).
First, refactor the existing Ant build to align it on Maven conventions:
Make things modular: if your existing build is a big monolithic build producing several artifacts from a single source tree, break it down into separate modules, one for each artifact.
Update directory structure: Maven comes with a standard directory layout and, while it is possible to customize this layout (i.e. to configure plugins for another layout), this is not really recommended and is more a source of troubles than benefits. So I'd move existing app sources, configuration files, tests, etc to match Maven's layout (e.g. src/main/java for application sources, etc).
Then, start to create the Maven build:
Create POMs for each module: Create a POM, declare external libraries as Maven dependencies (maybe add them to a corporate repository, using an enterprise repository is a good practice in an enterprise context anyway), add dependencies between modules.
Finalize the multi-modules build: Add parent(s) POM(s) and inheritance/aggregating relationships. Test that there is no regression with the created artifacts.
You could do this work in a separate VCS branch if you don't want to change anything until the work is done and create scripts to move things. And when ready, merge the Maven specific stuff and apply the scripts.
You could run the Ant script from Maven with the maven-antrun-plugin. Your pom.xml would look something like this:
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<dependencies>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant-nodeps</artifactId>
<version>${ant-nodeps.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>init</id>
<phase>compile</phase>
<configuration>
<tasks>
<!-- Ant code goes here -->
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</build>
</project>
That way you can start to move your dependencies into Maven, and reference them in the Ant script like so
${com.foo.bar:my-lib:jar}
Then just start slowly moving pieces of your Ant into pure Maven stuff.

How to remove generated build artifacts from Maven's target directory?

How to remove generated build artifacts from Maven's target directory? Maven generates a jar or war file to target directory. I'd like to remove that file after maven has installed the jar/war file to local repository (that is, after maven has executed the 'install' goal). The remove could happen either at install goal or separate goal I execute manually.
Note, that I'd like leave other parts of target directory intact, for example target/site and target/surefire-reports.
Just use the clean plugin and run an execution after the install phase:
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>auto-clean</id>
<phase>install</phase>
<goals>
<goal>clean</goal>
</goals>
<configuration>
<filesets>
<fileset>
<directory>${project.build.outputDirectory}</directory>
<includes>
<include>**/*.jar</include>
</includes>
</fileset>
</filesets>
</configuration>
</execution>
</executions>
</plugin>
There is nothing built into Maven that can do this. You could use the antrun plugin to execute an Ant script after install that deletes the artifact, or use the exec plugin to use the command line to delete the artifact, or write your own plug-in.
I suggest there is little value, if any, in doing any of these things. Maven is designed to place intermediate and final artifacts in target to make follow-on builds more efficient. The reason that there is nothing available to do this already is an indicator that this is of little value. If it is of value to you, you have a few options.
I know I am a little bit late. But I guess the issue was, that a maven project archives the artifacts automatically. In my case, I disabled the automatic archiving and just archived the artifacts manually using the post build actions. This way, only the artifacts that I am interested in are archived. I am willing to leave the generated artifacts on disk until the next build runs.