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