mike-neckのブログ

Java or Groovy or Swift or Golang

graalvm-native-image プラグイン 0.3.0 をリリースしました

表題のとおりです。

f:id:mike_neck:20200229235318p:plain

plugins.gradle.org


というだけではエントリーとしては面白くないので、このプラグインに関して github actions の活用とこのプラグインの考え方について 2 つほど書きます。

1. github actions を大活用するようにした

今回のリリースは機能的なリリースはまったくなく(そもそも機能が少ない)、リリース方法の更新、サポートされる graalvm のバージョンの更新が主な内容です。

こちらのプラグインはバージョン 0.1.0 の頃は全然 CI も設定していないプロジェクトで、思いつきをそのまま形にしただけのプラグインだったし、ドキュメントも間違っているというわりと散々な状態でした。 CI についても意識はしていたのですが、 github actions が GA になった頃で勉強がてら github actions でテストを回してみようかなとYAML を書いてみたもののまだ書き方がよくわからなくて動かせず、放置してた状態でした。

若干放置気味だったある日、 Christian Dräger さんという方がプルリクエストをいくつか送ってくれました。

  • README の間違っている箇所を修正する #2
  • github actions で CI できるようにする #3
  • gradle wrapper version を 6.0 に更新する #4
  • バッジを付ける #5
  • kotlin dsl のサンプルを付ける #6

やらなければと思いつつ、何もやらないでいたので、非常にありがたく、「神が現れた」とつぶやきつつノールック(ちゃんと全部目を通してるけど)でマージしました。特にありがたかったのが github actions で、作ってもらった動くサンプルを、この後いくつか github actions 勉強用のリポジトリーを作った際にコピペして使っています。

というわけで、これをきっかけにしていろいろと github actions 遊んで、調べていくうちに tag をプッシュした時に動かす方法というのもわかってきました。そこで、今回の更新のひとつ、 github actions で gradle plugin portal にリリースするようにしました。

github actions で tag push を検知してリリースする

tag が push された場合、 github というコンテキストオブジェクトの ref という値が ref/tags/{tag-value} という形になります。このタグの値から gradle プロジェクトのバージョンを設定するようにします。

gradle plugin portal にリリースする際には portal へのログインが求められますが(人の手を介する場合)、plugin portal のユーザープロフィール画面からトークンの一覧を取得できる画面に行けるので、そこで gradle.publish.keygradle.publish.secret という2つのトークンを取得して、同名のプロパティに設定するようにします。これらの値は GitHub のプロジェクトの Secrets にそれぞれ GRADLE_PUBLISH_KEYGRADLE_PUBLISH_SECRET という名前で設定します。

以上を実装すると、次のような YAML と、 build.gradle(一部のみ) ができます

name: Release Plugin
on:
  push:
    tag:
      - "*"

jobs:
  build:
    name: Release Plugin
    runs-on: ubuntu-18.04

    steps:
      - name: Checkout
        uses: actions/checkout@v1

      - name: Set up Java
        uses: actions/setup-java@v1.3.0
        with:
          java-version: '8.0.242'

      - name: Release to gradle plugin portal
        if: contains(github.ref, 'refs/tags/')
        env:
          REF: ${{ github.ref }}
          GRADLE_PUBLISH_KEY: ${{ secrets.GRADLE_PUBLISH_KEY }}
          GRADLE_PUBLISH_SECRET: ${{ secrets.GRADLE_PUBLISH_SECRET }}
        run: |
          ./gradlew clean publishPlugins \
            -Pgradle.publish.key=$GRADLE_PUBLISH_KEY \
            -Pgradle.publish.secret=$GRADLE_PUBLISH_SECRET \
            -PpluginVersion=`echo $REF | tr '/' ' ' | awk '{print $3}'`
ext {
    thisPluginVersion = project.hasProperty('pluginVersion')?
            project.property('pluginVersion'):
            'snapshot'
}

version = thisPluginVersion

また、job には strategy.matrix というマルチバリューマップを設定できて、それらの組み合わせで複数の job を実行できるようになります。これを用いれば複数の graalvm のバージョンでの動作を確認できます。

name: Run Gradle Tests
on: [push]
jobs:
  test:
    strategy:
      matrix:
        graal:
          - 19.3.0.java8
          - 19.3.0.java11
          - 19.3.1.java8
          - 19.3.1.java11
          - 20.0.0.java8
          - 20.0.0.java11
    runs-on: ubuntu-18.04
    name: Run functionalTest on graalvm ${{ matrix.graal }}
    steps:
      - name: Checkout
        uses: actions/checkout@v1

      - name: Set up GraalVM
        uses: DeLaGuardo/setup-graalvm@2.0
        with:
          graalvm-version: ${{ matrix.graal }}

      - name: Install GraalVM native-image
        run: gu install native-image

      - name: Run functional test
        run: ./gradlew clean functionalTest

上記の例では、 graalvm の

  • 19.3.0.java8
  • 19.3.0.java11
  • 19.3.1.java8
  • 19.3.1.java11
  • 20.0.0.java8
  • 20.0.0.java11

でテストが行われます。


2. このプラグインの考え方について

最初僕は次のユースケースにあう native-image を作るプラグインを探していました。

  • Java のプログラムを native image 化する
  • gradle で動かせる
  • graalvm 自体は自分のローカルにインストールされているものを使う
  • native-image のラップだけであって、その他の機能はいらないし、使わない

なぜなら僕は「 native-image を作れるプラグインがあるだろう、だって僕が gradle でやろうと思いつくくらいだから、世の優秀なプログラマーがすでに解決しているはず」と考えていたからです。

実際、 こちら を見ると native-image を作るプラグインがいくつかあるようです。

  1. Quarkus 用プラグイン
  2. ヒューレット・パッカード製のプラグイン
  3. Palantir technology 製のプラグイン

これらについて自分のユースケースと比較して、使えそうなものを探しました。しかし…

  • Quarkus のプラグインは名前の通り Quarkus 用のプラグインで、これを使って native-image を作れるかと思って native-image だけに絞って使い方のドキュメントを探したのですが maven のものは見つかるものの、 gradle のものは見つかりませんでした。
  • ヒューレット・パッカード製のプラグインは説明に 「Enables the use of Kotlin coroutines and GraalVM native-image together」 と書いてあるとおり、Kotlin コルーチンと密接に結合しているようです。 Kotlin もコルーチンも使わないので対象外でした。
  • 最後の Palantir technology 製のものは、 graalvm に特化している分、ユースケースに合致するかと思ったのですが、GraalVM をダウンロードするというあたりがどうにもユースケースに合わず諦めました。

といった感じで、自分のユースケースに合わなさそうなので、自分で作ることを決めました。

以上から、このプラグインは ローカルにインストールされている native-image を呼び出しているだけの簡単なプラグインを目指して作られていますし、実際にそれだけしかしません。 native-image を gu ツールでインストールする部分をラップしたタスクを用意してもいいかもしれないけど、実際に gradle で native-image を作るような人は、すでにインストールしてしまっているだろうし、ツールのインストール状況を管理するのは他のものを使って、 gradle はあくまでプロジェクトのビルドに徹するべきだと思っています。


以上、graalvm-native-image-plugin の考え方と github actions の活用について話しました。

まあ、 native-image を使うこと自体が稀だと思いますが、もし使うようなことがあればこのプラグインのことを思い出していただけると幸いです。