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.

Front Matter

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.

Enable

sed -i 's/\/\/include(":example:")/include\(":example:"\)/g' settings.gradle.kts

Disable

sed -i 's/include(":example:")/\/\/include\(":example:"\)/g'

Both commands are sed inserting into the settings.gradle.kts file.

  • Look for a line //include(":example:") if present change to include(":example:")
  • Look for a line include(":example:") if present change to //include(":example:")

It's not the cleanest but it works.

Build

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.

Integration Tests

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.

Publish

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.

Full Yaml

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

Source Code

Files · Part2 · AnimusDesign / examples / TypeProvider
GitLab.com