TravisCIでMavenCentralへのリリースを自動化する

[モバイルDevOpsアドベントカレンダー](http://qiita.com/tnj/items/79b728313a285eba0184) 10日目の記事です。

今回はAndroidアプリ開発に必須な、ライブラリなどのMavenCentralへのリリース作業をTravis CIで自動化したお話です。
意外とMavenCentralへのアップロードをTravisCI経由で行っているなどの記事が少なかったので、今回書いておくことにしました。
ちなみに、自動化したライブラリなどは以下のレポジトリで公開しているので、.travis.ymlなどを参考にしてください。

* [gradle-deploygate-plugin]
(https://github.com/DeployGate/gradle-deploygate-plugin)
* [deploygate-android-sdk](https://github.com/DeployGate/deploygate-android-sdk)

# 手作業では結構大変なリリース手順

MavenCentralへのリリース作業を行ったことがある人はご存知と思いますが、MavenCentralへのリリース作業は結構大変だったりします。
特に大変なのは初回の1回目(詳しくは[他の方の記事](http://blog.64p.org/entry/2014/10/31/075617)などをご参照ください)なのですが、これを済ませるとその後は割と簡単にリリースを行うことができるのですが、他のメンバーがリリース作業を行ったりするときなどは署名のための鍵の共有などが発生するため割と面倒くさいです。
具体的には、以下のような手順でリリースを行います。

1. 署名用の鍵を共有してもらい、リリース作業者のPCにimportする
2. 環境変数などを整えて、gradleによってbuild及びMavenCentralへのアッップロードをする
3. [Sonatype Nexus Professional](https://oss.sonatype.org/index.html#welcome)にアクセスして、CloseからのReleaseを行う

これを自動化することで、以下のように手順を短縮するとともに、分かりやすくすることができます。

1. リリースしたいrevisionでgitのtagを作成してGitHubにpushする(GitHub上で直接release tagを作成しても同じです)
2. TravisCIによりリリースが行われるので、リリース完了後に[Sonatype Nexus Professional](https://oss.sonatype.org/index.html#welcome)にアクセスして、CloseからのReleaseを行う

正直な話をすると、この2の手順さえも自動化したい(そのまま放置しても時間が経つことによって自動でリリースされるらしい？)のですが、現状は手動によってWebにアクセスしてリリースをしています。

# CIによるリリース自動化のメリット

CIツールなどによってリリースを自動化することで、属人化を防ぐメリットとともに、社内でのリリース手順の共有のコストも軽減することができます。
また、リリースビルド時のJDKのver固定などを強制できるメリットもあります。(1.8でビルドして、1.7で使用できないなどのしょうもない問題が解消できるのはデカイ)

# TravisCIによるMavenCentralへのリリース自動化

今回は実際にリリースの自動化を行っている[gradle-deploygate-plugin](https://github.com/DeployGate/gradle-deploygate-plugin)を例にして説明をしていきます。

## 前提条件

まず前提として、以下のコマンドでライブラリなどのbuildからMavenCentralへのuploadまでを行えるようにします。

```shell-session
$ ./gradlew clean build uploadArchivesx
```
uploadArchivesなどの設定は、[build.gradle](https://github.com/DeployGate/gradle-deploygate-plugin/blob/master/build.gradle)や[build.publish.gradle](https://github.com/DeployGate/gradle-deploygate-plugin/blob/master/build.publish.gradle)を参考にしてみてください。

## [.travis.yml](https://github.com/DeployGate/gradle-deploygate-plugin/blob/master/.travis.yml)の設定

今回使用している[.travis.yml](https://github.com/DeployGate/gradle-deploygate-plugin/blob/master/.travis.yml)は以下のようになっています。

```.travis.yml
language: java
sudo: false
env:
  global:
  - secure: ......
jdk:
- openjdk7
script:
- "./gradlew build test"
before_deploy:
- openssl aes-256-cbc -K $encrypted_......_key -iv $encrypted_......_iv
  -in secret.key.enc -out secret.key -d
- gpg --import --allow-secret-key-import secret.key
- rm secret.key
deploy:
  provider: script
  script: ./release.sh
  on:
    tags: true
    repo: DeployGate/gradle-deploygate-plugin
after_deploy:
- 'curl -X POST --data-urlencode "payload={\"text\": \"Released a gradle-deploygate-plugin in Maven Central! Please check <https://oss.sonatype.org/content/groups/public/com/deploygate/|public> or <https://oss.sonatype.org/index.html#stagingRepositories|stagingRepositories>\"}" $SLACK_URL'
```

重要な点として、travisコマンドの[encrypt-file](https://docs.travis-ci.com/user/encrypting-files/)を使って署名に使用する秘密鍵を渡しているところです。
TravisCI側に秘密鍵を暗号化して渡して復元した後に、gpg --import --allow-secret-key-importで鍵の設定をしています。

また、TravisCIの[Deployment](https://docs.travis-ci.com/user/deployment/)を使うことで、tagが作成されて時のみこのdeployタスクとbefore, afterが実行されるようになっています。
今回TravisCIのdeployを始めて使ったんですが、色々なproviderに対応していて便利ですね！
さらに、このdeployのprovider自身は[dpl](https://github.com/travis-ci/dpl)という名前で公開されているgemなので、必要なproviderがあればPRなどで追加できるのはいいですね！

ちなみに、deployで実際に実行しているrelease.shは以下のようになっています。
あえて別ファイルとしているのは、手元のPCでも簡単に実行できるようにするためです。

```release.sh
#!/usr/bin/env bash

./gradlew clean build uploadArchives -Psigning.secretKeyRingFile=$HOME/.gnupg/secring.gpg -PsonatypeUsername=henteko -PsonatypeFullname=deploygate -Psigning.keyId=$SIGNING_KEY_ID -Psigning.password=$SIGNING_PASSWORD -PsonatypePassword=$SONATYPE_PASSWORD
```

## after_deployでSlackに発言させる

最後にafter_deployによってSlackに通知が行くようにしています。
これはリリース作業の最後の手順をメンバーに実行させるようにするためです。
[gradle-deploygate-plugin]
(https://github.com/DeployGate/gradle-deploygate-plugin)では以下のような通知が来るように設定しています。
めでたい感じにすると、とてもテンションが上がります。
![スクリーンショット 2015-12-08 17.40.00.png](https://qiita-image-store.s3.amazonaws.com/0/6717/5925f4be-9fd5-152d-2b50-5f5e4e6abb99.png)

# さいごに

MavenCentralへのリリースをTravisCIによって自動化する一例を説明しました。
最近では[jCenter](https://bintray.com/bintray/jcenter)に直接リリースするのが主流になりつつあるそうですが、MavenCentralにリリースすればGradleで以下のような設定にしていても、透過的にMavenCentralへライブラリを取得しに行くので、安心ですね。(しかしリリースはめんどくさい)

```build.gradle
repositories {
    jcenter()
}
```