More Apache Maven Best Practices

9,094
-1

Published on

Second presentation on a collection of best practices given at ApacheCon US 2008

Published in: Technology

More Apache Maven Best Practices

  1. 1. More Apache Maven Best Practices Brett Porter - brett@apache.org 1 1
  2. 2. More Apache Maven Best Practices Brett Porter - brett@apache.org 1 1
  3. 3. Welcome Back This time last year... Apache Maven Best Practices Slides are available online • http://blogs.exist.com/bporter/ But wait, there’s more! 2 2
  4. 4. Recap 3 3
  5. 5. Environment Set up your environment in advance A repository manager is a must 4 4
  6. 6. Keep it Simple Keep the POM simple Write your build like you write your code 5 5
  7. 7. Keep it Portable Keep the build portable Avoid hard coding Make artifacts portable and minimize resource filtering 6 6
  8. 8. Keep it Reproducible Before releasing, make sure the build is reproducible First, it must be portable Lock down versions Lock down environmental variations 7 7
  9. 9. The Enforcer <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <version>1.0-alpha-4</version> <executions> <execution> <goals> <goal>enforce</goal> </goals> <configuration> <rules> <requirePluginVersions> <banLatest>true</banLatest> <banRelease>true</banRelease> </requirePluginVersions> </rules> </configuration> ... 8 8
  10. 10. The Enforcer <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <version>1.0-alpha-4</version> <executions> <execution> <goals> <goal>enforce</goal> </goals> <configuration> <rules> <requirePluginVersions> <banLatest>true</banLatest> <banRelease>true</banRelease> </requirePluginVersions> </rules> </configuration> ... 9 9
  11. 11. The Enforcer <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <version>1.0-alpha-4</version> <executions> <execution> <goals> <rules><goal>enforce</goal> </goals> <requirePluginVersions> <configuration> <rules> <banLatest>true</banLatest> <requirePluginVersions> <banLatest>true</banLatest> <banRelease>true</banRelease> <banRelease>true</banRelease> </requirePluginVersions> </requirePluginVersions> </rules> </rules> </configuration> ... 9 9
  12. 12. The Enforcer Help ensure build will be reproducible Based on rules force specific plugin versions ban snapshots global exclusions force Maven/Java/OS version can write your own 10 10
  13. 13. Release Early and Often Make sure releases are quick, easy, and automated Use the Maven/Continuum tools to help 11 11
  14. 14. And Now... Dependency management Integration testing Maven sites and reporting Plugin development 12 12
  15. 15. Dependency Management 13 13
  16. 16. Dependencies Everywhere Transitive dependencies are very convenient... ... until you get bitten by bad metadata You wind up with a tree of artifacts you may or may not be using 14 14
  17. 17. Troubleshoot Dependencies mvn dependency:tree or equivalent Eclipse integration [INFO] org.example.maven:example-webapp:war:1.2-SNAPSHOT [INFO] +- junit:junit:jar:3.8.1:test [INFO] +- org.apache.struts:struts2-core:jar:2.0.5:compile [INFO] | +- opensymphony:xwork:jar:2.0.0:compile [INFO] | +- org.apache.struts:struts2-api:jar:2.0.5:compile [INFO] | +- freemarker:freemarker:jar:2.3.8:compile [INFO] | +- ognl:ognl:jar:2.6.9:compile [INFO] | - commons-logging:commons-logging:jar:1.0.4:compile [INFO] +- org.apache.struts:struts2-sitemesh-plugin:jar:2.0.5:compile [INFO] | - opensymphony:sitemesh:jar:2.2.1:compile [INFO] +- org.apache.struts:struts2-spring-plugin:jar:2.0.5:compile [INFO] | +- org.springframework:spring-beans:jar:2.0.1:compile [INFO] | +- org.springframework:spring-core:jar:2.0.1:compile [INFO] | +- org.springframework:spring-context:jar:2.0.1:compile [INFO] | | - aopalliance:aopalliance:jar:1.0:compile [INFO] | - org.springframework:spring-web:jar:2.0.1:compile [INFO] +- javax.servlet:servlet-api:jar:2.4:provided [INFO] +- javax.servlet:jsp-api:jar:2.0:provided [INFO] +- commons-fileupload:commons-fileupload:jar:1.1.1:compile [INFO] | - commons-io:commons-io:jar:1.1:compile [INFO] +- uk.ltd.getahead:dwr:jar:1.1-beta-3:compile [INFO] +- org.example.maven:example-model:jar:1.2-SNAPSHOT:compile [INFO] - org.example.maven:example-manager:jar:1.2-SNAPSHOT:compile 15 15
  18. 18. Troubleshoot Dependencies mvn dependency:tree or equivalent Eclipse integration [INFO] org.example.maven:example-webapp:war:1.2-SNAPSHOT <exclusions> +- junit:junit:jar:3.8.1:test [INFO] <exclusion> +- org.apache.struts:struts2-core:jar:2.0.5:compile [INFO] [INFO] | +- opensymphony:xwork:jar:2.0.0:compile <groupId>commons-logging</groupId> [INFO] | +- org.apache.struts:struts2-api:jar:2.0.5:compile [INFO] | +- freemarker:freemarker:jar:2.3.8:compile <artifactId>commons-logging</artifactId> [INFO] | +- ognl:ognl:jar:2.6.9:compile </exclusion>| - commons-logging:commons-logging:jar:1.0.4:compile [INFO] </exclusions> +- org.apache.struts:struts2-sitemesh-plugin:jar:2.0.5:compile [INFO] [INFO] | - opensymphony:sitemesh:jar:2.2.1:compile [INFO] +- org.apache.struts:struts2-spring-plugin:jar:2.0.5:compile [INFO] | +- org.springframework:spring-beans:jar:2.0.1:compile [INFO] | +- org.springframework:spring-core:jar:2.0.1:compile [INFO] | +- org.springframework:spring-context:jar:2.0.1:compile [INFO] | | - aopalliance:aopalliance:jar:1.0:compile [INFO] | - org.springframework:spring-web:jar:2.0.1:compile [INFO] +- javax.servlet:servlet-api:jar:2.4:provided [INFO] +- javax.servlet:jsp-api:jar:2.0:provided [INFO] +- commons-fileupload:commons-fileupload:jar:1.1.1:compile [INFO] | - commons-io:commons-io:jar:1.1:compile [INFO] +- uk.ltd.getahead:dwr:jar:1.1-beta-3:compile [INFO] +- org.example.maven:example-model:jar:1.2-SNAPSHOT:compile [INFO] - org.example.maven:example-manager:jar:1.2-SNAPSHOT:compile 15 15
  19. 19. Troubleshoot Dependencies mvn dependency:tree or equivalent Eclipse integration [INFO] org.example.maven:example-webapp:war:1.2-SNAPSHOT <exclusions> +- junit:junit:jar:3.8.1:test [INFO] <exclusion> +- org.apache.struts:struts2-core:jar:2.0.5:compile [INFO] [INFO] | +- opensymphony:xwork:jar:2.0.0:compile <groupId>commons-logging</groupId> [INFO] | +- org.apache.struts:struts2-api:jar:2.0.5:compile [INFO] | +- freemarker:freemarker:jar:2.3.8:compile <artifactId>commons-logging</artifactId> [INFO] | +- ognl:ognl:jar:2.6.9:compile </exclusion>| - commons-logging:commons-logging:jar:1.0.4:compile [INFO] </exclusions> +- org.apache.struts:struts2-sitemesh-plugin:jar:2.0.5:compile [INFO] [INFO] | - opensymphony:sitemesh:jar:2.2.1:compile [INFO] +- org.apache.struts:struts2-spring-plugin:jar:2.0.5:compile <rules> [INFO] | +- org.springframework:spring-beans:jar:2.0.1:compile [INFO] | +- org.springframework:spring-core:jar:2.0.1:compile <bannedDependencies> [INFO] | +- org.springframework:spring-context:jar:2.0.1:compile <excludes> [INFO] | | - aopalliance:aopalliance:jar:1.0:compile [INFO] | - org.springframework:spring-web:jar:2.0.1:compile <exclude>commons-logging:commons-logging</exclude> [INFO] +- javax.servlet:servlet-api:jar:2.4:provided </excludes> [INFO] +- javax.servlet:jsp-api:jar:2.0:provided [INFO] +- commons-fileupload:commons-fileupload:jar:1.1.1:compile </bannedDependencies> [INFO] | - commons-io:commons-io:jar:1.1:compile </rules> [INFO] +- uk.ltd.getahead:dwr:jar:1.1-beta-3:compile [INFO] +- org.example.maven:example-model:jar:1.2-SNAPSHOT:compile [INFO] - org.example.maven:example-manager:jar:1.2-SNAPSHOT:compile 15 15
  20. 20. Don’t Add to the Problem Be careful with your own dependencies Specify only what you need Specify scope Use optional if you must Use dependencyManagement to: coerce Maven to use a particular version enforce consistency within a project 16 16
  21. 21. Only What You Need mvn dependency:analyze find out what you’re using but not declaring find out what you’re declaring but not using [WARNING] Used undeclared dependencies found: [WARNING] opensymphony:xwork:jar:2.0.0:compile [WARNING] Unused declared dependencies found: [WARNING] org.apache.struts:struts2-spring-plugin:jar:2.0.5:compile [WARNING] javax.servlet:jsp-api:jar:2.0:provided [WARNING] commons-fileupload:commons-fileupload:jar:1.1.1:compile [WARNING] javax.servlet:servlet-api:jar:2.4:provided [WARNING] org.apache.struts:struts2-core:jar:2.0.5:compile [WARNING] org.apache.struts:struts2-sitemesh-plugin:jar:2.0.5:compile [WARNING] uk.ltd.getahead:dwr:jar:1.1-beta-3:compile 17 17
  22. 22. Integration Testing 18 18
  23. 23. “Integration” Testing Covers any type of testing beyond unit integration testing functional testing, etc. Unfortunately, an afterthought in Maven 2.0.x at least in the lifecycle 19 19
  24. 24. Patterns Tests in a separate module Tests in same project Use of profiles applies to both eg. Maven Plugin ITs are in the plugin Core ITs are separate 20 20
  25. 25. Separate Project Most common pattern If you are testing multiple modules, use a separate project 21 21
  26. 26. Separate Project create a parallel module use the regular src/test/java directory add a dependency on the module(s) being tested enable the module in a profile if a profile is necessary 22 22
  27. 27. Separate Project create a parallel module use the regular src/test/java directory add a dependency on the module(s) being tested enable the module in a profile if a profile is necessary <profile> <id>run-its</id> <modules> <module>integration-tests</module> </modules> </profile> 22 22
  28. 28. Testing in the Same Project Good for framework examples and small projects Two alternatives separate directory, redeclare both compilation and test plugins • eg src/it same test directory, test exclusions • eg **/selenium/** Include the tests in a profile 23 23
  29. 29. Example: Selenium 24 24
  30. 30. Example: Selenium <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <excludes> <exclude>**/selenium/**</exclude> </excludes> </configuration> </plugin> 24 24
  31. 31. Example: Selenium <plugin> <profile> <groupId>org.apache.maven.plugins</groupId> <id>selenium</id> <artifactId>maven-surefire-plugin</artifactId> <build> <configuration> <plugins> <plugin> <excludes> <groupId>org.apache.maven.plugins</groupId> <exclude>**/selenium/**</exclude> <artifactId>maven-surefire-plugin</artifactId> </excludes> <executions> <execution> </configuration> <phase>integration-test</phase> </plugin> <goals> <goal>test</goal> </goals> <configuration> <includes> <include>**/selenium/**/*Test.java</include> </includes> </configuration> </execution> </executions> </plugin> </plugins> </build> </profile> 24 24
  32. 32. Example: Selenium <plugin> <profile> <groupId>org.apache.maven.plugins</groupId> <id>selenium</id> <artifactId>maven-surefire-plugin</artifactId> <build> <configuration> <plugins> <plugin> <excludes> <groupId>org.apache.maven.plugins</groupId> <exclude>**/selenium/**</exclude> <artifactId>maven-surefire-plugin</artifactId> </excludes> <executions> <execution> </configuration> <phase>integration-test</phase> </plugin> <goals> <plugin> <groupId>org.codehaus.mojo</groupId> <goal>test</goal> <artifactId>selenium-maven-plugin</artifactId> </goals> <version>1.0-beta-1</version> <configuration> <executions> <includes> <execution> <include>**/selenium/**/*Test.java</include> <phase>pre-integration-test</phase> </includes> <goals> </configuration> <goal>start-server</goal> </execution> </goals> </executions> </execution> </plugin> </executions> </plugins> <configuration> </build> <background>true</background> </profile> </configuration> </plugin> 24 24
  33. 33. Maven Sites and Reporting 25 25
  34. 34. Maven Sites Two technologies reporting rendering They aren’t the same! They work together ... but can be used independently ... and should be for different tasks 26 26
  35. 35. Site Tips Avoid reports on documentation sites some minimal project reports, like mailing lists, source repository may be relevant Use site inheritance Use versioning in the URL for version specific usage documentation especially for developer reference site Include release notes in the versioned usage documentation 27 27
  36. 36. Report Tips Set up what you’ll use! don't create reports with thousands of issues It won’t be used if... too much information irrelevant information Don’t settle for the default settings 28 28
  37. 37. Report Tips Use active checks, not passive reports fail the build! Use profiles if they are time consuming run them in continuous integration developers can use IDE integration Have a centralized location to deploy reports visualize problems, and errors under the build failure threshold 29 29
  38. 38. Plugin Development 30 30
  39. 39. Don’t Fear Scripting Sometimes it is easier to use a script for short, one-off, customizations antrun plugin jruby, groovy plugin, etc. If you might use it twice, consider writing a plugin 31 31
  40. 40. Plugin Development It isn’t the big deal you think it is Can be written in Java, Ruby, Groovy, ... Plugins are as easy to write as any other module though they still lack the quick “run and test” scenario of most scripting solutions 32 32
  41. 41. Plugin Tips Write functionality in components, with the Mojo as a “wrapper” easier to test and reuse the theory of mojos as pojos isn’t as realistic due to the current wiring Minimize Maven API dependencies and component exposure eg, use maven-artifact, not maven-core Minimize dependencies in general all builds have to download them! 33 33
  42. 42. Final Word Do as we say... ... but not as we do Maven fails to implement many of these practices in various projects We learned the hard way! It can be really hard to find time to go back and fix it later 34 34
  43. 43. Questions? Brett Porter - brett@apache.org 35 35
  44. 44. Questions? Brett Porter - brett@apache.org 35 35

×