Kengo's blog

Technical articles about original projects, JVM, Static Analysis and TypeScript.

Gradle用のGitHub Actions勘どころ

GitHub Actions のベータ版が個人リポジトリの方に来ているので、色々と試しています。使っているテンプレートプロジェクト実アプリケーションプロジェクトから、いくつか事例を紹介します。

なお各種単語の定義が公式サイトにあるので、いちど目を通すことをおすすめします。

テストレポートをworkflow runに添付する

upload-artifact actionを使うことで、テストレポートをworkflow runに対して添付することができます。

    - name: Build with Gradle
      run: ./gradlew build
    - name: Upload Test Report
      uses: actions/upload-artifact@v1
      if: always()
      with:
        name: test results
        path: build/test-results/test

if: always() がミソで、これがないとテスト失敗時にupload-artifactが実行されません。always()の説明は公式サイトにあります。

複数のjobを並列に実行する場合は、nameを固有かつ直感的な名前にしないと、レポートをダウンロードする際にどれを確認すべきかわからなくなってしまいますので要注意です。

wrapperとDockerコンテナどちらを使うべきか

Gradleを使ったビルドは、大きく分けて2つの方法が採れます。 Jobを実行しているマシンにJDKをインストールする方法と、Docker Hubで公開されているgradleのイメージを使う方法です。 なおGradle用の非公式actionが存在しますが、特にメリットがないため検討していません。

Jobを実行しているマシンにJDKをインストールしてGradle Wrapperを叩くケースが最もシンプルと言えます。 Wrapperを使うため、開発者が手元で使うGradleとバージョンを合わせることも容易です(Wrapperを使わずGradleをインストールしてPATHに通しても良いが特にメリットがない)。

    steps:
    - uses: actions/checkout@v1
    - name: Set up JDK 11
      uses: actions/setup-java@v1
      with:
        java-version: 11
    - name: Build with Gradle
      run: ./gradlew build

Docker Hubのgradleイメージを使う場合は、with.argsを使って実行するコマンドを指定します。 e2eテストのようなコマンドに依存するビルドでは使いにくい面もあると考えられますが、持ち運びの効くコンテナでCIを回せるのは嬉しい点です。YAMLファイルの見通しも比較的良いです。

    steps:
    - uses: actions/checkout@v1
    - name: Build with Gradle
      uses: docker://gradle:5.6-jdk11
      with:
        args: gradle build

なお今のところ、この2つの方法には速度の違いはないようです。Dockerコンテナを使うとsetup-javaがなくなりGradleインストールの時間が短縮される反面、イメージをpullする時間がかかります。Dockerイメージやローカルファイルシステムのキャッシュが導入されたら、このあたりは変わってくるかもしれませんね。

Maven Remote Repositoryは何が良いか

Organizationで使う場合はActionsを実行するリージョンが選べるそうです。

が、少なくとも私の個人リポジトリでは選択できない状態です。のでネットワーク的にどこが近いのか確信はないのですが、いくつか実行して試してみました:

試行回数を重ねないと確かなことは言えませんが、少なくともMavenリポジトリの物理位置がビルド速度に影響出るのは間違いありません。自前でRemote Repositoryを運用している場合は、それを物理的にどこに置くか考える必要がありそうです。あるいはpackage-registryを使っても良いかもしれませんね。

SonarCloudを使う

これは至ってシンプルで、sonar.host.url, sonar.organizationそしてsonar.projectKeyシステムプロパティで指定するだけです。公式フォーラムで紹介されています。これだけで通常の解析もブランチ解析PR解析もいけます。

    - name: Build with Gradle
      run: ./gradlew sonarqube -Dsonar.organization=foo -Dsonar.projectKey=bar -Dsonar.host.url=https://sonarcloud.io
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        SONAR_TOKEN: ${{ secrets.SONARCLOUD_TOKEN }}

上記の例では -D オプションを使って指定していますが、build.gradleに直接書いても大丈夫です。 環境変数として GITHUB_TOKENSONAR_TOKENの設定が必要です。

2020-01-12 追記

上記の書き方だとforked repoからPRを送ってもらった時に問題になるので、secret variableにアクセス可能な場合にのみ実行するような工夫が必要なようです。

    - name: Run SonarQube Scanner
      run: |
        if [ "$SONAR_LOGIN" != "" ]; then
          ./gradlew sonarqube -Dsonar.login=$SONAR_LOGIN
        fi
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        SONAR_LOGIN: ${{ secrets.SONAR_LOGIN }}

READMEにステータスバッジを埋める

公式ドキュメントが公開されましたので、それを参照すればOKです。

~/.gradle をキャッシュしたい!

GradleやMavenを使っていると、Mavenリモートリポジトリからダウンロードしたjarファイルをキャッシュしたくなります。残念ながら現時点ではその方法は無いようです。

Actions toolkitに入っているtool-cacheを使って~/.gradle/cachesをキャッシュするActionsを書いてみたのですが、キャッシュの保存はできてもキャッシュされたディレクトリをfindできません。Debugログを有効化しても特に情報は得られませんでした。

Javaに限らず他の言語のコミュニティにも期待されている機能だと思いますので、今後に期待しています。