Introduction

Moves serves two primary functions: Creating releases and deploying those releases to Containers (a.k.a App Servers). This section discusses the release process in detail.

A typical MIT application (for example a web app) will contain

  • code specific to that application
  • MIT developed components
  • third party components (for example the spring framework)

We will call these MIT apps, MIT components and 3rd party components respectively.

Prerequisites

Subversion set-up

Each MIT app and MIT component exists as a maven project. That project is housed in a subversion repository, using the subversion "trunk, tags, branches" pattern. That is, for every MIT application and every MIT component, there exists a subversion URL which contains the sub-folders "trunk", "tags" and "branches". In general, development occurs in the "trunk" folder, but on rare occasions development can occur in a subfolder of the "branches" subfolder. (See http://svnbook.red-bean.com/en/1.2/svn.branchmerge.maint.html for an overview of the "trunk, tags, branches" pattern.

Maven set-up

Within trunk, there will be a file called pom.xml. All builds are built by Maven. The pom.xml tells maven how to build an app/component, and which components that app/component depends upon. While Maven is primarily designed for building java apps and components, plugins exist whereby it can be used to package and assemble other types of components/application. A complete overview of Maven is beyond the scope of this document. However, for those new to maven, the following is a great place to begin learning http://www.sonatype.com/books/maven-book/.

The pom.xml file contains an element called version. In the subversion trunk *the version will always contain the -SNAPSHOT suffix.

Declaring dependencies on 3rd Party components - the easy way

For many/most mainstream open source components (for example the Spring Framework), source and binary code is automatically accessible to your project simply by declaring a dependency. For example, to include the Spring framework, we would add the following dependency

Spring-web Framework Dependency
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>3.0.3.RELEASE</version>
</dependency>

Since spring-web version 3.0.3 and all of it's dependencies exist in the standard maven repositories, then we're done.

Declaring dependencies on 3rd Party components which have their own repositories

It is possible to add repositories directly to your pom.xml. However, it is preferable to have a MIT Maven Repository Admin mirror the 3rd party repository. This will make the component available to all projects, while also decreasing network loads. (For the SAIS teams, the mirror configured in the MIT Maven Repository should be visible to the "saisGroupRepo" repository. See your network admin for details.) Once this is done, add your dependency to pom.xml as described in "Declaring dependencies on 3rd Party components - the easy way"..

Declaring dependencies on 3rd Party components which do not have a maven distribution available.

Sometimes the 3rd party components we wish to use will not exist in the standard Maven repositories. This may be because they are closed source, or because the vendor has their own repository. In this case, you will potentially need to perform the following tasks

  1. make up a group id (usually com.whateverthevendornameis) and artifactid (e.g my3rdpartycomponent)
  2. rename the jar file to [artifactid]-[version].jar
  3. create a jar file containing the source files, if available, and call it [artifactid]-[version]-sources.jar. This step is optional but STRONGLY recommended.
  4. create a pom file (pom.xml) with the correct groupId and artifactId. This file should also contain any dependencies to jar files used by the component. If these components are in the standard maven repositories, use those dependencies. Otherwise repeat this process for each dependent component.
  5. provide your MIT Maven Repository Admin with the pom.xml, [artifactid]-[version].jar and optional [artifactid]-[version]-sources.jar and request they add that to the appropriate MIT Maven Repository for your group.

Once this is done, add your dependency to pom.xml as described in "Declaring dependencies on 3rd Party components - the easy way".

Declaring dependencies on MIT components

In our Continuous Integration environment, we desire to always (or nearly always!) build apps that depend on the latest version of a component. This ensures that we know as soon as possible when a change is made to a component that breaks a dependency from another app/component. Thus we want our "trunk" builds to always point to the latest available version of an MIT component. That will be the trunk build of the component itself. To accomplish this we do two things.

  1. We specify a DEPENDENCY RANGE instead of a specific version
  2. We configure the component to use snapshot builds (if available) when building an app/component that includes that component

Below is an example of an app which specifies a dependency range for the MIT component edu.mit.ist.es.common:sais-common

Range dependency example
<dependency>
    <groupId>edu.mit.ist.es.common</groupId>
    <artifactId>sais-common</artifactId>
    <version>[0.0.0,999.999.999)</version>
</dependency>

Below is an excerpt from the sais-common pom.xml file which shos how to configure sais-common, such that applications which depend on sais-common will use snapshot builds when resolving a dependency range.

sais-common pom.xml exerpt
...
<build>
    <plugins>
        <plugin>
            <!-- because this component is a plugin, and because dev and ci
            builds always point to the LATEST SNAPSHOT, we will configure
            the maven-install-plugin to consider snapshot builds to the 
            local repo to be a release.
            -->
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-install-plugin</artifactId>
            <version>2.3.1</version>
            <configuration>
                <updateReleaseInfo>true</updateReleaseInfo>
            </configuration>
        </plugin>
        ...
    </plugins>
    ...
</build>
...

Adding your project to the Projects Directory

The Release Process

When you use Moves to perform a release of a component/application, the following steps happens

  1. Moves will check out the trunk source of the component/application from subversion
  2. Moves will parse the pom.xml to see if any dependency ranges are found. Moves will assume these dependency ranges are themselves MIT components.
  3. For each component found, moves will check out that component and recursively perform this set of steps.
  4. Moves will present you with a build page. For each component you will be given the option of performing a new build, or using an existing release
  5. Moves will take your input and use that to create a branch. The project version in the branch will be the same as the version in trunk, with the "-SNAPSHOT" suffix removed. Thus if your project is at version 2.1.5-SNAPSHOT, the branch version will be 2.1.5.
  6. Moves will increment the version in trunk. In our example above, the project version in trunk will become 2.1.6-SNAPSHOT.
  7. Moves will replace the dependency ranges in the branch with the versions that were calculated based on your selections. These can be previously released versions, or if you elected to release a new component, it will be the version of the component which will be released as part of this build.
  8. Moves will build each component for which you selected to build a new release
  9. Moves will build your top level component/application
  10. Moves will release each component/application that has been built to the MIT Maven repository
  11. Moves will commit the trunk changes (i.e. the incremented SNAPSHOT version) for each component/application that has been built
  12. Moves will commit the branch changes for each released component (i.e the release version, and resolved dependency ranges) to the [subversion url]/tags/releases/[version] tag
  13. Moves will copy the working branches for each released component to the [component's subversion url]/tags/releases/[version] tag
  14. Moves will remove the working branches for each released component

Thus at the end of the process, the following changes will have occurred:

  1. Each released component will exist in the MIT Maven repository
  2. A tag containing the source code for each released component will exist in [component's subversion url]/tags/releases/[version] tag. The pom.xml file's version element in that tag will have the release version, and any dependency ranges in that tag will have been replaced with the version of that component that was used in the release
  3. For each released component, the [component's subversion url]/trunk/pom.xml file's version element will have been incremented.

Creating a branch

Moves provides a facility for creating branches. If you need to branch a project, and if that project might have a release associated with it, then you should use Moves to create a branch.

When should I create a branch?

The answer to this is almost never. Branches add complexity, and changes made to a branch must be applied to the trunk. The process is subject to human error.

Valid reasons for creating a branch include

  1. Emergency bug fixes. Suppose you have example-web-app version 1.2.3 on production, and trunk is not in a releasable state. A critical bug needs fixing and you cannot wait until the next scheduled release. In this case you need to
    1. Branch the release on production (1.2.3).
    2. Branch any dependent components that must have code changes
    3. Fix the bugs
    4. Release the branch release
    5. Merge the fix back into trunk
  2. Concurrent development. Suppose you have a major change in example-web-app that requires a 6 month developer effort. Meanwhile, the business requires minor enhancements to be released every month. In this case you should create the branch, and apply the minor fixes and releases to that branch.
    1. Merge all branch changes back into trunk frequently.
    2. When the major release is ready, the branch should no longer be worked on.

Branch prerequisites

  1. A branch must be created from a release tag. Thus, if you want to create a branch from trunk you should
    1. make sure trunk builds
    2. create a release of trunk (it's ok to do nothing with that release... moves just needs the tag for a branch point)
  2. For each dependent component you must decide if you want to create a branch of that component.
    1. If the dependent component does not need to change (ie you are only changing code in your application), there is nothing to do.
    2. If you wish to use the trunk version of the dependent component, then change the version of the dependency in your application back to a range (ie <version>[0.0.0,999.999.999)</version>).
    3. If you wish to use a branch version of the dependent component, then complete these steps for the dependent component, and set up a BRANCH RANGE. (See "Branching Example" below for how to create a dependent branch range).

Branching example.

Let's suppose we have application example-web-app which has version 2.5.3 deployed to production. It depends on edu.mit.ist.es.common:sais-common:3.1.5 (the sais-common component version 3.1.5). Let's suppose it also depends on edu.mit.ist.es.components:example-component:1.2.3 (example-component version 1.2.3). A bug is found in production, and the trunk is not in a releasable state (perhaps we have a bunch of untested changes). We need a release as soon as possible. It is found that the bug fix requires changes to sais-common and example-web-app, but not to example-component.

(In trunk, example-web-app is at version 2.6.0-SNAPSHOT, sais-common is at 4.1.2-SNAPSHOT and example-component is at 1.2.4-SNAPSHOT).

The following will need to occur.

  1. Use moves to create a branch of example-web-app version 2.5.3. (This will become version 2.5.3b1.0-SNAPSHOT)
  2. Use moves to create a branch of sais-common component version 3.1.5. (This will become version 3.1.5b1.0-SNAPSHOT)
  3. Check out the example-web-app branch code (from [example-web-app-svn-url]/branches/releases/2.5.3b1).
  4. Check out the sais-common branch code (from [sais-common-svn-url]/branches/releases/3.1.5b1).
  5. edit the sais-common dependency in example-web-app's pom.xml, so that
    Range dependency example
    From:
    <dependency>
        <groupId>edu.mit.ist.es.common</groupId>
        <artifactId>sais-common</artifactId>
        <version>3.1.5</version>
    </dependency>
    To:
    <dependency>
        <groupId>edu.mit.ist.es.common</groupId>
        <artifactId>sais-common</artifactId>
        <version>[3.1.5b1.0, 3.1.5b1.999)</version>
    </dependency>
    

Your project should now build and deploy. Moreover, Moves will allow you to select a branch build after you commit all of your changes.

Once the branch has been created, the release process is much like the trunk release process. However, instead of the versions incrementing from, say 1.2.3-SNAPSHOT to 1.2.4-SNAPSHOT, they will increment from, say 1.2.3b1.0-SNAPSHOT to 1.2.3b1.1-SNAPSHOT. This allows you to perform multiple releases on the branch, until the branch cycle is completed. The corresponding released versions will be 1.2.3b1.1, 1.2.3b1.2, 1.2.3b1.3 etc.

Screenshots

TODO

  • No labels