Grails on Circle CI Basics
In this guide, we will learn how to setup Circle CI to build and test a Grails application.
Authors: Nirav Assar, Sergio del Amo
Grails Version: 4.0.1
1 Grails Training
Grails Training - Developed and delivered by the folks who created and actively maintain the Grails framework!.
2 Getting Started
Every software project needs Continuous Integration (CI).
Continuous integration is a software development strategy that increases the speed of development while ensuring the quality of the code. Developers continually commit small increments of code (at least daily, or even several times a day), which is then automatically built and tested before it is merged with the shared repository.
Circle CI is a continuous integration platform seamlessly integrated with GitHub. It supports your development process by automatically building, testing and deploying code changes.
In this guide you are going to create a Grails application on GitHub and use Circle CI to build and test your code. This guide assumes you are familiar with Git and GitHub. It also assumes that you already have a GitHub account. The guide will cover only build and test an Grails application with Circle CI. However, Circle CI has the ability to deploy, send notifications, and highly customize CI jobs.
Circle has one free plan for any project, and has progressively more costly plans for higher needs. Thus, it is really convenient to build and test an open source Grails Plugin which you may wish to contribute to the community.
2.1 What you will need
To complete this guide, you will need the following:
-
Some time on your hands
-
A decent text editor or IDE
-
JDK 1.8 or greater installed with
JAVA_HOME
configured appropriately
2.2 How to complete the guide
To get started do the following:
-
Download and unzip the source
or
-
Clone the Git repository:
git clone https://github.com/grails-guides/grails-on-circleci-basics.git
The Grails guides repositories contain two folders:
-
initial
Initial project. Often a simple Grails app with some additional code to give you a head-start. -
complete
A completed example. It is the result of working through the steps presented by the guide and applying those changes to theinitial
folder.
To complete the guide, go to the initial
folder
-
cd
intograils-guides/grails-on-circleci-basics/initial
and follow the instructions in the next sections.
You can go right to the completed example if you cd into grails-guides/grails-on-circleci-basics/complete
|
3 Writing the Application
The initial
project contains a Grails Application created with the web
profile.
You `build.gradle`file should look like:
grailsVersion=4.0.1
gormVersion=7.0.2.RELEASE
assetPipelineVersion=3.0.11
webdriverBinariesVersion=1.4
seleniumVersion=3.141.59
chromeDriverVersion=78.0.3904.105
geckodriverVersion=0.26.0
buildscript {
...
dependencies {
...
classpath "gradle.plugin.com.github.erdi.webdriver-binaries:webdriver-binaries-gradle-plugin:2.1" (1)
}
}
...
...
...
apply plugin:"com.github.erdi.webdriver-binaries" (1)
...
...
...
dependencies {
...
...
testCompile "org.grails.plugins:geb" (2)
testCompile "org.seleniumhq.selenium:htmlunit-driver:2.35.1"
testRuntime 'net.sourceforge.htmlunit:htmlunit:2.35.0'
testRuntime "org.seleniumhq.selenium:selenium-chrome-driver:$seleniumVersion" (3)
testRuntime "org.seleniumhq.selenium:selenium-firefox-driver:$seleniumVersion" (4)
testCompile "org.seleniumhq.selenium:selenium-remote-driver:$seleniumVersion" (5)
testCompile "org.seleniumhq.selenium:selenium-api:$seleniumVersion" (5)
testCompile "org.seleniumhq.selenium:selenium-support:$seleniumVersion" (5)
}
webdriverBinaries {
chromedriver "${chromeDriverVersion}" (6)
geckodriver "${geckodriverVersion}" (7)
}
1 | Apply the Webdriver binaries Gradle Plugin. A Gradle plugin that downloads WebDriver binaries specific to the operating system the build runs on. The plugin also as configures various parts of the build to use the downloaded binaries. |
2 | Include a testCompile dependency to the Geb Grails plugin which has a transitive dependency to geb-spock . |
3 | Adds the necessary selenium dependencies to use Chrome |
4 | Adds the necessary selenium dependencies to use Firefox |
5 | Geb is built on top of WebDriver. You need these testCompile dependencies. |
6 | Configures the ChromeDriver version to be used by the Webdriver binaries Gradle Plugin. |
7 | Configures the GeckoDriver version (e.g. Firefox) to be used by the Webdriver binaries Gradle Plugin. |
3.1 Unit Test
The initial
application contains a unit test which verifies the default UrlMapping for /
.
package example.grails
import grails.testing.web.UrlMappingsUnitTest
import spock.lang.Specification
class UrlMappingsSpec extends Specification implements UrlMappingsUnitTest<UrlMappings> {
void "test forward mappings"() {
expect:
verifyForwardUrlMapping("/", view: 'index')
}
}
3.2 Integration Test
The initial
application contains a functional test which uses Geb to verify that the Home Page
displays the sentence Welcome to Grails
.
package example.grails
import geb.spock.GebSpec
import grails.testing.mixin.integration.Integration
@Integration
class DefaultHomePageSpec extends GebSpec {
def 'verifies there is _<h1>_ header with the text _Welcome to Grails_ when we visit the home page.'() {
when:
go '/'
then:
$('h1').text() == 'Welcome to Grails'
}
}
1 | Ignore test unless system property geb.env is present. |
3.3 Verbose Test Output
When running the tests in a continuous integration server is useful to have a more verbose output.
Modify build.gradle
:
tasks.withType(Test) {
testLogging {
events "passed", "skipped", "failed"
exceptionFormat 'full'
}
}
When we execute the tests we will see output such as:
$ ./gradlew test
....
...
example.grails.UrlMappingsSpec > test forward mappings PASSED
3.4 Run Tests
Verify everything executes correctly up to this point.
./gradlew -Dgeb.env=chromeHeadless check
.
To run the tests:
./grailsw
grails> test-app
grails> open test-report
or
./gradlew check
open build/reports/tests/index.html
4 Create GitHub Repo
We will need to place the Grails application on GitHub so that Circle CI can access it.
Proceed to GitHub and follow the directions to create a new repository.
When creating the repo, make it public. Option not to create a LICENSE and .gitignore. We are importing an existing code base so we want to avoid conflicts. |
Import the code into the repo on GitHub by executing the following commands:
> git init
> git add .
> git commit -m "first commit"
> git remote add origin <Your repo URL>
> git push -u origin master
5 Integrate Circle CI
Circle CI integrates directly with your GitHub account. Follow the directions on the Circle CI website for creating a repo to integrate Circle CI
In short you will need to:
-
Use your GitHub account to sign into Circle CI.
-
Give permission to Circle to access your repositories.
-
Enable the repository with Circle CI.
-
Create a
.circleci/config.yml
The next image shows how to enable the repository with Circle CI (Click Setup Project).
5.1 Create Circle Config File
The config.yml
file tells Circle CI what to do. It must be located in a folder class .circleci/
at the top level of your project.
Circle CI uses a docker image as the container and has the ability to cache dependencies.
version: 2 (1)
jobs:
build:
working_directory: ~/repo
docker:
- image: circleci/openjdk:8-jdk-browsers (2)
environment:
JVM_OPTS: -Xmx3200m (3)
TERM: dumb
steps: (4)
- checkout (5)
- restore_cache: (6)
key: grailsapp-{{ checksum "build.gradle" }}-{{ checksum "gradle.properties" }}
- run: chmod +x gradlew
- run: ./gradlew --console=plain testClasses (7)
- run: ./gradlew --console=plain integrationTestClasses (8)
- save_cache: (9)
paths:
- ~/.gradle
key: grailsapp-{{ checksum "build.gradle" }}-{{ checksum "gradle.properties" }}
- run: ./gradlew --console=plain -Dgeb.env=chromeHeadless check (10)
- store_artifacts: (11)
path: build/reports
destination: reports
- store_test_results: (12)
path: build/test-results
1 | Check CircleCI 2.0 Java configuration for more details |
2 | Set this Docker Image as the primary container; this is where all steps will run |
3 | Customize the JVM maximum heap limit |
4 | A collection of executable commands. |
5 | Checkout the source code to working directory. |
6 | Restore the saved cache after the first run or if build.gradle has changed. |
7 | Assembles test classes. |
8 | Assembles integration test classes. |
9 | Saves the project dependencies |
10 | Runs both integration, functional and unit tests. The feature method DefaultHomePageSpec is ignored if we do not specify the system property geb.env . |
11 | Uploads the HTML test reports from the build/reports as an artifact |
12 | Uploads the test metadata from the build/tests-results directory so that it can show up in the CircleCI dashboard. |
Commit the change to Git push them to the remote repository. Upon the push, go to https://circleci.com/ and view the build running. Once the build is complete, restart the build to demonstrate that Circle CI will use the cache for dependencies.
6 Where to Go From Here?
Read Circle CI 2.0 documentation to see what it is possible.
For example, Circle CI workflows ease the creation of pipelines to test, and deploy your Grails applications.