3. Agenda
What are we discussing today?
What makes a good build script?
Smelly build scripts
Choosing your tools
Maven tips
Ant tips
Tuesday, 22 June 2010
5. Build quality - quality builds
What makes a good build script?
Gold Standard
Portable
Reproducible
Standard
Maintainable
Tuesday, 22 June 2010
6. Build quality - quality builds
Gold Standard
Reference build process
Reference binaries
Tuesday, 22 June 2010
7. Build quality - quality builds
Portable
Runs anywhere
Runs on any OS
No local dependencies
Environment-specific configurations
Specially-installed software or databases
...
Tuesday, 22 June 2010
8. Build quality - quality builds
Reproducible
“Play it again, Sam”
Tuesday, 22 June 2010
9. Build quality - quality builds
Standard
Knowing what to expect
Tuesday, 22 June 2010
10. Build quality - quality builds
Maintainable
Think of the next dude
Tuesday, 22 June 2010
11. Smelly builds
So what makes a poor build script?
1) The hard coded build
2) The OS-specific build
3) The IDE-only build
4) The Magic Machine build
5) The Oral Tradition build
6) The Nested build
7) The Messy Dependencies build
8) The DYI build
9) The untrustworthy build
10) The slow build
Tuesday, 22 June 2010
12. Paths
..
1/
URLs
Smelly builds
9.
c-
gi
lo
1
eb
00
Passwords
/w
:7
om
ea
.c
/b
me
C:
ac
r.
ve
er
ts
es .>
/t "..
:/ ger
"ti
tp rd=
The hard coded build
ht swo
pas
tt"
sco
e="
nam
ser
n u
<sv
/>
M E }"
S_HO
JBOS
env.
= "$ {
alue
s" v
Environment
jbos
dir.
me="
variables
y na
pert
<pro
Tuesday, 22 June 2010
15. Smelly builds
The hard coded build
<target name="war" >
<war destfile="c:/tomcat/jakarta-tomcat-5.0.19/webapps/app.war"
webxml="${src}/app.xml" basedir="${bin}" />
</target>
Hard-coded directories
Tuesday, 22 June 2010
16. Smelly builds
The hard coded build
<property name="wardir"
location="c:/tomcat/jakarta-tomcat-5.0.19/webapps"/>
<target name="war" >
<war destfile="${wardir}" webxml="${src}/app.xml"
basedir="${bin}" />
</target>
Still hard-coded
Tuesday, 22 June 2010
17. Smelly builds
The hard coded build
<svn username="scott" password="tiger">
<checkout url="http://subversion.acme.com/myapp/trunk"
destPath="${subproject.dir}" />
</svn>
Hard-coded username/password
Tuesday, 22 June 2010
18. Smelly builds
The hard coded build
<property environment="env"/>
<property name="dir.jboss" value="${env.JBOSS_HOME}"/>
Environment variable
Tuesday, 22 June 2010
19. Smelly builds
The OS-specific build
<exec command="grep "@" ${build.dir} | wc -l"
outputproperty="token.count"/>
Tuesday, 22 June 2010
20. Smelly builds
The OS-specific build
...
CALL PAUSE.CMD
...
build.cmd
...
:: Check for a non-existent IP address
:: Note: this causes a small extra delay!
IF NOT DEFINED NonExist SET NonExist=10.255.255.254
PING %NonExist% -n 1 -w 100 2>NUL | FIND "TTL=" >NUL
...
pause.cmd
Tuesday, 22 June 2010
21. Smelly builds
The IDE-only build
Tuesday, 22 June 2010
22. Smelly builds
The Magic Machine build
Directories
App servers
Databases
Configuration files
Environment variables
Installed software or tools
Tuesday, 22 June 2010
23. Smelly builds
The Magic Machine build
<proprerty weblogic.dir="/u01/app/bea/weblogic-9.1"/>
Directories
App servers
Databases
Configuration files
Environment variables
Installed software or tools
Tuesday, 22 June 2010
24. Smelly builds
The Oral Tradition build
Tuesday, 22 June 2010
25. Smelly builds
The Nested Build
#! /bin/sh
ANT_HOME=/u01/app/tools/ant-1.7.1
...
$ANT_HOME/ant $1
project/tools/ant.sh
Tuesday, 22 June 2010
31. Choosing your tools
Flexibility verses Convention
What’s better: flexibility or standards?
It depends what you’re doing...
Tuesday, 22 June 2010
32. Choosing your tools
Encourage/enforce
Standards and Conventions Support standards
standards
3
Easy to read
2
Make up your
own standards
No standards
Hard to read
Ad-hoc scripting Standards and Conventions
Tuesday, 22 June 2010
33. Choosing your tools
Flexibility and expressiveness
3 Do whatever you
Easy to read
want
2
Encourage/enforce
standards
Hard to read
Makes you stick to conventions Easy to do whatever you want
Tuesday, 22 June 2010
34. Choosing your tools
Flexibility verses Convention
Build Scripting Rule 1
“A build script will tend to reflect the personality of
it’s developer”
Tuesday, 22 June 2010
35. Choosing your tools
Flexibility verses Convention
Build Scripting Rule 2
“The more flexible a build script, the more likely it
is to become unmaintainable”
Tuesday, 22 June 2010
36. Choosing your tools
Flexibility verses Convention
Flexibility is great for some jobs:
Ad-hoc tasks
Some deployment tasks
“Out-of-the-box” stuff
Tuesday, 22 June 2010
37. Choosing your tools
Flexibility verses Convention
But convention pay off in lower maintenance costs
Tuesday, 22 June 2010
38. Ant tips
Better Ant scripts
Consistent conventions
Declare your dependencies
Make it readable
Tidy up your mess
Avoid long scripts
Tuesday, 22 June 2010
39. Ant tips
Be consistent
Standardize target names
Document your public targets
Tuesday, 22 June 2010
40. Ant tips
Declare your dependencies
Use an Enterprise Repository Manager
Several tool choices:
Maven Ant Tasks
Ivy
Tuesday, 22 June 2010
41. Ant tips
Using the Maven Ant Tasks
Declare dependencies
Deploy to a Maven Enterprise Repository
<artifact:dependencies pathId="dependency.classpath">
<dependency groupId="junit" artifactId="junit"
version="3.8.2" scope="test"/>
<dependency groupId="javax.servlet" artifactId="servlet-api"
version="2.4" scope="provided"/>
</artifact:dependencies>
Tuesday, 22 June 2010
42. Ant tips
Make it readable
Write a build script like your source code...
Avoid long targets
Avoid long build scripts
Use descriptive target names
Tuesday, 22 June 2010
43. Ant tips
Tidy up your mess
Always define a ‘clean’ target.
Tuesday, 22 June 2010
44. Ant tips
Move to Maven ;-)
Tuesday, 22 June 2010
46. Maven tips
Keep it simple
Use modules
Use an organization-level POM
Tuesday, 22 June 2010
47. Maven tips
Keep it portable
No hard-coding
Define sensible defaults for properties and profiles
Avoid resource filtering for production code
Tuesday, 22 June 2010
48. Maven tips
Keep it reproducible
Avoid external snapshots
Specify plugin versions
Use consistent environments
Tuesday, 22 June 2010
49. Maven tips
Consistent environments
Enforcing a minimum Maven version
<?xml version="1.0"?>
<project...>
<modelVersion>4.0.0</modelVersion>
<groupId>com.ciwithhudson.gameoflife</groupId>
<artifactId>gameoflife</artifactId>
<version>0.0.1-SNAPSHOT</version>
Minimum Maven version
<name>gameoflife</name>
<prerequisites>
<maven>2.2.1</maven>
</prerequisites>
Tuesday, 22 June 2010
50. Maven tips
Consistent environments
Use the same version of Maven
Use a “standard” Maven installation across the organization
Use a global settings.xml file
Store a copy in SCM
Enforce a minimum Maven version in your projects
Tuesday, 22 June 2010
51. Maven tips
Enforcing consistency with the enforcer plugin
Maven version
JDK version
Snapshots
Plugin versions
OS
...
Tuesday, 22 June 2010
52. Maven tips
Enforce the Maven version
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.0-beta-1</version>
<executions>
<execution>
<id>enforce-maven-version</id>
<goals>
<goal>enforce</goal>
</goals> Minimum Maven version
<configuration>
<rules>
<requireMavenVersion>
<version>2.2.1</version>
</requireMavenVersion>
</rules>
</configuration>
</execution>
</executions>
</plugin>
Tuesday, 22 June 2010
53. Maven tips
Enforce the JDK version
All developers should be using the same JDKs
Incompatible bytecode
Different XML parsers
Different Maven behaviour
Tuesday, 22 June 2010
55. Maven tips
Specify your plugin versions
Undeclared version numbers are bad
Inconsistent builds across different machines
Non-repeatable builds
Plugin changes can break the build
Don’t use SNAPSHOT plugins either
Tuesday, 22 June 2010
56. Maven tips
Specify your plugin versions
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.0-beta-1</version>
<executions>
<execution>
<id>enforce-versions</id>
<goals>
<goal>enforce</goal>
</goals> Plugin versions must be defined
<configuration>
<rules>
<requirePluginVersions/>
</rules>
</configuration>
</execution>
</executions>
</plugin>
Tuesday, 22 June 2010
57. Maven tips
Keep it clean
Keep tabs on your dependencies:
What dependencies are you actually using?
What dependencies do you really need?
Tuesday, 22 June 2010
58. Maven tips
Dependency list
What dependencies are you actually using?
$ mvn dependency:list
[INFO] Scanning for projects... mvn dependency:list
[INFO] Searching repository for plugin with prefix: 'dependency'.
[INFO] ------------------------------------------------------------------------
[INFO] Building babble-core
[INFO] task-segment: [dependency:list]
[INFO] ------------------------------------------------------------------------
[INFO] [dependency:list]
[INFO]
[INFO] The following files have been resolved:
[INFO] antlr:antlr:jar:2.7.6:compile
...
[INFO] commons-collections:commons-collections:jar:2.1.1:compile
[INFO] commons-logging:commons-logging:jar:1.0.4:compile
[INFO] dom4j:dom4j:jar:1.6.1:compile
[INFO] javax.persistence:persistence-api:jar:1.0:compile
[INFO] javax.transaction:jta:jar:1.0.1B:compile
[INFO] junit:junit:jar:4.5:test
[INFO] net.sf.ehcache:ehcache:jar:1.2:compile
[INFO] org.hamcrest:hamcrest-all:jar:1.1:compile
[INFO] org.hibernate:hibernate:jar:3.2.0.ga:compile
[INFO] org.hibernate:hibernate-annotations:jar:3.2.0.ga:compile
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
Tuesday, 22 June 2010
64. Maven tips
Keep it automated
Plan your release strategy
Use a Repository Manager
Automatic snapshot deployments
Automated releases
Tuesday, 22 June 2010
65. Maven tips
Maven best practices for CI builds
Use batch mode (-B)
Always check or snapshot updates (-U)
Use a repository per project
Print test failures to stdout (-Dsurefire.useFile=false)
Tuesday, 22 June 2010
66. Maven tips
Know when to script it
Groovy or Ant scripting is easy in Maven
Call external scripts when appropriate
Tuesday, 22 June 2010
67. Maven tips
Know when to script it
It’s pretty easy in Maven 2...
<project>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.0-rc-5</version>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
println "Hi there I’m compiling ${project.name}"
</source>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
Tuesday, 22 June 2010
68. Maven tips
Know when to script it
It’s even easier in Maven 3...
project {
build {
$execute(id: 'compilation-script', phase: 'compile') {
println "Hi there I’m compiling ${project.name}"
}
$execute(id: 'validation-script', phase: 'validate') {
println "Hi there I’m validating ${project.name}"
}
...
}
}
Tuesday, 22 June 2010