Github Actionsを使ってGradle Plugin Portalにリリースする

試しにやってみたら便利な気がしたので紹介します。

最初にタイトルの内容を実現するactinosを貼っておきます。以降は時間があったら読んでください。

name: Publish
on:
  push:
    tags:
    - '*'
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    - name: set up JDK 1.8
      uses: actions/setup-java@v1
      with:
        java-version: 1.8
    - name: Add .gradle dir
      run: mkdir ~/.gradle
    - name: Add gradle portal token
      run: |
        cat << EOS > ~/.gradle/gradle.properties
        gradle.publish.key=$GRADLE_PUBLISH_KEY
        gradle.publish.secret=$GRADLE_PUBLISH_SECRET
        EOS
      env:
        GRADLE_PUBLISH_KEY: ${{ secrets.GRADLE_PUBLISH_KEY }}
        GRADLE_PUBLISH_SECRET: ${{ secrets.GRADLE_PUBLISH_SECRET }}
    - name: Set tag version
      run: echo ::set-env name=TAG_VERSION::${GITHUB_REF#refs/tags/}
    - name: Publish this plugin to gradle portal
      run: ./gradlew clean publishPlugins

あらすじ

私はAndroid開発者をやっています。最近Gradle Pluginを書く機会があり、そのプラグインは会社のOrganazationでメンテする事になったため自分以外の人間も手軽にリリースできる仕組みを作りました。この記事ではプラグイン公開までざっくりした過程とGithub Actionsを利用したリリース方法について書きます。

プラグインの公開先について

少し前はプラグインもBintrayで公開する方法が一般的だった認識ですが、最近はGradle公式のプラグイン用のMaven Repositoryが用意されたのでGradle Plugin Portalにホストするのが主流なようです。詳しい公開手順は省きますが、下記のリンクを辿ると迷いなく公開まで出来るかと思います。
(もしGradleプラグインの作り方そのものについて詳しくなかった場合は、2月に開催されるDroidkaigi2020でその辺りを話すので足を運んでください :D )

Publishing Plugins to the Gradle Plugin Portal

リリースの自動化

社内のよく知らないライブラリの更新作業を突然頼まれた場合に一番困るパターンが、"リリースするために必要な秘匿値を頑張ってを探し出し、手元でリリースコマンドを叩くケース"かと思います。これは過去の経験から避けたいと思っていました。 そこでRundeckなどのジョブスケジューラを使ったリリースを考えたんですが、二点困り事があります。

  • 秘匿値を何で管理するか
  • Rundeckにリリースタスクがあることをどのように伝えるか

前者はどうにでもなリそうですが、後者は微妙な問題でPublishなレポジトリのREADMEに社内のジョブスケジューラのパーマリンクを貼るのは避けたいし、かといって社内ブログに書くと情報が分散してしまい見つけにくいデメリットがあります。 そこで最近興味があったGithub ActionsとレポジトリのSecretを使って解決できないか試したという経緯です。

タグを打ったら自動でリリース

Github Actionsは基本的にはイベントドリブンで動作します。一般的なジョブスケジューラみたいにGUIにRunボタンはないのでどうやってリリース処理を実行させるか考える必要があります。今回は任意tagがpushされたら反応するトリガーを設定し、そのtagのバージョンでMaven repositoryにリリースするスクリプトを書きました。それがこの部分に当たります。

on:
  push:
    tags:
    - '*'

環境変数やタスクの引数で秘匿値が渡せない

先程リンクしたプラグインの公開記事を読んでもらうと com.gradle.plugin-publish というライブラリを利用して公開することがわかると思います。記事の中では秘匿値として扱うべきtokenとsecretが ~/.gradle/gradle.properties から読み込まれていることがわかります。これはCI環境では絶妙に厄介です。出来ればタスクの引数や環境変数を通して設定したいのですがそのような方法は公式のドキュメントには存在しません。その上このプラグインはコードが公開されていないので正攻法で調べることも不可能でした(厳密には過去のバージョンは見れます) 。
一応ゴニョゴニョしてみたものの、結果的にタスクの引数や環境変数で秘匿値の受け渡しには対応してない事を確認したので、CI上で.gradle/gradle.propertiesを作って上げることにしました。その処理が下記の部分に該当します。Github Actionsファイルを作成するため3rd party製ツールのサポートもあったんですが、shell scriptでも書いても大差ないので利用しませんでした。

- name: Add .gradle dir
  run: mkdir ~/.gradle
- name: Add gradle portal token
  run: |
    cat << EOS > ~/.gradle/gradle.properties
    gradle.publish.key=$GRADLE_PUBLISH_KEY
    gradle.publish.secret=$GRADLE_PUBLISH_SECRET
    EOS
  env:
     GRADLE_PUBLISH_KEY: ${{ secrets.GRADLE_PUBLISH_KEY }}
     GRADLE_PUBLISH_SECRET: ${{ secrets.GRADLE_PUBLISH_SECRET }}

タグの情報を環境変数にする

リリースバージョンにtagの値を使いたかったので環境変数に設定したかったのですが、意外にもこの作業が面倒だったので下記のURLを参考に強引に環境変数に設定しています。

Solved: Re: How to get just the tag name? - GitHub Community Forum

- name: Set tag version
  run: echo ::set-env name=TAG_VERSION::${GITHUB_REF#refs/tags/}

終わり

こんな感じにリリースを自動化すると秘匿値の管理もリリースもGithubのレポジトリで完結し、push権限のある人はリリースが可能になるので便利です。READMEにも詳しく手順を書くことが可能なのでぜひ試してみてください。