650 likes | 849 Views
Managing your builds with Maven 2. Craig Walls Gateway Software Symposium 2007 craig@habuma.com 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.
E N D
Managing your builds with Maven 2 Craig Walls Gateway Software Symposium 2007 craig@habuma.com 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
What is Maven? • Build tool? • Project management tool? • Dependency management tool? • Documentation tool?
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) Maven vs. Ant
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.
validate generate-sources process-sources generate-resources process-resources compile process-classes generate-test-sources process-test-sources generate-test-resources process-test-resources test-compile test package pre-integration-test integration-test post-integration-test verify install deploy Maven lifecycle
Running Maven % maven [options] [goal(s)] [phase(s)] Examples: % maven -o clean package % maven tomcat:deploy % maven site
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
maven-archetype-* archetype bundles j2ee-simple marmalade-mojo mojo plugin-site plugin portlet profiles quickstart simple site-simple site webapp Other archetypes…
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>craig@habuma.com</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>dev@habuma.com</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>