β you have an Android or Kotlin or Java project built with Gradle
β you write unit tests
β you have no Continuous Integration system setup to run your tests on the server
Having the guarantee that your unit tests run on the build server is a keystone to establish a culture of testing withing your team - either at work or in an open-source project.
Perhaps you know that already, and have been told that you could setup Jenkins or Travis or CircleCi. But you don't even know which one to choose, let alone how to configure them.
My goal is to convince you that you can start today setting up a pipeline with GitHub Actions and Gradle.
My Workflow
Open your Android or Gradle project
Create a file called exactly .github/workflows/runOnGitHub.yml with this content
Commit and create a pull request
After a short while, you should see this:
The GitHub Action is failing.
That's progress: before it was not even running!
The next step is to follow the link "Details" to see what is going on.
Welcome to Gradle 6.6.1!
FAILURE: Build failed with an exception.
* What went wrong:
Task 'runOnGitHub' not found in root project '$YOUR_PROJECT'.
BUILD FAILED in 1m 31s
That makes a ton of sense, we didn't define the Gradle task runOnGitHub yet.
Next:
Open the rootbuild.gradle.kts or build.gradle file
Register a Gradle task called runOnGitHub like this:
tasks.register("runOnGitHub"){// 1dependsOn(":app:lint",":app:testDebugUnitTest")// 2 ==> CUSTOMIZE THIS LINEgroup="custom"// 3description="$ ./gradlew runOnGitHub # runs on GitHub Action"//3}
There are three steps
you register a new task called runOnGitHub
you define via dependsOn() which tasks should be executed before runOnGitHub. In this example we run the linter and the unit tests in the app module. This is the crucial step that will depend from project to project. So be sure to customize it for your needs.
you document what will appear when you run ./gradlew tasks
Push to GitHub and make the Action pass
Once you have defined the task:
Run locally the task ./gradlew runOnGitHub and check it does what you want.
Tip: Save time by running ./gradlew --dry-run runOnGitHub to see quickly what tasks would be executed without actually running them.
Push to GitHub
Open the Actions tab on GitHub and if you are lucky you will see this after a while:
Execute your Gradle build and trigger dependency submission
Important
As of v3 this action has been superceded by gradle/actions/setup-gradle
Any workflow that uses gradle/gradle-build-action@v3 will transparently delegate to gradle/actions/setup-gradle@v3.
Users are encouraged to update their workflows, replacing:
As of v3, the gradle/gradle-build-action action delegates to gradle/actions/setup-gradle with the same version.
Configuration and usage of these actions is identical for releases with the same version number.
But instead of talking about those complex ad hoc workflows, I thought it would be more interesting to help all Gradle and Android projects to make the first step to have continuous integration with GitHub Action and Gradle.
Yaml File or Link to Code
The nice thing about my workflow is that it's pretty generic.
I submitted my workflow in two Pull Requests, one for a friend's project and the other for the Android app of DEV.to
If you look at the pull-request, one thing I have done is to setup the Gradle build-scan for better reporting when tests are failing. I wrote abouit here already:
A problem I encountered in the DEV-Android app is that it had very few unit tests
Something to keep in mind if you have an Android project is that my workflow allows you to run the unit tests on GitHub, but not the integration tests / automated GUI tests also called Android instrumentation tests.
There are good reasons for that.
Unit tests are fast, easier to write and lead faster to the discovery and fix of the bug when they fail.
This is why the recommended strategy is to have a testing pyramid where the emphasis is put on writing a lot of fast simple unit tests:
Unfortunately there is a common anti-pattern in the Android world where not enough emphasis is put on the unit tests. The testing pyramid looks like this and won't probably last as long as the ones in Egypt:
To understand why it's an anti-pattern, read the Google Testing blog:
Now if you want to start putting more emphasis on writing more unit tests, having this infrastructure in place with GitHub Action is a nice first step.
YAML is a terrible programming language
My biggest frustration by far was due to those YAML "configuration files".
I use quotes here because I think that "configuration file" here is a lie.
Look, we want to make a computer do stuff that are not trivial.
What we are doing is writing a programming script.
What happens here is that someone at GitHub just made up a terrible programming language disguised as YAML. There are hundred things that can go wrong, the IDE won't help you a bit, and it's a mmajor time waster.
The better alternative is to use an actual programming language.
Not Bash.
Just imagine how simpler it would be if the IDE could help you exactly as well as it helps you when you write your code.
Well you don't have to imagine because configuration as code is a thing in alternatives to GitHub Action for example in TeamCity from JetBrains
I hope GitHub will provide us something like this.
Feedback?
I hope you will try setting up your first CI with GitHub Action + Gradle.