はじめまして、モバイルエンジニアの久保出と言います。
今回、社内Mavenリポジトリを利用しやすくするために、Gradleを拡張するライブラリを作成したのでその手法をご紹介します。
前提として、gradle.ktsでのみ利用可能な内容になっています。
経緯
Wantedlyでは、社内のプライベートなライブラリ群を利用するためにAWS S3上にMavenリポジトリが存在します。
プライベートなので当然S3の認証がかかっています。ローカルでの開発環境ではlocal.propertiesに認証情報を、CIでは環境変数に認証情報を置く運用にしているため、Gradleでリポジトリを利用できるようにするには次のような長い記述が必要で、build.gradle.ktsの可読性を下げる一因になっていました。
// build.gradle.kts
fun getProp(name: String): String? {
return rootProject.file("local.properties")
.takeIf { it.exists() }
?.let { Properties().apply { load(it.reader()) }.getProperty(name) }
?: System.getenv(name)
}
val wtdMavenAccessKey = getProp("WTD_MAVEN_ACCESS_KEY")
val wtdMavenSecretKey = getProp("WTD_MAVEN_SECRET_KEY")
repositories {
maven {
url = uri("s3://foo.s3.amazonaws.com")
credentials(AwsCredentials::class) {
accessKey = wtdMavenAccessKey
secretKey = wtdMavenSecretKey
}
content {
includeGroupByRegex("""com\.wantedly.*""")
}
}
}
dependencies {
implementation("com.wantedly.foo:bar:baz")
}
社内ライブラリを配布または利用したいとき、それぞれのGitリポジトリのbuild.gradle.ktsにこの記述をしなければなりません。また、今後もしGitHub Packagesに移行するようなことがあれば、すべてのbuild.gradle.ktsを大きく書き換える必要が出てきます。
話は変わりますが、Androidエンジニアなら誰でも、次のようなgoogle()を使ったことがあると思います。
repositories {
google()
}
google()と同じようにwantedly()と記述できれば、記述はスッキリするし、なんとなくイケてる感じがしそうだと思ったのが今回の話の始まりです。
導入した結果
先に前述のコードが最終的にどうなったかを次に書きます。
// build.gradle.kts
import com.wantedly.maven.repository.wantedly
buildscript {
repositories {
jcenter()
}
dependencies {
classpath("com.wantedly:wantedly-maven-repository:0.0.2")
}
}
repositories {
wantedly()
}
dependencies {
implementation("com.wantedly.foo:bar:baz")
}
以前と比べると非常にスッキリしたと思います。
GitHub Packagesに移行するようなことがあっても、このwantedly-maven-repositoryのバージョンを上げれば対応でき、大きな変更が不要になるというメリットもあります。
実装
実際にこれをどうやったかというと、単にGradleを拡張するライブラリをOSSで作成し、JCenterに登録しただけです。
実装の手順を説明します。
$ gradle init
を適当なディレクトリで実行します。
何を作成するか聞かれるので、Gradle plugin、Kotlin、Kotlinを選択しましょう。
$ gradle init
Select type of project to generate:
1: basic
2: application
3: library
4: Gradle plugin
Enter selection (default: basic) [1..4] 4
Select implementation language:
1: Groovy
2: Java
3: Kotlin
Enter selection (default: Java) [1..3] 3
Select build script DSL:
1: Groovy
2: Kotlin
Enter selection (default: Kotlin) [1..2] 2
これでGradle Pluginのプロジェクトが出来上がりました。gradle initはこういう場合非常に便利です。
次に、build.gradle.ktsを次のように変更します。
実際にBintrayへアップロードして、JCenterにリンクする記述はここでは省略します。
// build.gradle.kts
plugins {
`kotlin-dsl`
id("org.jetbrains.kotlin.jvm") version "1.3.70"
id("com.jfrog.bintray") version "1.8.4"
`maven-publish`
}
repositories {
jcenter()
}
dependencies {
compileOnly(gradleApi())
implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
implementation(kotlin("gradle-plugin"))
implementation(kotlin("stdlib-jdk8"))
}
もともとあったgradlePlugin {}の記述は不要なので消します。
Gradle Pluginを作るのではなく、GradleのAPIを拡張するのが目的だからです。
次にsrc/main/kotlinに生成された**Plugin.ktを編集します。
前述の通りPlugin自体は作らないので、RepositoryHandlerの拡張関数のみを書きます。
// **Plugin.kt
private fun getProp(name: String): String? {
return File("local.properties")
.takeIf { it.exists() }
?.let { Properties().apply { load(it.reader()) }.getProperty(name) }
?: System.getenv(name)
}
private val wtdMavenAccessKey = getProp("WTD_MAVEN_ACCESS_KEY")
private val wtdMavenSecretKey = getProp("WTD_MAVEN_SECRET_KEY")
fun RepositoryHandler.wantedly(): MavenArtifactRepository {
return maven {
url = URI("s3://foo.s3.amazonaws.com")
credentials(AwsCredentials::class) {
accessKey = wtdMavenAccessKey
secretKey = wtdMavenSecretKey
}
content {
includeGroupByRegex("""com\.wantedly.*""")
}
}
}
後は適切にpublishするための設定をして、Bintrayへアップロード、JCenterへリンクするだけです。
手法は省略しますので、Bintrayの公式ドキュメントなどを見てください。
メリット
- 他のライブラリをpublishするときにも利用できる。
- GitHub Packagesに移行するようなことがあっても、バージョンを上げれば対応でき、大きな変更が不要になる。
- 認証情報の環境変数名やプロパティ名を統一できる。
- Googleに並ぶというちょっとした優越感も得られる。
まとめ
社内Mavenリポジトリを使いやすくする手法をご紹介しました。
同じように社内Mavenリポジトリを運用している人の助けになれば幸いです。