Check! GitHub Actions: Maven リポジトリにデプロイする
Prologue
前回に引き続き、とあるプロジェクトで、 Maven リポジトリへのデプロイを GitHub Actions に移行することになったお話です。
まず前回は、Java を利用した経験が乏しく不慣れだったので、手始めとして手動で Maven リポジトリへデプロイする手順を確認し、記事にまとめました。今回の作業環境もこの記事がベースになっています。
そして、本記事では、GitHub Actions で Maven リポジトリにデプロイする方法を整理していきます💡
Maven リポジトリにデプロイする GitHub Actions のワークフローを作成する
実は、ほとんどのことが、こちらの公式ドキュメントにとてもわかりやすく記載されています😳
ざっくりとした流れは、 setup-java
アクションを使ってJava のセットアップをし、 run
で mvn
コマンドを実行するだけです。
このドキュメントでは GPG 署名について触れられていなかったので、その点を中心に補足していきます。
- Maven プロジェクトの設定を確認する
-
setup-java
アクションに GPG 秘密鍵をインポートさせる - シークレットを登録する
- GitHub Actions のワークフローを書く
Maven プロジェクトの設定を確認する
まず、ここで扱うプロジェクトについて記載します。
pom.xml の構成
プロジェクトの pom.xml には、下記のように記述しています。
<version>
は、mvn
コマンドを実行する際に上書きして指定できるようにプロパティをあてました。
<project>
<groupId>com.example.your-project<groupId>
<artifactId>your-artifact</artifactId>
<version>${revision}${changelist}</version>
...
<distributionManagement>
<repository>
<id>your-repository</id>
<url>http://<your server>:8081/nexus/content/repositories/your-repository</url>
</repository>
</distributionManagement>
...
<!-- GPG sign -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
<!-- To make reference to the passphrase on settings.xml instead of GUI dialog -->
<configuration>
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
<properties>
<revision>1.0.0</revision>
<changelist>-SNAPSHOT</changelist>
</properties>
</project>
settings.xml の設定
settings.xml は、後述のGitHub Actions のワークフローの中で setup-java
アクションに指示して自動で作成させます。
setup-java
アクションに GPG 秘密鍵をインポートさせる
この setup-java
アクションは、Java の環境セットアップとともに、settings.xml
の生成や GPG キーのインポートまで実施してくれます。詳細は下記をご参照ください。
setup-java
アクションはこのように記載します。
- name: Set up Java with importing GPG
uses: actions/setup-java@v1
with: # running setup-java again overwrites the settings.xml
java-version: 1.8
server-id: maven # Value of the distributionManagement/repository/id field of the pom.xml
server-username: MAVEN_USERNAME # env variable for username in deploy
server-password: MAVEN_USER_PASSWORD # env variable for token in deploy
gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase
gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} # Value of the GPG private key to import
まず、server-username
, server-password
, gpg-passphrase
に指定するのは、このアクションが生成する settings.xml のそれぞれの値で参照させる環境変数の変数名(文字列)です。
<settings>
<servers>
<server>
<id>maven</id>
<username>${env.MAVEN_USERNAME}</username>
<password>${env.MAVEN_USER_PASSWORD}</password>
</server>
<server>
<id>gpg.passphrase</id>
<passphrase>${env.MAVEN_GPG_PASSPHRASE}</passphrase>
</server>
</servers>
</settings>
そして gpg-private-key
に指定する値は、GPG秘密鍵の内容(value)です。
GPG秘密鍵のエクスポートは gpg --export-secret-key
でできますが、このままだとバイナリデータで出力されます。バイナリでは GitHub のシークレットで扱えないため、テキスト形式で出力する必要があります。 --armor
オプションを指定することで、テキスト形式で出力することができます。
gpg --export-secret-key --armor 'your-key' > private.pem
gpg --help
-a, --armor create ascii armored output
ここで出力した private.pem
の中身をシークレットに登録し、 gpg-private-key
に渡します。すると、このアクションが GPGインポートを実行してくれ、以後のステップで利用できるようになります。
シークレットを登録する
それでは、ワークフローで利用するシークレット情報を登録していきましょう。
GitHub リポジトリの「Settings」>「Secrets」をひらき、「New repository secret」を選択してシークレットを登録します。
ここでは、4つのシークレットを登録します。
シークレット名 | 説明 |
---|---|
MAVEN_USERNAME |
Maven リポジトリに接続するユーザー名 |
MAVEN_USER_PASSWORD |
Maven リポジトリに接続するためのパスワードまたはトークン |
MAVEN_GPG_PASSPHRASE |
GPGキーのパスフレーズ |
MAVEN_GPG_PRIVATE_KEY |
前述で取得した GPG 秘密鍵の中身 |
GitHub Actions のワークフローを書く
さて、百聞は一見に如かずなので、コードを見てみましょう。このコードは下記の動きをします。
- トリガは、リリースが公開されたときの発動を想定(後述の解説参照)
- Java のバージョンは
1.8
、アーキテクチャはx64
対象
ジョブは、 2つ。まずビルドを行い、成功したらデプロイを行います。
- ビルド
- JDK のセットアップ
-
mvn clean package
でビルド
- デプロイ
- GPG キーのインポートを含む、 JDK のセットアップ
-
mvn clean deploy
でデプロイ
name: Release artifacts
on:
release:
types:
# - released
- published
env:
JAVA_VERSION: '1.8'
JAVA_PACKAGE: jdk
JAVA_ARCHITECTURE: x64
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup JDK
uses: actions/setup-java@v1
with:
java-version: ${{ env.JAVA_VERSION }}
java-package: ${{ env.JAVA_PACKAGE }}
architecture: ${{ env.JAVA_ARCHITECTURE }}
- name: Package
run: |
mvn clean package --batch-mode --no-transfer-progress
deploy:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v2
- name: Setup JDK
uses: actions/setup-java@v1
with:
java-version: ${{ env.JAVA_VERSION }}
java-package: ${{ env.JAVA_PACKAGE }}
architecture: ${{ env.JAVA_ARCHITECTURE }}
server-id: dev
server-username: MAVEN_USERNAME
server-password: MAVEN_USER_PASSWORD
gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }}
gpg-passphrase: MAVEN_GPG_PASSPHRASE
- name: Deploy
run: |
mvn clean deploy --batch-mode --no-transfer-progress -DskipTests=true -Dchangelist= -Drevision=${{ github.event.release.tag_name }}
env:
MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
MAVEN_USER_PASSWORD: ${{ secrets.MAVEN_USER_PASSWORD }}
MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
解説
ポイントは、デプロイ時の run
ステップの環境変数の指定です。それぞれの環境変数は、setup-java
アクションの server-username
, server-password
, gpg-passphrase
で指定した文字列を変数名とし値を渡すことで、 settings.xml
で読み込まれ、デプロイ処理に反映されます。
また、 mvn clean deploy
のオプションで、revision
と changelist
プロパティを操作しています。これは、pom.xml で定義したプロパティで、revision
プロパティにリリースタグ ${{ github.event.release.tag_name }}
を渡し、スナップショットの指定を外すため changelist
プロパティを空にしています。
細かい補足はこちらをご参照ください。
- 参考: 補足: リリースのトリガについて
- 参考: 補足:
run
ステップを指定したディレクトリで実行したい場合 - 参考: 補足:
mvn
コマンドのオプション(--batch-mode
,--no-transfer-progress
)
動作確認
ワークフローを push したら、実行させてみましょう!
不必要なリリースの作成はしたくないですが、作業用と割り切って、プレリリースを作成して公開します。このとき、リリースタグの設定は、作業ブランチに対して行ってください。(リリースタグが設定されたブランチに対してワークフローを参照しに行くためです。)
そして、アクションを見てみましょう。
無事にワークフローの実行が完了していれば成功です!👏
補足
mvn deploy
中にパスフレーズを入力させる GUI が出てしまう現象の対処
補足: 前述の pom.xml の maven-gpg-plugin
の設定にあるこの部分、
<configuration>
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
</configuration>
これは、前の記事 でも記載しましたが、 mvn deploy
で GPG 署名を行う際、パスフレーズの入力を促される(※)現象を回避するための記述です。
※ 実際には、下記のような gpg: signing failed: Inappropriate ioctl for device
というエラーメッセージでダイアログを表示できないエラーが発生します。
[INFO] --- maven-gpg-plugin:1.6:sign (sign-artifacts) @ your-artifact ---
gpg: signing failed: Inappropriate ioctl for device
gpg: signing failed: Inappropriate ioctl for device
[INFO] ------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------
[INFO] Total time: 29.957 s
[INFO] Finished at: 2020-12-09T15:54:50Z
[INFO] ------------------------------------------------------------------
Error: Failed to execute goal org.apache.maven.plugins:maven-gpg-plugin:1.6:sign (sign-artifacts) on project your-artifact: Exit code: 2 -> [Help 1]
Error:
Error: To see the full stack trace of the errors, re-run Maven with the -e switch.
Error: Re-run Maven using the -X switch to enable full debug logging.
Error:
Error: For more information about the errors and possible solutions, please read the following articles:
Error: [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
Error: Process completed with exit code 1.
こちらの issue でも話題になってました。
補足: リリースのトリガについて
実際、ワークフローの作成・編集を行っていると、released
のトリガでは扱いにくいです。(作業したいだけなのにリリース打たないとならないのはちょっと…)
なので、今回は下記の方法で作業しました。
- トリガには
on.release.types
にpublished
を指定しておく - 作業ブランチに対してリリースタグを設定し、作業用のプレリリースを作り公開する → ワークフローが作動する
- 再度ワークフローを実行させたいときは、
git push -d origin <tag name>
でタグを消去すると ↑のプレリリースがドラフトに戻るので、再度公開することで発火させる
edited
を指定して、プレリリースの description などを適宜変更して保存する方法でもよいかもしれません。
リリースのトリガについては細部を確認したいので、下記のスクラップで検証状況を掲載しつつ、記事にまとめようと思います。
run
ステップを指定したディレクトリで実行したい場合
補足: GitHub Actions のワークフローで run
ステップを指定したディレクトリで実行したい場合は、 working-directory
で指定します。
- name: Package
run: |
mvn clean package
working-directory: ./path-to-your-project
また、ワークフロー全体で同じディレクトリを指定したい場合は defaults.run.working-directory
で、ジョブ全体で指定したい場合は jobs.<job_id>.defaults.run.working-directory
も利用できます。
defaults:
run:
working-directory: ./path-to-your-project
jobs:
job1:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./path-to-your-project
mvn
コマンドのオプション( --batch-mode
, --no-transfer-progress
)
補足: 用途に寄りますが、mvn
コマンドの下記のオプションが便利そうです。
mvn --help
-B,--batch-mode Run in non-interactive (batch)
mode (disables output color)
-ntp,--no-transfer-progress Do not display transfer progress
when downloading or uploading
Epilogue
ようやく、長かった Java Maven リポジトリへのデプロイの自動化が確立できました!
知らない分野の作業するのは、初動はどうしてもキャッチアップに時間がかかってしまいますが、できるようになると楽しいですね!✨
Discussion