【Gradle】プロジェクトの設定をPluginで共通化

複数のGradleのプロジェクトを管理しているとき、
「共通的な設定をひとまとめにして管理したい」と思ったことはないでしょうか?

それ、Gradleプラグインで実現できます!

プラグインで共通化をすることで、一気に更新をかけなければいけないなんて時の手間が数分の1ですみますし、
重要な設定の設定モレ・ミスなんてこともなくなります!

この記事では、Gradleプラグインの基本的な作り方から、やりたいことベースで実装方法を紹介していきます!

プラグイン作成

まずは簡単なプラグインを作ってみましょう!

Hello, gradle pluginと表示するだけのhelloタスクを追加するプラグインを作ってみたいと思います。

プラグイン提供側

まずはプラグイン側の作業です。

build.gradleとプラグインのメインクラスを作成します!

plugins {
    // 開発言語としてgroovyを指定
    // build.gradleがgroovyで記載されているので、感覚が近いかなと
    id 'groovy'
    // プラグイン開発時に必要なプラグイン
    id 'java-gradle-plugin'
    // Mavenへpublishするために必要(今回はlocalリポジトリを利用)
    id 'maven-publish'
}

group 'sample'
version '1.0.0'
sourceCompatibility = 17

gradlePlugin {
    plugins {
        mySamplePlugin {
            // プラグイン利用時の識別子
            // 「apply plugin: 'xxxxx'」のやつ
            id = 'sample.sample-gradle-plugin'
            // プラグインの実装クラスを指定
            implementationClass = 'sample.SampleGroovyPlugin'
        }
    }
}

repositories {
    mavenCentral()
}

dependencies {
    // プラグイン開発に必要な依存を自動で取り込んでくれる設定です
    gradleApi()
}

// maven利用のための設定
publishing {
    publications {
        mavenPlugin(MavenPublication) {
            artifactId = 'sample-gradle-plugin'

            from components.java
        }
    }
}
package sample

import org.gradle.api.Plugin
import org.gradle.api.Project

// パッケージ・クラス名は「implementationClass」と対応させる
class SampleGroovyPlugin
        // Plugin<Project>を実装する
        implements Plugin<Project> {
    @Override
    void apply(Project project) {
        // タスクの追加方法
        project.tasks.create('hello') {
            doLast {
                println('Hello, gradle plugin')
            }
        }
    }
}

ここまでできたら以下のコマンドでmavenリポジトリにuploadしましょう!
※この記事ではmaven localを使用します。

$ ./gradlew publishToMavenLocal

# 通常のリポジトリ使用時はこちら
$ ./gradlew publish

プラグイン利用側

maven repository (ローカルや社内リポジトリ含め)にプラグインのjarファイルをアップロードをしている場合、
buildscriptでプラグインの取得元を指定してあげる必要があります。

buildscript {
	repositories {
		// プラグインのpublish先を指定(今回はローカルリポジトリ)
		mavenLocal()
	}
	dependencies {
		// 開発したプラグインのgroup.project name.version
		classpath 'sample:sample-gradle-plugin:1.0.0'
	}
}

// idで指定した識別子でプラグインを適用
apply plugin: 'sample.sample-gradle-plugin'

これでhelloタスクが追加され、実行すると…

> Task :app:hello
Hello, gradle plugin

🎉🎉🎉🎉🎉

逆引き実装例

ここからはやりたいことベースで実装方法を紹介していきます!

実際に僕が現場のプロジェクトの共通化をしたときの実装を例にあげていきますね!

自作プラグインの動作を設定可能に

プラグインの利用者側で

hello {
    message = 'plugin extention'
}

のように設定すると、messageを元にメッセージを出力するようにしてみます。

まずはExtensionを作成します。
読み込ませたい設定をフィールドに持つクラスを作成するだけです!

class HelloExtension {
    String message
}

次に作成したExtensionをProjectに登録します。

    @Override
    void apply(Project project) {
        // extensionを登録
        project.extensions.create("hello", HelloExtension)

        project.tasks.create('hello') {
            doLast {
                // extensionの読み込みは`project.extensions.getByXxxx`を使う
                println("Hello, ${project.extensions.getByType(HelloExtension.class).message}")
            }
        }
    }

プラグインの設定を変更する

設定変更は本家プラグイン側の実装方針によっていろいろあるので、中身を追う必要があります。

例えばbootJarに以下のような設定を追加したい場合

bootJar {
	classifier = 'sample'
}

classifierの中身を追ってみます。IntellijであればCtrl(Win) or Cmd(Mac)を押しながらクリックすると実装内容が見れます。

// ①:taskで定義されていそう
public abstract class AbstractArchiveTask extends AbstractCopyTask {
    ...
    // ③:archiveClassifierはproperty
    private final Property<String> archiveClassifier;
    ...
    @Deprecated
    public void setClassifier(@Nullable String classifier) {
        this.archiveClassifier.convention(classifier);
        // ②:archiveClassifierという変数に値を設定している
        this.archiveClassifier.set(classifier);
    }
    ...
}

つまり、「bootJarタスク」の「archiveClassifier」プロパティを変更すればよいことが分かります。

これを実装するとこんな感じ!

    @Override
    void apply(Project project) {
        // 利用者側で設定可能なのはこっち
        project.tasks.getByName('bootJar').property('classifier', 'custom')

        // 利用者側の設定も上書きしちゃうのはこっち
        project.afterEvaluate {
            project.tasks.getByName('bootJar').setProperty('classifier', 'custom')
        }
    }

※いくつかパターンがありそうなので発見次第追記予定

プラグインの追加

Checkstyleというコードフォーマットをテストしてくれるプラグインを入れる例です!

build.gradle

plugins {
    id 'checkstyle'
}

プラグイン実装

    @Override
    void apply(Project project) {
        project.plugins.apply('checkstyle')
    }

依存の追加

lombokを依存に追加する例です!

build.gradle

dependencies {
	compileOnly 'org.projectlombok:lombok'
	annotationProcessor 'org.projectlombok:lombok'
}

プラグイン実装

    @Override
    void apply(Project project) {
        project.dependencies {
            compileOnly 'org.projectlombok:lombok'
            annotationProcessor 'org.projectlombok:lombok'
        }
    }

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です