Showing posts with label Gradle. Show all posts
Showing posts with label Gradle. Show all posts
on Monday, 13 October 2014

I'm pleased to announce the arrival of the Gradle Weblogic Plugin. Its been a while in the making, but I've finally got a stable version out with the 6 primary tasks. They are :
  • wlDeploy - Deploys or redeploys an application or module.
  • wlUndeploy - Stops the deployment unit and removes staged files from target servers.'
  • wlCancel - Attempt to cancel a running deployment task.
  • wlRedeploy - Redeploys a running application or part of a running application.
  • wlStart - Makes a stopped (inactive) application available to clients on target servers.
  • wlStop - Makes an application inactive and unavailable administration and client requests.

The latest version is currently:



You can find the source code and README at the following address:
Github - Gradle Weblogic Plugin

and the binaries are hosted at:
Bintray - Gradle Weblogic Plugin


on Friday, 19 September 2014

Problem

I have an archive compiled with properties pre-defined within, but they need to change as I promote my build through the different stages of the SDLC. One example could be with a connection.xml that has URLs pointing to different databases.

Gradle already offers some great solutions such as keyword expansion and ant token replace, but both methods require the token to be in a predefined format. The expand() solution looks very similar to groovy string interpolation and looks for ${..}, whereas ant replace tokens looks for @..@.

Solution

The solution here was to pass a closure to filter which is called for every line of the filtered file. The closure performs some simple processing using the MapFilter() class and its MapReplace() method. An example is shown below:


There's more ...

You may have noticed that this example also includes a lot of meta-programming. This was just my first dip into the world of meta-programming. In this example the metaclass simply intercepts every new call to map filter and returns the original map filter instance.
on Monday, 19 May 2014
myFile.toURL() deprecated The fix to this is quite simple:
on Wednesday, 23 April 2014



I have recently been working on writing a Gradle plugin for the popular SoapUI functional testing tool. To make things easier I decided to port the maven plugin rather than reinvent the wheel. I've been working predominantly in IntelliJ, and for some reason it didn't flag any dependency failures.

I felt the time had come to add the project to CI and was surprised to see the build failed. I have been employing test driven development so had expected test failures but not dependency failures.

To resolve the issue I first had to establish what was causing the problem; running the 'gradlew dependency' task helped nicely! The output below is quite clear:



Simply changing the dependency to a later version fixed my issue.
on Tuesday, 28 January 2014
This snippet will produce a zip archive that includes the artifacts of the subprojects.
on Monday, 30 December 2013
The short answer is everything!

When I talk about build process metrics I'm not talking about code coverage, or lines of code - there's a plethora of tools that will extract that information for you such as cobertura, findbugs etc. What I mean is information about the build process itself.

Here's just an example of a few metrics I find useful:

Current time is Dec 28, 2013 10:41:38 AM
System.getProperty('os.name') == 'Windows 7'
System.getProperty('os.version') == '6.1'
System.getProperty('os.arch') == 'amd64'
System.getProperty('java.version') == '1.7.0_45'
System.getProperty('java.vendor') == 'Oracle Corporation'
System.getProperty('sun.arch.data.model') == '64'

You might be asking why this is important, or why bother when you're using a build automation tool such as Jenkins. Unfortunately for me not every project is fully automated. It should be, but we're not quite there yet. I like to use Gradle as it provides the tools to extract a lot of information about your build process.  As this is performed at a lower level than CI this means for those odd tasks that are run manually we don't miss out on that juicy data. Data is valuable, just ask Google.....

So, what do we hope to find? 

The interesting thing about data is you don't really know what's there until you start digging. One such example presented itself recently ... at my company we split the task of releasing software into 2 stages. First, we have the volatile build phase, followed by the stable release phase which is performed by a different team. During one projects build phase I was repeatedly running deployments of our web application in approximately 3 minutes to our QA environments. However, when the release manager was deploying into production it was taking 45 minutes..... what the deuce??

Before even looking at the data I knew we both used the same work issued laptop, with the same version of Java, and the Gradle wrapper ensured we were using the same version of the build tool. So, what was causing this massive increase in deployment time? Well, I later found out from the data that the release manager had failed to mention he was running the deployment from his bedroom across a VPN ..... Bingo! the increased deployment time was due to the network, and was easy to fix. (we quickly put this project in Jenkins with a manual start).

The moral of the story is to collect all the information you can. Gradle is an extremely powerful DSL, and its groovy support means your options for pushing and processing the data are endless.


on Wednesday, 27 November 2013

Problem

With Gradle the project name is derived from the project's directory name. However, in Jenkins the project's directory name is derived from the Jenkins job name.
There are a few steps in the build lifecycle that use the project.name, such as the jar task. If our Jenkins job was "myProject_build" this would result in a jar named myProject_build-1.0.jar.

Solution


With a single project the solution is to add a settings.gradle and set the (root) project name there (rootProject.name = "...").

With a multi-project build you may wish to override the sub-project name:


on Tuesday, 26 November 2013


In this recipe we will see how easy it is to call the Weblogic tool "wldeploy" from Gradle.

Getting ready


The deployment depends on having a copy of the wlfullclient.jar available to the build scripts. There are plenty of tutorials online on how to create this, so I wont cover that here.

How to do it ...

  • Create our build file.

  • Create our Weblogic instance configurations.


How it works ...

I wont get into the configuration elements of this project. Its covered in great detail here. The important thing to take from this is we are tokenizing our build scripts making them reusable.

The deployToWLS task is where the magic happens. Here we define the ant task using the name, classname and classpath. Next we specify a directory with our deployables; I've used the "build/libs" directory as that's where my war files are packaged to. Next, through the powers of the eachFile closure we get the filename and trim the extension, we then deploy each file in that directory.


on Thursday, 10 October 2013
I wanted to use the Gradle Wrapper, but wanted to keep the download internal to avoid having to expose proxy setting in the gradlew scripts.

The change was quite simple. We hosted the files on a staging server (Windows) and simply changed the gradle-wrapper.properties to the following:


on Wednesday, 2 October 2013
I've been working quite closely with one of the testers who's written a test suite using Selenium. He had initially wrote a single gradle task for each browser.

As i hope you can see its a little clunky:


So, I set out to make this more flexible and minimize the amount of code in the build file. Using rules which are provided by the Gradle API I was able to write the following task:


Now all thats required is "gradle intTestChrome" or "gradle intTestFirefox".... perfect!
on Tuesday, 1 October 2013

This simple Gist adds 2 additional output listeners; Standard Out and Standard Error and pipes their output to a build log.



on Wednesday, 25 September 2013
There's small changes you make when developing that you often disregard as too simple to matter. One such example is shown below.

Dates should be ordered: YEAR, MONTH, DAY. (e.g. YYYYMMDD, YYMMDD, YYYYMM). Time should be ordered: HOUR, MINUTES, SECONDS (HHMMSS). The reason for this is that files will always be sorted in correct chronological order.

As a build manager I use this most in my Gradle scripts for ordering the build output logs.
on Tuesday, 28 May 2013

Gradle strikes again:


Yes, it really was that easy!

The Oracle database
This post assumes that you have an Oracle database available. I used an Oracle 10g XE instance running on localhost to develop this post. XE is free to download and is sufficient for development purposes.

I had a SCOTT schema with the password "oracle" in the database and also installed the utPLSQL schema, which is a necessary step to following this example. To replicate what I done I recommend downloading the Oracle Developer Days VM.

NOTE: If you install the utPLSQL schema into an Oracle 10g XE database, make sure that you have granted access on UTL_FILE to public as explained here (remember to connect as sysdba when doing this otherwise it won’t work).

The structure I used for this example is:

.
|-build
|---build.gradle
|---ut_run.sql
|-src
|---main
|-----sql
|-------run.sql
|---test
|-----sql
|-------run.sql
on Monday, 13 May 2013
I recently seen this blog post and thought it would be really cool if I could integrate git flow into my build scripts. Whats great about this is that because this is a java library it was extremely painless to integrate.

With a little effort this could easily be converted into a plugin for Gradle, but here's my example:


This is only a snippet, so not all of the library is shown, but it works very well as a proof of concept.

on Thursday, 2 May 2013

When creating a release package its nice to maintain a copy of all the metadata. I like to do this using the power of Groovy from within my Gradle build scripts.


 import groovy.xml.MarkupBuilder  
 task xmlGen << {  
      def tag = "git describe --abbrev=0 --tags".execute().text  
      def sha = "git rev-parse HEAD".execute().text  
      def fw = new FileWriter("build_info.xml" )  
      def xml = new groovy.xml.MarkupBuilder(fw)  
      xml.build(id:tag){  
           ProjectName("ORCA")  
           SHA1(sha)  
           Date(new Date())  
           Components("component1, component2, component3")  
      }  
 }  

And the output is:


 <build id="v1.3.0">  
  <ProjectName>MyProject</ProjectName>   
  <SHA1>1f661e69797dc23281d2955d6ca2dda3cdd81dc0</SHA1>   
  <Date>Thu May 02 16:14:33 BST 2013</Date>   
  <Components>component1, component2, component3</Components>   
 </build>  

on Friday, 5 April 2013

To ensure no plain text passwords are stored on the servers the following piece of code can be used encrypt and decrypt passwords.


 import java.security.*  
 import javax.crypto.*  
 import javax.crypto.spec.*  
 class DESCodec {  
   static encode = { String target ->  
     def cipher = getCipher(Cipher.ENCRYPT_MODE)  
     return cipher.doFinal(target.bytes).encodeBase64()  
   }  
   static decode = { String target ->  
     def cipher = getCipher(Cipher.DECRYPT_MODE)  
     return new String(cipher.doFinal(target.decodeBase64()))  
   }  
   private static getCipher(mode) {  
     def keySpec = new DESKeySpec(getPassword())  
     def cipher = Cipher.getInstance("DES")  
     def keyFactory = SecretKeyFactory.getInstance("DES")  
     cipher.init(mode, keyFactory.generateSecret(keySpec))  
     return cipher  
   }  
   private static getPassword() { "secret12".getBytes("UTF-8") }  
 }  

Things to note in this script are:

  • encode - this method takes a string, encodes the string against a key and returns an encoded string
  • decode - this method takes the encoded string and key and decodes to the plain text password
  • key - this is the string that is set to "secret12" in the code above. This should be changed and owned
  • on a per environment basis. To further improve ease of use this should be parameterised.

Usage:



 task setPassword << {   
   println new DESCodec().encode("password")  
 }  
 task getPassword << {   
   println new DESCodec().decode("VGf1XPEzkT7g6D2EhjMlrg==")  
 }  

How you use this in your gradle script is entirely up to you. One suggestion I have would be to pass in the
Key as a parameter to your script.