Eric Helgeson
Posted on November 14, 2019
I recently was playing with Github Actions and a Grails 3 app. Was a bit of trial and error though I finally got a working CI workflow.
Github recently added build caching with limitations - this dramatically speeds up your CI builds.
A nice aspect about Actions is you can have actions based on not only pushes/PRs/tags but also things like Github comments. For example /rebase
- there's an entire marketplace of actions you can try out.
I've commented the yml
file to help you get an understanding of whats going on and how it works.
Full syntax for this yml file can be found here:
I've also included customized test reporting below - since there is no "results" step to see a junit type report. You can find that below the ream of yml.
.github/workflows/grails.yml
name: Grails CI
# When this workflow will run - here it will run on all pushes but
# not on branch 'master
on:
push:
branches-ignore:
- 'master'
# A list jobs to run when the condition is met - here we've parallelized
# the build to run test, integrationTest, and assemble.
jobs:
test:
runs-on: ubuntu-latest
# A list of Docker containers you require to run the test
services:
postgres:
image: postgres:latest
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
ports:
- 5432:5432
# Steps in this build
steps:
- uses: actions/checkout@v1
# We are caching the node_modules, ~/.gradle and app/.gradle
# to speed up our build. Caches are automatically stored and restored
# based on a file hash - in this case yarn.lock and build.gradle
- name: Cache node modules
uses: actions/cache@v1
with:
path: src/main/vue/node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-node-
- name: Cache .gradle
uses: actions/cache@v1
with:
path: .gradle
key: ${{ runner.os }}-dotgradle-${{ hashFiles('**/build.gradle') }}
restore-keys: |
${{ runner.os }}-dotgradle-
- name: Cache gradle
uses: actions/cache@v1
with:
path: /home/runner/.gradle
key: ${{ runner.os }}-gradle-${{ hashFiles('**/build.gradle') }}
restore-keys: |
${{ runner.os }}-gradle-
# Setup JDK 8
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
# Finally run the test.
- name: test
run: ./gradlew test --no-daemon
# Integration and assemble are much the same
# though it's yml so not DRY - omitted the copy/paste
integrationTest:
steps:
- name: integrationTest
run: ./gradlew integrationTest --no-daemon
assemble:
steps:
- name: assemble
run: ./gradlew assemble --no-daemon
And here is a test formatter that gives you the Spock errors to stdout nicely for debugging as well as a summary:
.gradle/testFormatter.gradle
// From https://stackoverflow.com/a/40656862
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent
tasks.withType(Test) {
testLogging {
// set options for log level LIFECYCLE
events TestLogEvent.FAILED,
TestLogEvent.PASSED,
TestLogEvent.SKIPPED
exceptionFormat TestExceptionFormat.SHORT
showExceptions true
showCauses true
showStackTraces true
// set options for log level DEBUG and INFO
debug {
events TestLogEvent.STARTED,
TestLogEvent.FAILED,
TestLogEvent.PASSED,
TestLogEvent.SKIPPED
exceptionFormat TestExceptionFormat.SHORT
}
info.events = debug.events
info.exceptionFormat = debug.exceptionFormat
afterSuite { desc, result ->
if (!desc.parent) { // will match the outermost suite
def output = "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} passed, ${result.failedTestCount} failed, ${result.skippedTestCount} skipped)"
def startItem = '| ', endItem = ' |'
def repeatLength = startItem.length() + output.length() + endItem.length()
println('\n' + ('-' * repeatLength) + '\n' + startItem + output + endItem + '\n' + ('-' * repeatLength))
}
}
}
}
Posted on November 14, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.