14 February 2009

Starting a project with Maven 2, Subversion, Hudson, and Restlet



First, install maven 2 and subversion as appropriate for your platform. Navigate to where you want to work on this tutorial, then run a command like

mvn archetype:create -DgroupId=com.mycompany.app -DartifactId=superapp

That might take a few minutes. After running it, you will have a directory called superapp in your current directory.

cd superapp

You can verify everything worked by running the following commands:

mvn package

If you lack a jdk, the first command will say BUILD FAILURE and explain where it looked. In that case, install a jdk. This command might also take a little while, since it must download additional jars.

Then,

java -cp target/superapp-1.0-SNAPSHOT.jar com.mycompany.app.App

Will print "Hello World!"

So far this has all been duplicating the basic maven tutorial.

Type mvn clean to get rid of the compiled files, since we'll be putting this in version control.

Now we're going to take this simple app, integrate it into version control and a continuous integration system, and give it some small functionality.

First, we'll add it to a subversion repository. If you don't already have one handy to use, you'll want to create one with the appropriate structure. Move back to your working directory (that is, below the superapp directory), then type:

svnadmin create superapp-repository


mkdir superapp-structure
mv superapp superapp-structure/trunk
mkdir superapp-structure/branches
mkdir superapp-structure/tags
svn import superapp-structure file:///full/path/to/superapp-repository/superapp -m "First import."

Then, to get a copy you can work with, run

svn co file:///full/path/to/superapp-repository/superapp/trunk superapp

If you want, cd into that directory and verify you can still package and run the app.

Now we're going to start continuous integration. Download the latest release at hudson.dev.java.net

It will be a war file -- make sure you don't unpack it.

Open a new terminal and move to wherever you downloaded it, then run

java -jar hudson.war

That will start up a instance of hudson we can use for this tutorial, available at http://localhost:8080/

When you go there, you should see the Hudson dashboard, which says Welcome to Hudson! in the middle.

Click on New Job, on the left.

Name the job "Superapp Build" and choose "Build a maven2 project". This job will be just for building superapp. Under Source Code Management, choose Subversion, then put file:///full/path/to/superapp-repository/superapp/trunk for the Repository URL. Leave everything else at the defaults.

Leave Build whenever a SNAPSHOT dependency is built checked, and also check Poll SCM. For Schedule, go ahead and put "* * * * *" (without quotation marks). That will poll every minute.

Next to maven version, click system configuration link. Down where it says Maven you'll need to Add a Maven installation. I called it "default maven" and gave it the appropriate maven home. On my system, that was /usr/share/maven2 . You'll know you have the location right if, when your focus leaves the MAVEN_HOME field on the hudson config page, it doesn't complain.

After doing that, go back to the Superapp Build config page, put 'package' (without quotation marks) for Goals and option, then save. At this point, Hudson should build the project for the first time. You'll be able to see that the build has succeeded on the "Superapp Build" page. Go ahead and click on the link to the build. There will also automatically be a test report generated, which you can peruse by clicking on Test Result on the left.

Now that we have basic continuous integration going, lets go back to our superapp directory with the code checked out from the repository. We're going to edit that.

Since I'm going to edit in eclipse, I first need to turn it into an eclipse project, so I run


mvn eclipse:eclipse
svn add .classpath .project
svn commit -m "Added eclipse support"


Then check out the project in eclipse to edit. You could also just edit the project in place. If you decide to edit in eclipse, make sure you install the Maven 2 eclipse plugin.

We're going to make this a Restlet application, so first we're going to add a dependency on Restlet. Go ahead and add this section to the <repositories> element of the pom.xml (you can also do this with m2eclipse):

<repository>
<id>maven-restlet</id>
<name>Public online Restlet repository</name>
<url>http://maven.restlet.org</url>
</repository>

Then add the following chunk to the <dependencies> element:


<dependency>
<groupid>org.restlet</groupid>
<artifactid>org.restlet</artifactid>
<version>1.1.2</version>
</dependency>
<dependency>
<groupid>com.noelios.restlet</groupid>
<artifactid>com.noelios.restlet</artifactid>
<version>1.1.2</version>
</dependency>
<dependency>
<groupid>com.noelios.restlet</groupid>
<artifactid>com.noelios.restlet.ext.simple</artifactid>
<version>1.1.2</version>
</dependency>

Now, in the com.mycompany.app package, go ahead and create the HelloWorldResource and FirstStepsApplication classes as outlined at restlet.org

Then, replace the main method in the App class with the one from the "Run as a standalone Java application" section.

You can verify this worked by running the new main method and visiting http://localhost:8182 , where you should see your hello world message.

Now, add and commit your changes. This will trigger a hudson build, of course. If the build fails, you probably need to add the following section just inside the <project> element of your pom.xml, telling maven to use java 1.5:


<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>

Now, lets add a few tests. But first, go ahead and change the version of junit in the pom.xml to 4.5 . Then add a new junit test case in the tests source folder and appropriate package called HelloWorldResourceTest.

Time to start testing. Fill out our test case like so:


public class HelloWorldResourceTest {

private HelloWorldResource resource;

@Before
public void createResource() {
Request request = new Request();
this.resource = new HelloWorldResource(new Context(), request, new Response(request));
}

@Test
public void testConstructor() {
assertTrue(false);
}

@Test
public void testRepresent() {
assertTrue(false);
}
}

Check those changes in, and see how hudson responds. Notice that the old test is still passing, even though it isn't testing anything. You might want to remove that old test case for now, especially as we've moved to junit 4.5 .

Lets make those tests pass.

First, the constructor test:

@Test
public void testConstructor() {
assertEquals(1, this.resource.getVariants().size());
assertEquals(MediaType.TEXT_PLAIN, this.resource.getVariants().get(0).getMediaType());
}

Then, the represent test:

@Test
public void testRepresent() throws IOException {
Representation representation = this.resource.represent(new Variant(MediaType.TEXT_PLAIN));
assertEquals("Hello World!", representation.getText());
}

Take a look at how that is reflected in Hudson.

At this point it would be possible to make successful builds be deployed to a development environment, but that's a task for another time.

No comments:

Post a Comment