Hello Human!
This tutorial is for you if
- β 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.
Define the task ./gradlew runOnGitHub
Here is the error you will found in Details
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 root
build.gradle.kts
orbuild.gradle
file - Register a Gradle task called
runOnGitHub
like this:
tasks.register("runOnGitHub") { // 1
dependsOn(":app:lint", ":app:testDebugUnitTest") // 2 ==> CUSTOMIZE THIS LINE
group = "custom" // 3
description = "$ ./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:
- Celebrate
Submission Category:
Maintainer Must-Haves
Additional Resources / Info
To know more about creating your own Gradle tasks, follow the gentle tutorial at https://guides.gradle.org/writing-gradle-tasks/
Read the docs about GitHub Actions
Read the docs about the Gradle Command Action
gradle / gradle-build-action
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:
uses: gradle/gradle-build-action@v3
with
uses: gradle/actions/setup-gradle@v3
See the setup-gradle documentation for up-to-date documentation for gradle/actions/setup-gradle
.
Setup Gradle for use in GitHub Actions workflows
This GitHub Action can be used to configure Gradle on any platform supported by GitHub Actions.
Example usage
name: Build
on: [ push ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
- name: Build with Gradle
run: ./gradlew build
See the full setup-gradle documentation for more advanced usage scenarios.
Personal Story
Using GitHub Action to publish libraries
I have used GitHub Actions in the past for more complex workflows to publish libraries.
If you are interested, have a look here:
https://github.com/jmfayard/refreshVersions/tree/master/.github/workflows
https://github.com/LouisCAD/Splitties/tree/main/.github/workflows
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
π Setup a GitHub Action using Gradle to run the unit tests #2 #100
What type of PR is this? (check all applicable)
- [ ] Refactor
- [x] Feature
- [ ] Bug Fix
- [ ] Documentation Update
Description
A GitHub Action for Gradle that runs the unit test of this Android project
Related Tickets & Documents
GitHub Actions hackaton on DEV
https://dev.to/devteam/announcing-the-github-actions-hackathon-on-dev-3ljn
Screenshots/Recordings (if there are UI changes)
See https://github.com/jmfayard/DEV-Android/actions?query=workflow%3A%22Android+unit+tests%22
I added the build scan plugin for better reporting if there are tests failure
https://scans.gradle.com/s/2tzis4ikslecg/tests
[optional] What gif best describes this PR or how it makes you feel?
π GitHub Action with ./gradlew runOnGitHub #12
If merged, a GitHub Action will be installed that runs ./gradlew runOnGitHub
on each pull request
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:
Use the Gradle build-scan!
Jean-Michel π΅π»ββοΈ Fayard γ» Sep 22 '19
Is your Testing Pyramid Inverted?
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:
Just Say No to More End-to-End Tests
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.
Copy the file .github/workflows/runOnGitHub.yml, define your Gradle task runOnGitHub
and create your pull request.
Please leave a comment if that works for you. I usually only hear from what went wrong :)
Top comments (0)