minne 事業部で Android アプリエンジニアをやっている tick-taku です。
この投稿では GitHub Enterprise Server (以下 GHES) の GitHub Packages を Maven リポジトリとして利用し、Gradle で Android アプリに導入するまでを公開します。
概要
Android でライブラリを利用しようと思うと Gradle で mavenCentral などからインポートすることになりますが、「ライブラリを社内を横断して配布したい、でも外部公開したくない」と言ったケースがありました。そのため、社内で利用している GHES の GitHub Packages を利用してクローズドな環境にライブラリをホストして、Gradle でインポートすることにしました。
提供するライブラリ側の設定と Android プロジェクトで利用するまでを解説していきます。
アップロードする Android ライブラリの準備
まずは GitHub Packages にホストする Android のライブラリを作成しましょう。Android プロジェクトを作成し、New Module
から Android Library module を作成します。
今回は以下のようにサービスごとにインポートする module を用意する構成としました。interface などを core
module に定義し提供する口はそろえ、core module の依存を伝搬するように内部実装はサービスに合わせた module を作成します。sample
module は API の使用例を載せています。
.
├── buildSrc
├── core
├── minne
├── sample
└── suzuri
最後に作成したプロジェクトをリポジトリに push しましょう。
GitHub Packages へのアップロード
maven publish plugin のセットアップ
準備で作成したライブラリを GitHub Packages へアップロードするため、プラグインを導入します。今回は gradle-maven-publish-plugin を利用してアップロードします。pom.xml に必要な情報を gradle.properties にまとめられ管理しやすい点を評価しています。
まずは ルートの build.gradle
に classpath を追加します。
buildscript {
dependencies {
classpath "com.vanniktech:gradle-maven-publish-plugin:0.18.0"
}
}
次にアップロードする module の build.gradle にプラグインのセットアップをします。
plugins {
id 'com.vanniktech.maven.publish'
}
android {
...
}
dependencies {
api project(':core')
}
mavenPublish {
releaseSigningEnabled = false
sonatypeHost = null
}
最後に gradle.propeties を用意して pom.xml の情報を記載します。
VERSION_NAME=0.0.1
GROUP=pepabo.mobile.hoge
POM_PACKAGING=aar
また各 module 内に artifactId をわける必要があるため gradle.propeties を用意します。今回 VERSION_NAME をルートの gradle.properties に指定していますが、こちらに指定すると各 module ごとに version が管理できます。
POM_ARTIFACT_ID=minne
maven の認証設定
Maven リポジトリとして GitHub Packages を利用するにあたり、maven の向き先と認証情報を定義する必要があります。
publishing {
repositories {
maven {
name = "GitHubPackages"
url = uri("https://maven.<GHES のドメイン>/<organization>/<Repository Name>")
credentials {
username = "<GHES のユーザ名>"
password = "<Parsonal Access Token>"
}
}
}
}
name
は GitHubPackages
固定です。url にはリポジトリの GitHub Packages の URL を指定します。GitHub Packages の URL のドメインの最初に maven.
をつけたものになると思います。
credentials
に GHES の認証情報を記載します。認証には Parsonal Access Token (以下 PAT)が必要になるので準備しておきましょう。scope は repo
、 write:packages
、read:packages
を指定して発行します。username
には GHES のユーザ名、password
には発行した PAT を指定します。
おそらく本番のプロダクトでは GitHub Actions など CI/CD でビルドしたりしていると思います。ペパボでも GitHub Actions を利用しているので Secrets にそれぞれを登録しておき Actions で環境変数にセットして呼び出すようにしています。また、 ローカル環境でもビルドしたいので以下のように環境変数を設定しておきます。
credentials {
username = System.getenv("PACKAGES_ACCESS_NAME")
password = System.getenv("PACKAGES_ACCESS_TOKEN")
}
export PACKAGES_ACCESS_NAME=<GHES のユーザ名>
export PACKAGES_ACCESS_TOKEN=<Parsonal Access Token>
ここで個人のトークンを利用していると、例えばその方が退職したりしてユーザが存在しなくなった場合 CI でのビルドが失敗します。それは困るので、ペパボでは pepabot
と言う bot ユーザが存在していてそのアカウントのアクセストークンを Secrets に登録し利用しています。
アップロードの確認
以上で公開の設定は完了なので実際にアップロードしてみます。プロジェクトのルートディレクトリで以下のコマンドを実行します。
./gradlew :minne:publish --no-daemon --no-parallel
success と出たらアップロード完了です。Repository の GitHub Packages を確認するとアップロードした module が登録されているはずです。
プロジェクトへの導入
アップロードと同様の認証情報をルートの build.gradle
に設定します。また、ここで必要となる PAT の scope は read:packages
なので発行しておきましょう。ペパボではこちらもアップロードと同様に PAT を環境変数と Secrets にセットして運用しています。
allprojects {
repositories {
maven {
name = "GitHubPackages"
url = uri("https://maven.<GHES のドメイン>/<organization>/<Repository Name>")
credentials {
username = "<GHES のユーザ名>"
password = "<Parsonal Access Token>"
}
}
}
}
最後に使用する module の build.gradle
に依存関係を追加して Sync Project
を実行するとライブラリが利用できるようになります。dependencies にアップロードしたライブラリを追加しましょう。groupId や artifactId は maven publish plugin のセットアップで用意した gradle.properties の GROUP
や POM_ARTIFACT_ID
になります。
dependencies {
implementation '<groupId>:<artifactId>:<version>'
}
以上で、GHES の GitHub Packages にアップロードしたライブラリをプロジェクトで利用する方法でした。
GitHub Actions を利用したライブラリの自動アップロード
最後にタグを push したときにライブラリを自動でアップロードする Actions を紹介します。
当然毎回ライブラリを手動でリリースするのも大変なので GitHub Actions を利用して何らかのトリガーで自動でアップロードしたくなります。x.y.z
の形式のタグが push されたら gradle.propaties の VERSION_NAME
をリプレイスしてコミットし、リリースコマンドを実行します。あとは例えば master にマージされるとタグを push する Actions と併用すると PR が master にマージされるとインクリメントしてリリースすることが可能です。
name: Deploy to GitHub Packages
on:
push:
tags:
- '[0-9]*.[0-9]*.[0-9]*'
jobs:
build_and_deploy:
runs-on: normal
container:
image: <docker image>
steps:
- uses: actions/checkout@v2
with:
ref: master
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Update version
run: |
sed -i "s/VERSION_NAME=[0-9]*.[0-9]*.[0-9]*/VERSION_NAME=${GITHUB_REF#refs/tags/}/g" ./gradle.properties
rm -rf gradle.propreties-e
git config user.name "<user name>"
git config user.email "<メールアドレス>"
git add .
git commit -m "Update version ${GITHUB_REF#refs/tags/}"
git push
- name: Clean build
run: ./gradlew clean build
- name: Deploy
run: |
./gradlew :core:publish --no-daemon --no-parallel
./gradlew :minne:publish --no-daemon --no-parallel
./gradlew :suzuri:publish --no-daemon --no-parallel
env:
PACKAGES_ACCESS_NAME: ${{ secrets.PACKAGES_ACCESS_NAME }}
PACKAGES_ACCESS_TOKEN: ${{ secrets.PACKAGES_ACCESS_TOKEN }}
まとめ
以上が Android のライブラリを社内ホストしている GHES の GitHub Packages にアップロードして Android プロジェクトで利用するまでの流れになります。
これにより、例えば暗号化処理でアルゴリズムは社内全体で共通化する方針となったときなどにクローズドにしておきたいライブラリを事業部を横断して利用できるようになるため各リポジトリ内に分散していたコードが一元管理でき実装コストも下がりますし、プロジェクトで閉じていたコードが事業部外のメンバーからのフィードバックを得やすくなりよりパフォーマンスを高めることも期待できます。
その他ペパボでは RubyGem レジストリとしても利用 しています。また、今は GitHub Packages が対応していませんが Swift や Dart が対応されれば iOS や Flutter でも同様にライブラリをホストしていきたいと考えています。