managing your builds with maven 2
DESCRIPTION
Managing your builds with Maven 2. Craig Walls Gateway Software Symposium 2007 [email protected] http://www.springinaction.com. About you…. Java? .NET? Ruby/Rails? Erlang? Java 6? Java 5? Java 1.4? Java 1.3? 1.2 or older? Who’s using Maven? How long? Maven 1? Maven 2?. About me. - PowerPoint PPT PresentationTRANSCRIPT
Managing your builds with Maven 2
Craig WallsGateway Software Symposium 2007
http://www.springinaction.com
About you…
• Java? .NET? Ruby/Rails? Erlang?– Java 6? Java 5? Java 1.4? Java 1.3? 1.2
or older?
• Who’s using Maven? How long?– Maven 1? Maven 2?
About me
• Agile developer with Semantra– Natural language data access
• Developing software professionally for over 13 years– Telecom, Finance, Retail, Education– Java for most of that– Also some C/C++, C#/.NET, Ruby
• Spring fanatic
Intro to Maven 2
What is Maven?
• Build tool?
• Project management tool?
• Dependency management tool?
• Documentation tool?
Maven vs. Ant
Ant• Boilerplate build
code• Explicit target
definitions• Explicit project
structure• Dependencies must
be provided by developer
Maven• Declarative• Common tasks are
built-in• Project structure
imposed by Maven• Dependencies
declared (Maven gets them for you)
MYTH: Maven is hard
• Maven is different than Ant…but not necessarily harder.
• Q: Is Chinese harder than English?– 1.2 billion people don’t think so.
• In most cases, Maven is significantly simpler than Ant.
• You must be willing to think differently about how you build your projects.
MYTH: Maven is slow
• Fact: Maven is slow when it needs to download a lot of dependencies.
• Dependencies are cached locally, so future builds will be faster.
• Typical builds are at least as fast (and maybe faster) than Ant.
Maven principles
• Convention over configuration
• Declarative execution
• Reuse of build logic
• Coherent organization of dependencies
Consistent directory structure
• How Maven knows where everything is.
• How the developer knows where everything is.
Maven lifecycle
1. validate
2. generate-sources
3. process-sources
4. generate-resources
5. process-resources
6. compile
7. process-classes
8. generate-test-sources
9. process-test-sources
10. generate-test-resources
11. process-test-resources
12. test-compile
13. test
14. package
15. pre-integration-test
16. integration-test
17. post-integration-test
18. verify
19. install
20. deploy
Running Maven
% maven [options] [goal(s)] [phase(s)]
Examples:
% maven -o clean package% maven tomcat:deploy% maven site
Exploring the POM
Key POM sections
• Basic project info
• Build section
• Reporting section
• Dependencies section
• Profiles section
Basic project info
• Basic project information…
<project> <modelVersion>4.0.0</modelVersion> <name>Poker Service</name> <groupId>com.habuma</groupId> <artifactId>Poker</artifactId> <version>1.0</version> <packaging>war</packaging> <description> Sample Spring-WS service </description> […]</project>
Build settings
• Used to define build properties and configure plugins…
<build> <finalName>Poker</finalName> <plugins> … </plugins></build>
Reports settings
• Configure plugins for generating reports
<reporting> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jxr-maven-plugin</artifactId> </plugin> </plugins></reporting>
Dependencies
• Tells Maven what other libraries this app depends upon…
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> <version>2.0</version> <scope>compile</scope> </dependency></dependencies>
Dependency resolution
• Dependencies are automatically resolved…– First looks in local repository:
• ~/.m2/repository
– Then looks in one or more remote repositories• Default: http://repo1.maven.org
• Transitive dependencies– Your project depends on Hibernate…– …which depends on cglib…which depends on…
• SNAPSHOT dependencies– Downloaded anew once every day
Other repositories
• http://download.java.net/maven/2/• http://snapshots.repository.codehaus.org• http://repository.codehaus.org
• Add a new repository to your build:
<repository> <id>Codehaus</id> <name>Codehaus Repository</name> <url>http://repository.codehaus.org</url> <layout>default</layout></repository>
Dependency scopes
• compile - Dependency is made available in all classpaths (compile, test, and runtime)– Most dependencies will be in this scope
• provided - Dependency is made available during compile, but will be provided by JDK or container at runtime.– The Servlet API JAR is in this scope
• test - Dependency is made available only at test time– This scope is appropriate for JUnit.
• runtime - Dependency is made available in test and runtime classpaths, but not at compile-time
• system - Like “provided” but you must explicitly provide the dependency JAR file.
Online vs. offline
• Remote dependency resolution depends on internet connection.
• If you’ll be offline, run Maven with -o switch– Dependencies will only be resolved from
local repository– Of course, dependencies must be in local
repository
What if a JAR isn’t in repository?
• If it’s open source, look again. It’s probably there.
• Licenses prevent commercial and some other (SUN) JAR files from being placed in public Maven repositories.– Options:
• Install in your own private corporate repository• Install in your local repository
Profiles
• Profiles enable you to override certain properties for different scenarios.
<profiles> <profile> <id>itest</id>… </profile></profiles>
• Enacted with -P switch on command line.
Maven in Action
No…this isn’t a book title
Maven project kickstart
• Use the Maven archetype plugin to go from zero to working app in about 1 second…
% mvn archetype:create -DgroupId=com.habuma -DartifactId=MyAwesomeApp
Other archetypes…
• maven-archetype-*
– archetype– bundles– j2ee-simple– marmalade-mojo– mojo– plugin-site– plugin
– portlet– profiles– quickstart– simple– site-simple– site– webapp
Compiling, testing, packaging,etc
• Most basic project build activities are accomplished through Maven’s lifecycle goals.– Compile:
% mvn compile
– Run unit tests:% mvn test
– Create a JAR, WAR, EAR, etc:% mvn package
Choosing a Java version
• Configure the compiler plugin…<build> […] <plugins> […] <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> </plugins></build>
Tweaking the packaging name
• By default, the project name and version number end up in the generated package– MyProject-2.1.3.war
• Use <finalName> to set the…er…final name of the package<build> <finalName>${project.name}</finalName></build>
Filtering resources
• Configure resources for filtering…<build> <filters> <filter>src/main/filters/other.properties</filter> </filters> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources></build>
• Use properties in resource files…application.name=${pom.name}application.version=${pom.version}application.contactNumber=${other.contactNumber}
• Filters will be applied during the “process-resources” goal
Optional
Cleaning out all build artifacts
• The “clean” goal removes the target directory– Not a lifecycle goal…part of the “clean” plugin– Effectively removing all build artifacts
% mvn clean
• Can be used along with other goals
% mvn clean package
Automatically clean every time
• If you can’t or don’t want to type clean every time…– Attach the “clean” goal to the “validate” lifecycle goal:
<project> [...] <build> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <executions> <execution> <id>auto-clean</id> <phase>validate</phase> <goals> <goal>clean</goal> </goals> </execution> </executions> </plugin> </plugins> </build> [...]</project>
Setting properties
• Use a <properties> block to set properties: <properties> <spring.version>2.0.6</spring.version></properties>
• Use ${…} syntax for referencing properties:<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> <version>${spring.version}</version> <scope>compile</scope> </dependency></dependencies>
Install a JAR into the local repo
• If the project’s packaging is “jar”, the “install” lifecycle goal will do:% mvn install
• To install a 3rd party JAR (assuming that it’s not already in a repository):% mvn install:install-file -DgroupId=com.bigmoneysoftware -DartifactId=ProprietaryLibrary -Dversion=1.2.1 -Dpackaging=jar -Dfile=MyLibrary-1.2.1.jar
Kickstart a web app project
• Use Maven’s webapp archetype:
% mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetype -DarchetypeArtifactId=maven-archetype-webapp -DgroupId=com.habuma -DartifactId=MyWebApp
Deploy a web app to a server
• Use Cargo’s (http://cargo.codehaus.org) Maven plugin<plugin> <groupId>org.codehaus.cargo</groupId> <artifactId>cargo-maven2-plugin</artifactId> <version>0.3</version> <configuration> <container> <containerId>tomcat5x</containerId> <type>remote</type> </container> <configuration> <type>runtime</type> <properties> <cargo.hostname>localhost</cargo.hostname> <cargo.servlet.port>8080</cargo.servlet.port> <cargo.remote.username>admin</cargo.remote.username> <cargo.remote.password>password</cargo.remote.password> </properties> </configuration> </configuration></plugin>
• Note: Tomcat must be running!
Deploy to embedded Jetty
• Add the Jetty plugin<build> <plugins> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId> </plugin> </plugins></build>
• Start Jetty and run your app:% mvn jetty:run
Multi-module projects
• Create a top-level project with “pom” packaging<project> <modelVersion>4.0.0</modelVersion> <groupId>com.habuma</groupId> <version>1.0-SNAPSHOT</version> <artifactId>MySuperApp</artifactId> <packaging>pom</packaging> <modules> <module>my-lib</module> <module>my-webapp</module> </modules></project>
• Reference parent in child POMs<project> <parent> <groupId>com.habuma</groupId> <artifactId>MySuperApp</artifactId> <version>1.0-SNAPSHOT</version> </parent> […]</project>
Exclude integration tests
• Configure SureFire plugin to skip “ITest” classes
<build> […] <plugins> […] <plugin> <artifactId>maven-surefire-plugin</artifactId> <configuration> <excludes> <exclude>**/*ITest*</exclude> </excludes> </configuration> </plugin> </plugins></build>
Running integration tests
• Create an “itest” profile that does not exclude “ITest” classes:
<profile> <id>itest</id> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <excludes> <exclude>none</exclude> </excludes> </configuration> </plugin> </plugins> </build></profile>
• Run integration tests with…% mvn test -Pitest
Getting past those pesky firewalls
• In settings.xml:
<settings> <proxies> <proxy> <active>true</active> <protocol>http</protocol> <host>proxy.habuma.com</host> <port>8080</port> <username>mwalls</username> <password>letmeout01</password> </proxy> </proxies></settings>
Embedding Ant
• Use the “antrun” plugin…<build> […] <plugins> […] <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> <dependencies> <dependency> <groupId>ant</groupId> <artifactId>ant-antlr</artifactId> <version>1.6.5</version> </dependency> </dependencies> <configuration> <tasks> <echo>Do Ant stuff</echo> <ant antfile="ant-build.xml" inheritAll="true" inheritRefs="true" /> </tasks> </configuration> </plugin> </plugins></build>
• Execute Ant...% mvn antrun:run
Attaching Ant to a lifecycle goal
• Place <configuration> inside of an <execution> block:<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> […] <executions> <execution> <phase>install</phase> <configuration> <tasks> <echo>Do Ant stuff</echo> </tasks> </configuration> </execution> </executions></plugin>
Getting some help
• help:active-profiles– Lists the profiles that are currently active for the
build
• help:effective-pom– Displays the effective POM for the current build,
with active profiles factored in
• help:effective-settings– Prints out calculated settings for the project, given
any profile enhancement and the inheritence of global settings into the user settings.
• help:describe– Describes a plugin and its attributes
Generate a project website
• Use the “site” plugin:
% mvn site
• Kickstart a project with a site structure in place:
% mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-site -DgroupId=com.habuma -DartifactId=MyAwesomeApp
Give credit to project members
• Developer info will be included in generated site:
<developers> <developer> <id>craig</id> <name>Craig Walls</name> <email>[email protected]</email> <roles> <role>Head honcho</role> <role>Developer</role> </roles> <organization>habuma.com</organization> <timezone>-5</timezone> </developer></developers>
Continuous Integration
• Includes a link to the CI system in the site<ciManagement> <system>Cruise Control</system> <url>http://ci.habuma.com/cruisecontrol</url> <notifiers> <notifier> <configuration> <address>[email protected]</address> </configuration> </notifier> </notifiers></ciManagement>
Issue Management
• Includes a link to the issue management system
<issueManagement> <system>JIRA</system> <url>jira.habuma.com</url></issueManagement>
Licenses
• Includes a license page on the site
<licenses> <license> <name>Apache License, Version 2.0</name> <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> <distribution>repo</distribution> </license></licenses>
Mailing Lists
• Includes mailing list information on the generated project web site
<mailingLists> <mailingList> <name>Poker Service Mailing List</name> <subscribe>[email protected]</subscribe> <unsubscribe>[email protected]></unsubscribe> <post>[email protected]</post> <archive>http://mail-archives.habuma.com</archive> </mailingList></mailingLists>
Reporting: JavaDoc
• Generates JavaDoc and includes in generated project web site:
<reporting> <plugins> <plugin> <artifactId> maven-javadoc-plugin </artifactId> </plugin> </plugins></reporting>
Reporting: Java XRef
• Includes a Java cross-refence with the generated project web site<reporting> <plugins> <plugin> <groupId>org.codehaus.mojo </groupId> <artifactId> jxr-maven-plugin </artifactId> </plugin> </plugins></reporting>
Reporting: Test coverage
• Includes test code coverage report<reporting> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>cobertura-maven-plugin </artifactId> </plugin> </plugins></reporting>
Reporting: Test reports
• Includes unit test reports<reporting> <plugins> <plugin> <groupId>org.apache.maven.plugins </groupId> <artifactId>maven-surefire-plugin </artifactId> </plugin> </plugins></reporting>
Reporting: JDepend
• Produces a JDepend report and includes with generated project web site<reporting> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jdepend-maven-plugin </artifactId> </plugin> </plugins></reporting>
Additional site content
• Placed in src/site/…– …/apt : Almost plain text– …/fml : FAQ markup– …/xdoc : XDoc files– site.xml : Site structure
Creating an archetype
• Build a project with the following structure:
• Or better yet…use the archetype archetype% mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-archetype -DgroupId=com.habuma -DartifactId=MyArchetype
An archetype’s pom.xml
<project> <modelVersion>4.0.0</modelVersion> <groupId>com.habuma</groupId> <artifactId>MyArchetype</artifactId> <packaging>maven-plugin</packaging> <version>1.0</version></project>
META-INF/archetype.xml<archetype> <id>webapp</id> <sources> <source>src/main/java/HomeController.java</source> <source>src/main/java/AddressFormController.java</source> <source>src/main/java/Address.java</source> </sources> <testSources> <source>src/test/java/HomeControllerTest.java</source> </testSources> <resources> <resource>.project</resource> <resource>.classpath</resource> <resource>.springBeans</resource> <resource>src/main/webapp/WEB-INF/web.xml</resource> <resource>src/main/webapp/WEB-INF/mvc.xml</resource> […] </resources></archetype>
archetype-resources
• Where the project template lives• Includes any resources and source
code that needs to be included in generated project.
• Source files are “packaged” automatically (be sure to include ${package} in .java files).
• Text files are filtered and placeholders are replaced.
Final Tips & Gotchas
• Resolve dependency ambiguities manually
• Avoid SNAPSHOT dependencies
• Only deploy non-SNAPSHOT dependencies once
• Not all projects have quality POM files
• Be careful when upgrading Maven--test first!
Additional Maven resources
• “Get the most out of Maven 2 site generation”http://www.javaworld.com/javaworld/jw-02-2006/jw-0227-maven.html
• “The Maven 2 POM Demystified”http://www.javaworld.com/javaworld/jw-05-2006/jw-0529-maven.html
• “Better Builds with Maven: How-to Guide for Maven 2”http://www.devzuz.com/web/guest/products/resources#BBWM
• “Maven: The Definitive Guide”http://www.sonatype.com/book/