Skip to main content

Build XPages app from Git with Jenkins

Since introduction of Headless designer tech-preview in Domino Designer 9.0.1 many people started to think about build automation. Now is time to try it with Jenkins - popular free build automation server.

I've used Gradle as a build tool, which uses Groovy language. So some G-stuff which all the cool kids use in their projects (I always wonder why so many project names start with G even when they are not in direct relation to Google).

*disclaimer*
Most of these tools I haven't used in production, so I might break some best practices and take other shortcuts.
Also all code is written just as a proof of concept, nothing more.
*end of disclaimer*

Required tools:

  • Windows machine
  • Java JDK
  • GIT
  • Domino Designer 9.0.1
  • Jenkins
  • Git repository - bitbucket in my case

Jenkins setup

I did use Jenkins installation with GIT and Gradle plugin. If you are new to Jenkins, there are many tutorials online how to setup Jenkins. Recent tutorials for Android app builds use Gradle too, so you might want to check them.

If you just want to get it up and running, following steps did it for me:
  1. Install Jenkins
  2. In windows configure Jenkins service, so it can interact with desktop

    This might not be necessary, but egmar had some problems when running as a service in his TeamCity integration and I had problem when my ID file was stored on VMware shared folder mapped as local drive, which couldn't be accessed by services, and without this I didn't know why the build was stuck.
  3.  In Manage Jenkins set-up security (it should ask you to do it using small banner on top). I just used settings that allowed all logged-in users do anything.
    This is probably necessary only if you want to access private Git repositores.
  4. Install plugins - in Manage Jenkins / Manage Plugins / Available plugins just check Gradle and Git plugin and let Jenkins install them
  5. If your GIT and Java installation are not in system PATH, you might need to add whose in Manage Jenkins / Configure System
 Now your  Jenkins should be ready.

Create job to fetch project

I hope you have all your projects in GIT (or any other SCM) repositories, so you can pick any to try. I recommend small ones first, since for example IBM Teamroom template took about 8 minutes to build in my test VM. And this is not good for experiments.

If you just want to follow this article, repository I used is public, so you can get it from Bitbucket too.

  1. Click on New Item and create your first job
  2. Give it a name (ideally without spaces to avoid troubles later with my GradleNotesPlugin)
  3. Select a free-style build and click OK
  4. Configure Source Code Management to fetch you repository

    I used my repository bitbucket.org/pradnik/testing.git and develop branch. It contains one NSF project and one Java project for tests that I want to integrate later.
  5. Optionaly configure build triggers.
    My Jenkins is not publicly available, which is why I couldn't trigger the build from Bitbucket, which is recommended way, so I used just Poll SCM option.
Now you should be ready to start your build and fetch the repository to local file system.

Save it and click Build Now. When done, you should find your repository locally under Jenkins/jobs/ProjectName/workspace/


Build the Notes app with Gradle

You might notice that my project contains files like settings.gradle, build.gradle and gradlew.bat. These are used for Gradle build.

Gradlew.bat together with gradle directory is just a wrapper arround gradle. It allows anyone to run Gradle build on machines even when they don't have Gradle installed, because it takes care of everything.

This is good for our testing, as we can try to launch the build from our on-disk-project without using Jenkins and then get back to Jenkins with configuration that works.

Gradle Notes Build plugin

To keep our builds flexible I decided to create plugin that hides all the calls to Domino Designer. You may as well write it in build.gradle file, but this is better for reuse.
Originally I wanted to write the plugin in Java, but I had problems with task parameters, so I had to switch to Groovy (this is first piece of code I have ever written in Groovy, so don't blame me for any mess, please).

Again, plugin can be build with Gradle. But if you don't want to do it, just download it here as a jar.

Repository
Project for this plugin is publicly available on Bitbucket  https://bitbucket.org/pradnik/gradlenotesplugin

I won't cover details how to build a Gradle plugin here as many tutorials exist. I just want to show main code of task that we will use



All it does is same routine as in batch file form my previous posts. It has 3 parameters
  • filePath - path to NSFproject (actually .project file)
  • fileName - name of NSF file created
  • notesDir - path to Notes directory
 It creates command in syntax from Headless designer wiki runs it and then waits in loop for notes to finish.

You can see that there is currently no error handling and also the time limit can be low (I probably almost hit it with Teamroom). But this will be improved in future releases :-) . Also when you run the build, it doesn't show output from designer, which might be usefull.

If you want to modify it and build it yourself just run gradle uploadArchives and it will save jar in locally created maven repository.

Build structure

In my repository I have currently 2 projects, so I need to structure my build in some way. This is quite common in Gradle world and Gradle can do magic with it. For now we can forget TestingTestTests directory as it is not used.

Our root project Gradle file just tells gradle to build what needed and setting.gradle tells what subproject is should check.

build.gradle
apply plugin: 'java'




dependencies {
    compile gradleApi()
    compile localGroovy()
}

settings.gradle
include ':testingTest'

Main work is done in build.gradle in testingTest directory (which is my NSF project)

build.grade
buildscript {
     dependencies {
        classpath files(gradleNotesPlugin)
    }
}
apply plugin: 'notes-plugin'

import com.pradny.gradle.NotesBuildTask

task createNSF(type: NotesBuildTask) {
    filePath=file('.project')
    fileName=nsfName
  
} 

All lines are important in this case. Gradle, unlike Maven and Ant, doesn't require huge ammount of lines just to get basic stuff done.

  1. buildscript block - tells us where to find our plugin. We will set this as a command line parameter.
  2. apply-plugin - tells Gradle to use our plugin
  3. import - imports class of our Task (might not be necessary if you use full name on next line)
  4. task - runs our task with parameters (filePath is taken from current project location and fileName is passed as a command line parameter)
In real-world scenario you will configure those parameters in more sophisticated manner, but this also shows that Gradle can do simple things in very simple way.

And this is all.
Now just run:

gradlew createNSF -PgradleNotesPlugin=c:/gradleNotesPlugin.jar -PnsfName=blogTest.nsf

note: parametres are passed using -Pname=value syntax

When done, you should have blogTest.nsf in your Notes data directory.

Calling Gradle build from Jenkins

Last piece in our puzzle is hooking Gradle into Jenkins build. So return to Jenkins web page and open configuration of your job.

  1. At bottom click Add build step button and select Invoke Gradle script
  2. Select Use Gradle Wrapper
  3. Add parameters that we used during test launch
  4. As Task use createNSF
  5. Save it
Run your build and enjoy power of automation.

You can experiment with  build triggers and other Jenkins options, but from Notes - Jenkins integration it is all for today. In future I want to and task to move created nsf to server (for now you can use batch file method from my previous posts, run test including Selenium, etc.

------------------------------------------------------------------------------------------------------------------------

Troubleshooting note - sometimes Designer didn't want to start. Currently I don't know if it was caused by calling it from local service and as a user during experiments, or was it something else. After reboot it was fine again.

Comments

Popular posts from this blog

XPages Date Field Issue: Solving the One-Day Jump on Every Save

 A user reported a very strange issue - when a document with a date field is saved, it changes the value one day to the past. With every save. But only for some dates, not all. It turned out to be a mystery that goes deep into XPages and Notes/Java APIs. I've posted a sample on OpenNTF Discord and Serdar tried it on his server - no issue. But he uses the GMT zone and I have CET (Windows set to UTC+1 - Amsterdam, Berlin... to be precise). To cut it short, the issue is caused by daylight saving interpretation between Notes and Java. The date fields (because XPages have no notion of real date-only fields) are stored with 00:00 time component and for some dates the conversion back to Java Date resulted in 23:00 on the previous day. XPages that get the date component as String for the input field, which is then saved back as a previous day during document save. The app is full of date fields and I couldn't add custom logic to every save operation, so I tried to fix it at XPages conv...

HCL Domino 12.0.2, Engage 2022 and HCL Factory tour Milan

 I haven't published my recap after Engage this year and the recent HCL Factory tour in Milan is a great opportunity to write a summary about what's happening in HCL (mostly Domino) space. It's a mix of news about 12.0.2, future directions, and my impressions, so it can be a bit chaotic, but I got the impression that many people see it similarly.  Engage 2022 Engage 2022 was great (as always). I love the atmosphere in Brudges. I visited it once after Engage a few years ago and I was happy to come back. This was also the first time I had the opportunity to speak at Engage, which obviously made it a bit more stressful, but also more fun. Together with Domino Jams, HCL continued conversations with customers and partners about the future of their products at Engage. Many of these ideas were now discussed in greater detail in Milan, some of them were even demoed.  My main takeaways from Engage were: Nomad (web and mobile) are a great addition to Notes family Restyle is a great...

XPages EL/class-loader memory leak (now with solution)

 We have recently experienced OutOfMemory crashes of XPages app server. The server was recently upgraded to 12.0.1FP1, but we were getting some panic crashes in HTTP even before the upgrade (it was 9.0.1FP10). Our hopes were that the upgrade would stabilize the server, but it's not the case. At least now I start to see what's the problem.  update 8.12.2022 There were actually 3 different leaks. I have rewritten the article to be a bit more clear. I also re-run some of the tests on 9.0.1FP10, so I assume the problems are also in earlier versions. Problem 1 The server is hosting over 1000 NSF sharing the same design + some other custom apps. Not all NSFs are used via web as the app still has classic Notes UI in parallel, so it's a bit tricky to estimate the load. By using tell http xsp show modules I usually see around 350 NSFs active. We kept the default application timeout that should provide reasonable application recycling if it's not used continuously.  We started to...