Tuesday, February 28, 2012


Part 2: Continuous Integration (CI) with Jenkins for a application using Play Framework 

In CI Part 1 I have shown you how to configure Play Framework, how to configure the Jenkins Play Plugin. In this post I will show how to post your modules to Nexus server, how to use the repository in the dependencies file, chained dependencies, continuous integration and auto deploy.

Intro

When working on an application in the early stage you will go on and build the requirements. But as the application grows you find necessary to split your application in different components. In time after you build more and more applications you realize that those components can be used across different applications.
To achieve this Play framework provides us with modules. A play module is nothing more than a play application with a small difference that it doesn't have an application.conf file and it is not meant to run on its own, it needs to be included in a containing application. You can read more details about pay modules and how to use them in this fine article: Divide and conquer play framework modules.

Modules and Apps

Usually when working with play you will have a play application and several modules. In the bellow diagram you can see and example. The "MyWebApp" applications depends on three modules:
MyWebApp and its dependencies

To create a play application I'll use the following command:
    > play new MyWebApp

Then I will create my modules:
   > play new-module Module1
    > play new-module Module2
    > play new-module Module3

Then folder structure would look like this:
/myProjects/
    /yoda/Module1-1.0
    /yoda/Module2-2.1
    /yoda/Module3-3.0
    /MyWebApp
  
So this is it. You have a web app ready and a couple of modules, but how to use those modules in your application? Check the next chapter.

Configure dependencies

Each Play application, in conf folder has a file called dependencies.yml used to dependency management for your application. 
For MyWebApp the dependencies.yml should look like this:

# Dependencies

require:
 - play

This is simple, but I still don't have the the modules in dependencies, so I can define repositories. Because my modules are in the local files system I will define a local repository, so the dependencies.yml will look look this:

# Dependencies

require:
 - play
 - yoda -> Module1 1.0
 - yoda -> Module2 2.1
 - yoda -> Module3 3.0
repositories:
 - MyLocalRepo:
    type: local
    artifact: ${application.path}/../[organization]/[module]-[revision]
    contains:
      - yoda -> *

When running the play deps --sync --clearcache command, when resolving the dependencies the dependency resolver will search in folder /myProjects/ for organization yoda/ for modules Module1, revision 1.0, Module2 revision 2.1 and Module3 revision 3.0, as declared in the dependencies.yml require section. 
I have only explained the basic and practical stuff, the play dependency mangement has more details on dependency management.

Post to Nexus

So far so fine, but you need to have the modules in the local file system. Probably you will work with a SCM  like GIT or SVN and you will need to checkout all modules in your file system and create all the folder structure. On top of all you will need to constantly update your code. That is a lot of overhead if you ask me:  Nexus to the rescue.

Before showing you how can you post to Nexus I will explain how the dependencies.yml file should look for a play module.

# Module dependencies file

self Module1 1.0

require:
    - play 1.2.4

The first line is the module name declaration with the module revision number, then we have the required section where I have declared play and play version. The play version is optional but when running the play build-module command, it will ask for play version.

A couple of days ago I have found this snippet. Its a play command that posts a module to a repository. This play command requires the python library poster. After you have installed that python library the command is easy to install and use. Download the nexus.py file in ${play.path}/framework/pym/play/commands/ and that is it, you can use just like any other play command.

How to use Nexus command:

First you need to add in the module application.conf a couple of nexus configurations:

nexus.server.url=http://myNexus.server.org/repo/artifact-group
nexus.server.user=MyUser
nexus.server.password=password

Run the following commands:

play build-module //creates [module]-[version].zip in folder [module]/dist

Next run command:

play nexus-commit [-a] // -a: pushes the file without confirmation

The command will look for the [module]-[version].zip file in dist folder and post the file to nexus at address http://myNexus.server.org/repo/artifact-group/[module]/[version]-SNAPSHOT/[module]-[version]-SNAPSHOT.zip

Configure a chained repository

With that nice nexus play command I have posted my module to a repository and now I can configure the dependencies for MyWebApp to use the nexus to retrieve the module dependencies, so I don't need all my modules in my file system(only the ones I work on) and I don't bother with doing constant updates on modules that I don't work(We will see why in the next chapter when I'll show you how to configure Jenkins).
So the dependencies.yml will look like this now:

# Dependencies

require:
 - play
 -  artifact-group -> Module1 1.0
 -  artifact-group -> Module2 2.1
 -  artifact-group -> Module3 3.0

repositories:
 - MyChainedRepo:
    type: chain
    using: 
      - LocalModules:
          type: local
          artifact: ${application.path}/../[organization]/[module]-[revision]
      - MyNexus:
          type: http
          artifact: http://myNexus.server.org/repo/artifact-group/[module]/[version]-SNAPSHOT/[module]-[version]-SNAPSHOT.zip
    contains:
      - artifact-group -> *

This chain dependency will look for the required modules in the local file system and if are not found then it will download them from nexus.

Continuous Integration

In CI Part 1 I have explained you how to create a Jenkins job for a play application and a play module. I want to post all my modules to nexus using Jenkins. 
The solution is very simple, I will create a Jenkins for each of my modules and besides the standard commands:

play deps --sync --clearcache
play precompile
play auto-test
play build-module

I will add the nexus command to post the module to nexus

play nexus-commit -a

This is it, your latest changes are available on Nexus.

Auto-deploy for MyWebApp:

I want all my changes to be available for testing as soon as possible so you can configure autodeploy  for your web app. You just need to create a Jenkins job, and add this commands:

play deps --sync --clearcache // clear all my cached dependencies and synchronize them
play precompile // If it's a problem in the java classes then the job will fail
play auto-test
play restart --http.port=<port>

When working on a application that uses Play you will notice that all your modifications are available just after you've saved the file you have modified. Well, almost all modifications because after a modification in application.conf, you will need to restart the server.

Conclusions

Well, this is about it related with continuous integration. I hope it helps and I am waiting for feedback.

P.S. I am also working on some code analysis with sonar but because Play Framework doesn't follow the "Java Best Practices" rules, sonar rates are small for the code.

5 comments:

  1. Nice post and Nice blog too. thanks for sharing.

    Javin

    ReplyDelete
  2. Excellent post. Unfortunately, the code snippet at http://www.playframework.org/community/snippets/25 is no longer available. Also, I can't find the nexus.py file anywhere. Could you please point me to that file?

    Thanks,

    Mike

    ReplyDelete
    Replies
    1. If others are looking for the script, it's here: http://stackoverflow.com/a/9325472

      Delete
  3. Hello,
    Thanks for pointing this.
    You can find the code snippet here also:
    https://gist.github.com/1851916

    Regards,
    Ionut

    ReplyDelete