Maven Workflow
I stumbled upon Maven much much later in my Java career than I should have. But now that I’m here, I’d like to leverage it for my needs. It’s a pretty versatile system that can do quite a lot. I’m sure much more than I’d care to explore. I’m not going to really introduce it as there’s enough on the web you can browse to basically get the hang of what Maven is about and what it can do for you.
For the purposes of this post, I’m going to catalog some of the things I did to configure Maven so that it can accomplish my workflow goals. Namely:
- Create a Java project that can be managed by Maven and developed in Eclipse.
- Commit to a source control management system.
- Install to the local Maven repository so other projects can use it.
- Run the project in a web container.
- Sync the content to an external repository.
- Deploy releases of the project as a zip and to a maven repository.
If you need an introduction to what Maven is or the exact inner workings of a pom.xml, this post wont be that. But if you want to take a peek at some of the things I’ve clobbered together in the pom.xml, and perhaps have any other neat suggestions, feel free to take a look and contribute some of your own solutions.
Commands
But first, a little bit of a cheatsheet for the commands I most commonly use in Maven:
mvn clean
: Return the project to base state. Basically removes the “target” directory.mvn package
: Create the jars and packaged items (like wars) from your codemvn install
: Install the project to your local repository. Keeps any -SNAPSHOT monikers used.mvn deploy
: Pushed the installed project to remote maven repositories.mvn release:prepare
: Prepares the project for release. Be sure to check in all your code first else this will faile. Also the release process will automatically remove any -SNAPSHOT monikers from your version and allow you to specify the next version to update to. Pretty convenient.mvn release:perform
: Once prepared, actually performs the release. This means doing any install and deploy calls.mvn release:clean
: Cleans up the release details like the property file and so on. Especially useful if you forgot to checkin prior to doing the prepare stage. Although the plugin is smart enough to continue where you left off, I usually just like to have a clean start all the way through.mvn release:rollback
: Rollsback a release to the previous version. I haven’t quite used this enough to really make use of it yet.mvn war:war
: Explicitly creates the packaged war file for a project. Even if the project is specifying a packaging of jar.mvn tomcat7:run
: Runs the project in a tomcat environment. No need to explicitly create a war via the pom.xml or to execute war:war. It’ll just do it.
pom.xml
And the related pom.xml I’ve crafted to get the steps above done. It took a while to cobble it together and it’s still not quite fully there, but close enough. I’ll use the authentication module’s pom.xml as an example. See the version this post is based on: pom.xml and perhaps to what it has currently evolved: pom.xml.
1. Create
I’ve listed the creation step as a formality since I need to remind myself how it gets done. However, I already did that with the maven setup post, so go there, get setup, and come back.
2. Commit
Once your project is there, all you basically need to do is to git init
in the directory and you’re all set. Most of the useful commands I use git, including some setup tips, I’ve cataloged on the git cheatsheet post.
3. Install
I usually write components and frameworks where one project will rely on another. So it’s important to have a way to nicely package and install these projects to a central location from where it can be synced. Maven offers a local repository to do just that. All you need to do once you’re ready is to do a:
mvn install
and the code should get packaged and installed to your local maven repository. Then other projects can simply add their dependency for your project based on your group and artifact ids (and version). Now why bother doing this if Eclipse can simply link the 2 projects together? It’s just more universal. You wont be tied down to Eclipse to manage the interconnection and if you want to reuse your component in something like a Play Framework project, it’s a trivial addition to add your local project just like you would any other public project. It’s one of those that’s simple to do and just better in the long run to get used to.
4. Run
Often times, even if I’m creating a component piece, I may want to include a simple showcase just to help the end user/developer visualize what the project is about. Normally, by Maven convention, you would have a base <packaging>jar</packaging>
project and a related <packaging>war</packaging>
project inked to it for the simple application. But I find it to be rather cumbersome to have 2 projects just for a simple showcase.
So instead, you can actually get away with telling maven to create your project as a web app, change the packaging to “jar” in the pom.xml, attach the tomcat plugin to it, and just tell it to ignore the packaging and run:
<plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>${tomcat7-maven-plugin.version}</version> <configuration> <ignorePackaging>true</ignorePackaging> <url>http://localhost:8080/manager</url> </configuration> </plugin>
Magically it treats your jar project as a war (provided you created it as a web app) and just makes it run in the tomcat environment via this command:
mvn tomcat7:run
I had actually experimented with trying to keep the packaging as a war and telling maven to export just the jar into the local maven repository for shared use, but for some reason, it would always copy the .war over to the local maven repo as the .jar, which essentially broke all the downstream projects. I’m not sure why this happens, and a similar issue seems to simply have been closed.
So now I keep it packaged as a jar and if, for some reason, I actually want the war, I’ll use the mvn war:war
command. Otherwise, the mvn tomcat7:run
command works just fine.
5. Sync
For public projects, I, like quite a lot of developers, decided that GitHub can get that honor. For a simple sync of the code, it’s nothing more than your usual git push
to push your code to GitHub. But a release deploy is a little different.
6. Deploy
Not only do I want to sync my code to GitHub, I want to use GitHub as a release hub for my code. This means that I would like to have my code packaged as a zip file, version tagged with the current version number I’m working on, upload it to the “Releases” section in GitHub, and increment my local version to the next iteration so that I can continue to work on the next version right away.
Not only that, I’d like to be able to offer my code to a Maven repository so that others can access it via Maven (or sbt) instead of downloading it. While officially, you’ll probably want to formally release your code to somewhere like Sonatype’s system so that your project will hit the main Maven repository, I just haven’t gotten that far yet. In the meantime, you can apparently just create a branch in GitHub to host your code. Sounds like a good compromise solution for the time being.
Luckily, GitHub offers a plugin for all this. You will have to modify a few things to make it work:
- Add your GitHub credentials to settings.xml
- Add a distributionManagement section to the pom.xml
- Configure the maven-release-plugin to use the version format you want (or if you don’t care, no need).
- Configure the site-maven-plugin with your desired details for release and maven repository publication.
Once all that is complete:
mvn clean
mvn release:prepare
mvn release:perform
should get you rolling. It’s going to ask you versioning information and so on about your release and incremental version. It’s not too bad, but be sure to commit your work first, else the process will fail and you’ll probably want to mvn release:clean
before trying again just to make sure you get a proper clean start. When all is said and done, you should see your releases section populated and the named repository branch should have your latest release ready for public use. The repository for people to point to will be something like this:
<repository> <id>com.subdigit.authentication</id> <url>https://raw.github.com/subdigit/authentication/mvn-repo/</url> <snapshots> <enabled>true</enabled> <updatePolicy>always</updatePolicy> </snapshots> </repository>
The one catch though is the plugin cant seem to do a nicely formated native release. So be sure to click on the version number of the release and edit it manually. Add whatever description you want and any other details, save, and it should look a whole lot better.
Suggestions?
I hope this helps. It’s nothing special, just something I want to use to help automate my project maintenance/publication workflow. I’m sure there are a lot of improvements that could be made and other neat tips and tricks to shove into the pom.xml, so if you have any, I’m more than happy to entertain suggestions.
Thanks!
I hope this takes care of a lot of the administrative stuff I dont really care to think about too often. Maven image sourced from ideyatech