IntroductionThis document contains a mixture of information, advice and examples. It is intended to be a recommendation of best practices. Official guidelines for ASF releases are found elsewhere. The examples below assume that preparation is being made to release version 1.2 of component Foo. Build EnvironmentsCommons components are expected to use Maven to build the project website. Components may choose to use either Maven or Ant to build the actual jar files to be distributed, although it is recommended that Maven be used for this. Both approaches are covered below. This document assumes that the release is being prepared on a linux/unix system, and that steps are being executed from a command-line. The principles are the same, however, for a release prepared on other operating systems or using graphical tools. PreparationSelect a Release ManagerA commons committer (normally one of the development team) should post an email to the development list proposing that a release be made and nominating a release manager. Typically, this should be the proposer. Normal voting procedures apply (lazy consensus). A release plan should also be prepared, in which the tasks remaining to be done before the release are listed. It may be useful to prepare draft release notes before proposing the release, so that others can see what changes are expected for the new release. Preparing the required documents before the release and presenting them for public review (as part of the plan) gives a better chance that any problems can be corrected at an early stage. Many release managers favour development of the plan on the wiki. This format encourages collaboration between developers and reduces the overhead of maintaining the plan. For complex releases, release managers should consider calling a vote on the release plan (by lazy consensus). This may help to coordinate the execution of the plan and to ensure that all developers are aware of the state of the plan. Consider a Release BranchConsider whether a release branch is needed before preparing for the new release. During the preparation for a release, the changes made to the code needs to be tightly controlled. The release manager should take particular care in reviewing all changes. If a release branch is not taken then the trunk code will need to be frozen for critical periods and normal development work suspended for the duration. If a release branch is taken then work will be required to merge any changes back into the trunk. Whether a release branch is needed or not is a judgement call but the more active the component, the more justified a release branch would be. If a release branch is used then the branch should be taken before the release candidate is cut and voted upon. Whether this is done early in the process or later is a judgement call. Taking the branch early allows development to continue on the trunk. However it means that any updates made as part of the preparations for the release will later need to be merged into the trunk code. In general, commons components are small enough (i.e. development rate is low enough) that the branch can be made later in the process (as each release candidate is generated). If a release branch is to be made early, then the following should be done:
cd to the project's base directory in your subversion working copy.
svn update trunk
svn cp trunk branches/foo-1.2-work
svn commit branches/foo-1.2-work
Note that the "svn update" step is necessary in order to ensure that the directory being
copied does not have a mix of files at various revisions; even if the files haven't changed
since the last svn update this can cause "svn log -v" on the new directory to report files as
having been (R)eplaced. Alternatively, use "svn cp URL1 URL2" which will copy files
internally within the repository without using the local working copy: this always ensures
a clean copy is made.
Including details of the branch strategy in the release plan aids coordination. The description below assumes a release is being prepared on the trunk. The process is nearly identical when preparing from a release branch: only the directory in which the work is performed is different. Check CompatibilityConsult the Commons Versioning Guidelines and check that the current level of compatibility is suitable for the proposed version number. Check the current level of compatibility in the code. Tools like Clirr and JDiff are very useful. Both support ant and maven. Check Javadocs And Code Style
Ensure all new classes and methods have Ensure no errors or warnings are reported by the javadoc tool. Check that the javadocs have the correct version number. If the component uses checkstyle or PMD tools, examine the reports and fix all problems. Check Class File FormatUnless appropriate options are set, code compiled with more modern JVMs may fail on older JVMs. The minimum target JVM for the project should be documented. Check that compilation produces code that will execute correctly on that JVM.
If using maven 1, the
The maven 1 build now adds entries to the jar's manifest to show the values
of the
For Maven 2 builds, the Commons parent POM specifies default values for
Check DocumentationCheck that the documentation has been generated correctly. Check that all links are working. Those using maven can use the LinkCheck plugin report to automate this check. (Maven Only) Consider Naming Of Source DistributionBy default, maven uses the same directory name for both binary and source distributions (commons-foo-1.2). Some find it more convenient to have the source distribution unpack to commons-foo-1.2-src. This can be done easily by adding the following line to the component's project.properties file:
maven.dist.src.assembly.dir=${maven.dist.assembly.dir}/src/${maven.final.name}-src
Maven 2 builds use assembly descriptors, which by default live in
<assembly>
...
<baseDirectory>${project.artifactId}-${project.version}-src</baseDirectory>
...
</assembly>
Creating a Release CandidateCheck The Jar ManifestMaven Build Maven will create an appropriate MANIFEST.MF file automatically and, unless specifically configured, any MANIFEST.MF file present within the project will simply be ignored.
The maven build has been modified to include two non standard attributes
in the jar's manifest to indicate the
The entries created in the manifest will look something like the following:
X-Compile-Source-JDK: 1.3
X-Compile-Target-JDK: 1.3
These entries are created by specifying appropriate entries in the
maven.jar.manifest.attributes.list=X-Compile-Source-JDK,X-Compile-Target-JDK
maven.jar.manifest.attribute.X-Compile-Source-JDK=${maven.compile.source}
maven.jar.manifest.attribute.X-Compile-Target-JDK=${maven.compile.target}
Maven 2 builds have these properties automatically inserted if the POM inherits from the Commons parent POM (org.apache.commons:commons-parent:pom:4). All Commons projects using Maven 2 are vigorously encouraged to use the parent POM. Ant Build
If you are using Ant to build the release, then the MANIFEST.MF file at foo/src/conf/MANIFEST.MF
should contain appropriate If your component does not currently include an manifest when building it's jars, one should be added. Here is an example of a typical commons manifest:
Extension-Name: org.apache.commons.foo
Specification-Title: Apache Commons Foo
Specification-Vendor: The Apache Software Foundation
Specification-Version: 1.2
Implementation-Vendor-Id: org.apache
Implementation-Title: org.apache.commons.foo
Implementation-Vendor: The Apache Software Foundation
Implementation-Version: 1.2
Resolve BugsResolve all bugs on that version! They can be resolved by:
Prepare Release NotesEach component should have a file RELEASE-NOTES.txt in the base directory of the component. This file should be included within the distributions available for download. The release notes should contain a description of all the changes since the previous release. Any compatibility issues with the last release (whether binary or semantic) should be highlighted. If there are no compatibilty issues, this too should be mentioned. An introduction to the release may also be given, describing the component and the release in general terms. The release notes should contain the minimum target Java version for the component. The release notes should be a plain text file. Take care to ensure that the format allows easy reading on a wide variety of platforms. Long lines may need to be broken manually to allow them to be easily read easily without word wrap. Different components have their own ways of creating the change log. Here's the most common way:
Get a list of all the commits since the last release by following these steps.
cd {project-base}/tags
svn log --stop-on-copy foo-1.1
# The last revision NNNN reported in the log output is the revision that was
# copied to create the tag. If this is a true tag directory, then of course
# there will only be one revision listed by the log command..
cd ..
svn log -v -rNNNN:HEAD trunk > commits-since-last-release.txt
This will result in a file that contains info on each commit that affected at least one file within the trunk directory since the last release. Note that if a commit affected a group of files of which some were outside the trunk directory, then they will be included with the associated commit message but can be ignored. Using "svn diff" instead of "svn log -v" will result instead in a file that shows the actual diffs for each file instead of the commit messages. This may be more convenient when the commit messages are not sufficiently detailed to be able to build the release notes directly from them. Inspect the list of changes and enter relevant information into the release notes; this may require inspecting the actual changes using "svn diff". Enhancements and new features need to be collated by topic. Bugs fixed should be listed separately together with a short summary of the bug. Please remember to spell check the release notes. Please break lines at 80 characters. IMPORTANT! At the current time, selecting by date in subversion within the ASF repository isn't reliable. The reason is that when converting a date to a revision number, subversion assumes that revision N has an earlier date than revision N+M, and that it can therefore perform a binary search on revision numbers to locate one with the required date. However CVS imports of data that retain the original date information from CVS break this assumption. And unfortunately because revisions are repository-wide information, this affects date-based searches even in directories unrelated to the ones that CVS stuff was imported into. So while dates are reported correctly in "svn log" output, only revision numbers should be used with the -r option. See issue #752 in the subversion issue tracker at tigris.org.
Those using Maven 1 should check that the distribution build adds the release notes
to the binary distributions. It may be necessary to add some scripting to the
<preGoal name="dist:build-bin">
<copy todir="${maven.dist.bin.assembly.dir}">
<fileset file='${basedir}/RELEASE-NOTES.txt'/>
...
</copy>
</preGoal>
<preGoal name="dist:build-src">
<copy todir="${maven.dist.src.assembly.dir}">
<fileset file='${basedir}/RELEASE-NOTES.txt'/>
...
</copy>
</preGoal>
Maven 2 users should make sure to configure this in the assembly descriptors in src/assembly as described above. Test Against Listed DependenciesIf you are using Maven to execute the unit tests associated with the component then there is nothing to do here; Maven will automatically perform the tests using the library versions specified in the project.xml file. If you are using Ant to execute unit tests, then ensure the Ant build.xml file references the same library versions as are listed as dependencies in the project.xml file then execute the unit tests. Ensure a good build.xmlIf using Maven, and a hand-built Ant build.xml file does not exist in the project, then ensure that 'maven ant' (for Maven 1) or 'mvn ant:ant' (for Maven 2) has been run so a usable build.xml file exists. Check the Apache LicenseCheck the Apache Licenses page for current information. Check that each distribution contains a copy of the license. Check that the jar contains a copy of the license in the META-INF directory. Check that the years in the copyright statement in the license in each source file are correct. Developer documentation on how to apply the Apache License can be found in Applying the Apache License, Version 2.0 Some of the important items from the aforementioned documents: Do I have to have a copy of the license in each source file? Only one full copy of the license is needed per distribution. Each source file only needs to contain the boilerplate notice at:
In my current source files I have attribution notices for other works. Do I put this in each source file now? No. The new license allows for a NOTICE file that contains such attribution notices (including the Apache attribution notice). See
for an example that provides all of the notices applicable to the httpd-2.0 distribution. Check NOTICE.txtThe component should contain a NOTICE.txt (next to the LICENSE.txt). If this is not present, it must be created. The basic content (excepting external attributes notes) should be:
This product includes software developed by
The Apache Software Foundation (http://www.apache.org/).
The NOTICE.txt must be distributed along with the LICENSE.txt. Check that the distribution build correct adds this file to the distributions. Those using maven may need to add some scripting to the maven.xml. For example:
<preGoal name="dist:build-bin">
<copy todir="${maven.dist.bin.assembly.dir}">
...
<fileset file='${basedir}/NOTICE.txt'/>
</copy>
</preGoal>
<preGoal name="dist:build-src">
<copy todir="${maven.dist.src.assembly.dir}">
...
<fileset file='${basedir}/NOTICE.txt'/>
</copy>
</preGoal>
Check that the jar contains a copy of the NOTICE.txt in the META-INF directory. Those using maven may need to add NOTICE.txt to the build resources section of the project.xml. For example:
<resources>
<resource>
<directory>${basedir}</directory>
<targetPath>META-INF</targetPath>
<includes>
<include>NOTICE.txt</include>
</includes>
</resource>
...
</resources>
Maven 2 builds have this automatically taken care of by the Commons parent POM. Create the Release CandidateOnce all the preparations agreed in the release plan has been completed, create a Release Candidate. Before taking the tag from which the release candidate will be taken, run the distribution build and double check that everything is still fine.
Modify the build version number to indicate that this build is a release candidate. For example,
Now create the tag for the release candidate. For example (cutting the candidate from the trunk): svn update trunk svn cp trunk tags/foo-1.2-rc1 svn commit tags/foo-1.2-rc1 Note that the "svn update" step is necessary in order to ensure that the directory being copied does not have a mix of files at various revisions; even if the files haven't changed since the last svn update this can cause "svn log -v" on the new directory to report files as having been (R)eplaced. Alternatively, use "svn cp URL1 URL2" which will copy files internally within the repository without using the local working copy; this always ensures a clean copy is made.
Build distributions from that tag (as per full release).
Post the release candidate into the public folder ~/public_html in your home directory
on Create the Release Candidate WebsiteAs well as putting up the user distribution in your home directory on people.apache.org for others to download and verify, the new website should also be published there. For Maven 1 builds, temporarily edit the project.xml file tag <siteDirectory> to point to something like: <siteDirectory>public_html/foo-1.2rc1/site</siteDirectory>then run maven site:generate maven -Dmaven.username=yourapacheid site:deploy Maven 2 builds should temporarily add a site location to the <distributionManagement>:
<distributionManagement>
<id>stagingSite</id>
<url>scp://people.apache.org/home/<apacheuser>/public_html/foo-1.2rc1/site</url>
</distributionManagement>
and then run
mvn site:stage-deploy
To save time entering your username and password, you can edit your
~/.m2/settings.xml to specify them:
<settings>
<servers>
<server>
<id>stagingSite</id>
<username>...</username>
<password>...</password>
</server>
<server>
</servers>
</settings>
The reports generated by maven (Clover, jCoverage, etc) are very useful things to inspect in this website. Note that when verifying this candidate site you need to be careful of absolute URLs; following these will lead to the currently published site, not to the equivalent page on the new site being evaluated. Voting On Release[VOTE] Release Foo 1.2Once the release candidate has been created and uploaded, now it's time to propose the release VOTE.
Post a
Votes from members of the Commons PMC are binding, however votes from other committers, users and
contributors are welcomed.
If the If the vote fails, then fix the problem, update the version number (RC2, RC3, ...) and create a new release candidate (including creating another tag; tags are cheap!). Then call another vote. Creating a perfect release isn't easy, and it is quite common for the first few release candidates to fail, particularly on simple issues like missing license files.
Once a vote is successful, post a
The following people voted on release Foo 1.2:
Bob +1
Sue +1
Sam +0
Sandy +1 (non-binding)
Note that binding the VOTEs recorded need to clearly deliminated in the RESULT.
This may be done by either stating only the binding votes (and indicating that to be the case)
or by adding Final PreparationsUpdate the version number in the project.xml (and possibly build.xml) so that it reflects the release (rather than the release candidate). Clean build and test. Double check that the version number is correct by examining the documentation.
Do Tag the release now: svn cp trunk tags/foo-1.2 You're now ready to cut the release. Remember to update the main website when the candidate has been cut. Things To Look For When Inspecting A Release CandidateThere are a number of common things that releases fail on. API ChangesAccidental non-compatible API changes in a minor release. The jdiff report generated by Maven is very useful in spotting these. Javadoc
project.xml (aka POM)project.xml, used by Maven to generate that site, has some data which may have become stale. Make sure it isn't before releasing. Look at the dependencies report, todo report, and other reports.
Code StyleMany projects enforce coding styles using the CheckStyle or PMD tools. If your project does this, don't forget to check the output and fix any problems. Class File FormatBuilding on a more recent JVM than the code will run on. Java class file format has changed a number of times over the years, and code compiled with a modern JVM may fail to load in an older JVM with the error message "invalid class file format" unless the code is compiled with appropriate options set. If you are using Maven, then ensure that project.properties has maven.compile.target set to the minimum JVM version your binary is intented to support. If you are using Ant, then ensure that the javac task has xml attribute "target" is set to the appropriate JVM version. Maven Build
The maven build has been modified to include two non standard attributes
in the jar's manifest to indicate the
The entries created in the manifest will look something like the following:
X-Compile-Source-JDK: 1.3
X-Compile-Target-JDK: 1.3
These values should be checked to ensure that the release has been built for the appropriate JVM.
If they are not present or no values are specified then the Build-Jdk entry should
be checked to ensure the release has been built with the appropriate JDK.
LicensingThe NOTICE.txt file must be included in both the distribution tars/zips and the included jars. Maven 2 builds default to including this, so no further effort is required for those projects. To make sure that this file is included in maven 1-generated jars, include the following in the build section of your project.xml (or just add the resource defined below to the build resources you already have).
<resources>
<resource>
<directory>${basedir}</directory>
<includes>
<include>NOTICE.txt</include>
</includes>
<targetPath>META-INF</targetPath>
</resource>
</resources>
To make sure that this file is included in the top-level directory of source and binary distribution files (zips and tars), define preGoals for maven's dist goal that copy NOTICE.txt to the source and binary assembly directories that it uses to package the release. To do this, add the snippet below to maven.xml.
<preGoal name="dist:build-bin">
<copy todir="${maven.dist.bin.assembly.dir}">
<fileset file='${basedir}/NOTICE.txt'/>
</copy>
</preGoal>
<preGoal name="dist:build-src">
<copy todir="${maven.dist.src.assembly.dir}">
<fileset file='${basedir}/NOTICE.txt'/>
</copy>
</preGoal>
If you use Maven 2, you should also build source and javadocs jars according to Maven 2 standards. You can use the following antrun-plugin configuration to accomplish this:
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>run</goal>
</goals>
<phase>package</phase>
<configuration>
<tasks>
<copy todir="${project.build.directory}/site/api-release">
<fileset dir="${project.build.directory}/site/apidocs"/>
</copy>
<zip destfile="${project.build.directory}/${artifactId}-${version}-javadoc.jar.new">
<zipfileset src="${project.build.directory}/${artifactId}-${version}-javadoc.jar"/>
<zipfileset dir="." prefix="META-INF">
<include name="LICENSE.txt"/>
<include name="NOTICE.txt"/>
</zipfileset>
</zip>
<move file="${project.build.directory}/${artifactId}-${version}-javadoc.jar.new"
tofile="${project.build.directory}/${artifactId}-${version}-javadoc.jar"/>
<zip destfile="${project.build.directory}/${artifactId}-${version}-sources.jar.new">
<zipfileset src="${project.build.directory}/${artifactId}-${version}-sources.jar"/>
<zipfileset dir="." prefix="META-INF">
<include name="LICENSE.txt"/>
<include name="NOTICE.txt"/>
</zipfileset>
</zip>
<move file="${project.build.directory}/${artifactId}-${version}-sources.jar.new"
tofile="${project.build.directory}/${artifactId}-${version}-sources.jar"/>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
It is a good idea to bind this to a particular profile, such as "release", so that it
doesn't run in the default lifecycle and thus in every build.
FeedbackFeedback - yes please! Comments, critiques and error reports - post them any and all to the dev mailing list at commons.apache.org. Please prefix with [doc]. |