Now that we have the core plugin and skeleton build out. We want to ensure a prompt quick feed back loop for ensuring that changes are indeed working.
This example will be using GitLab CI/CD.
We will be focusing on building a simple pipe line. With three stages.
- Build the plugin
- Integration test against the plugin
- Publish the plugin.
If you're not familiar with the GitLab CI/CD system. It takes a
YAML file at the root of the repository to define the pipe line. Each stage is executed in a docker container. Each stage may define a custom image, or a top level image.
image: registry.gitlab.com/animusdesign/kotlin-mp-build:latest stages: - build - test - integration_test - publish - pages cache: paths: - ./.m2/repository - .gradle/wrapper - .gradle/caches key: "$CI_BUILD_REF_NAME"
- image Defines the docker build image. This is a custom one I maintain for building multi platform images.
- stages Defines the respective pages of the pipe line.
- cache Defines what to cache, downloaded dependencies, etc.
As we define the front matter. We want to think about repetitive tasks to expedite the build. That's why I built a custom docker image. It includes additional debugging tools that can help me if a build steps. You can also limit time by re-using dependencies.
The Tricky Part
Building gradle plugins requires some extra work up front. The problem is we need to manipulate
settings.gradle.kts. Disabling and enabling the example project that consumes the plugin. The example project will throw an error if the plugin is not present.
sed -i 's/\/\/include(":example:")/include\(":example:"\)/g' settings.gradle.kts
sed -i 's/include(":example:")/\/\/include\(":example:"\)/g'
Both commands are sed inserting into the
- Look for a line
//include(":example:")if present change to
- Look for a line
include(":example:")if present change to //
It's not the cleanest but it works.
During the build stage prior to running tests, we want to ensure that the plugin builds. There is no point in running tests if there is a compile error on the plugin.
While this is a very simple example, a one property class. We still want to set up the scaffolding for easing testing. Above is a screen capture of the test running, and it's status.
The integration tests, use the gradle plugin. Generating the expected types. Then runs tests against them. This is a full dog food run.
We now publish the artifact so that it can be consumed / used. This is done after testing and validation. We don't want to publish an artifact without validating that it works as anticipated.
Note: There is a bug regarding gradle and snapshots not working right now with GitLab packages.
image: registry.gitlab.com/animusdesign/kotlin-mp-build:latest stages: - build - test - integration_test - publish - pages cache: paths: - ./.m2/repository - .gradle/wrapper - .gradle/caches key: "$CI_BUILD_REF_NAME" build:typeprovider_plugin: stage: build script: - ./scripts/publish-local.sh artifacts: paths: - plugin/build expire_in: 60 mins integration_test:example: stage: integration_test script: - sh ./scripts/publish-local.sh - tree ~/.m2/repository - sed -i 's/\/\/include(":example:")/include\(":example:"\)/g' settings.gradle.kts - ./gradlew :example:generateTypes - ./gradlew :example:test artifacts: reports: junit: example/build/test-results/test/*.xml publish:typeprovider_plugin: stage: publish except: refs: - release/.* - master script: - sed -i 's/include(":example:")/\/\/include\(":example:"\)/g' settings.gradle.kts - ./gradlew :plugin:publish artifacts: paths: - plugin/build/libs/*.jar expire_in: 1 week