Jenkinsプラグインの作成
1. 概要
Jenkinsはオープンソースの継続的インテグレーションサーバーであり、特定のタスク/環境用のカスタムプラグイン作成を作成できます。
この記事では、ビルド出力に統計情報、つまりクラス数とコード行を追加する拡張機能を作成するプロセス全体について説明します。
2. セットアップ
最初に行うことは、プロジェクトをセットアップすることです。 そのためのLuckily, Jenkins provides convenient Maven archetypes。
以下のコマンドをシェルから実行するだけです:
mvn archetype:generate -Dfilter=io.jenkins.archetypes:plugin
次の出力が得られます。
[INFO] Generating project in Interactive mode
[INFO] No archetype defined. Using maven-archetype-quickstart
(org.apache.maven.archetypes:maven-archetype-quickstart:1.0)
Choose archetype:
1: remote -> io.jenkins.archetypes:empty-plugin (Skeleton of
a Jenkins plugin with a POM and an empty source tree.)
2: remote -> io.jenkins.archetypes:global-configuration-plugin
(Skeleton of a Jenkins plugin with a POM and an example piece
of global configuration.)
3: remote -> io.jenkins.archetypes:hello-world-plugin
(Skeleton of a Jenkins plugin with a POM and an example build step.)
ここで、最初のオプションを選択し、対話モードでグループ/アーティファクト/パッケージを定義します。 その後、<name>TODO Plugin</name>などのエントリが含まれているため、pom.xmlを改良する必要があります。
3. Jenkinsプラグインの設計
3.1. 拡張ポイント
Jenkins provides a number of extension points.これらは、特定のユースケースのコントラクトを定義し、他のプラグインがそれらを実装できるようにするインターフェイスまたは抽象クラスです。
たとえば、すべてのビルドはいくつかのステップで構成されます。 “Checkout from VCS”、“Compile”、“Test”,“Assemble”,など。 Jenkinsはhudson.tasks.BuildStep拡張ポイントを定義しているので、それを実装して、構成可能なカスタムステップを提供できます。
もう1つの例はhudson.tasks.BuildWrapperです。これにより、事前/事後アクションを定義できます。
また、hudson.plugins.emailext.plugins.RecipientProvider拡張ポイントを定義する非コアEmail Extensionプラグインがあり、これにより電子メール受信者を提供できます。 実装例はここにあります:hudson.plugins.emailext.plugins.recipients.UpstreamComitterRecipientProvider。
注:プラグインクラスがhudson.Pluginを拡張する必要があるレガシーアプローチがあります。 ただし、it’s now recommended to use extension points instead.
3.2. プラグインの初期化
拡張機能とそのインスタンス化方法についてJenkinsに伝える必要があります。
まず、プラグイン内で静的内部クラスを定義し、hudson.Extensionアノテーションを使用してマークを付けます。
class MyPlugin extends BuildWrapper {
@Extension
public static class DescriptorImpl
extends BuildWrapperDescriptor {
@Override
public boolean isApplicable(AbstractProject, ?> item) {
return true;
}
@Override
public String getDisplayName() {
return "name to show in UI";
}
}
}
次に、プラグインのオブジェクトのインスタンス化に使用するコンストラクターを定義し、org.kohsuke.stapler.DataBoundConstructorアノテーションでマークする必要があります。
パラメータを使用することができます。 それらはUIに表示され、Jenkinsによって自動的に配信されます。
E.g. Maven pluginを考慮してください:
@DataBoundConstructor
public Maven(
String targets,
String name,
String pom,
String properties,
String jvmOptions,
boolean usePrivateRepository,
SettingsProvider settings,
GlobalSettingsProvider globalSettings,
boolean injectBuildVariables) { ... }
次のUIにマッピングされています。
セッターでorg.kohsuke.stapler.DataBoundSetterアノテーションを使用することもできます。
4. プラグインの実装
ビルド中に基本的なプロジェクト統計を収集する予定なので、hudson.tasks.BuildWrapperがここに行く正しい方法です。
それを実装しましょう:
class ProjectStatsBuildWrapper extends BuildWrapper {
@DataBoundConstructor
public ProjectStatsBuildWrapper() {}
@Override
public Environment setUp(
AbstractBuild build,
Launcher launcher,
BuildListener listener) {}
@Extension
public static class DescriptorImpl extends BuildWrapperDescriptor {
@Override
public boolean isApplicable(AbstractProject, ?> item) {
return true;
}
@Nonnull
@Override
public String getDisplayName() {
return "Construct project stats during build";
}
}
}
さて、実際の機能を実装する必要があります。
プロジェクト統計のドメインクラスを定義しましょう。
class ProjectStats {
private int classesNumber;
private int linesNumber;
// standard constructors/getters
}
そして、データを構築するコードを書きます。
private ProjectStats buildStats(FilePath root)
throws IOException, InterruptedException {
int classesNumber = 0;
int linesNumber = 0;
Stack toProcess = new Stack<>();
toProcess.push(root);
while (!toProcess.isEmpty()) {
FilePath path = toProcess.pop();
if (path.isDirectory()) {
toProcess.addAll(path.list());
} else if (path.getName().endsWith(".java")) {
classesNumber++;
linesNumber += countLines(path);
}
}
return new ProjectStats(classesNumber, linesNumber);
}
最後に、エンドユーザーに統計を表示する必要があります。 そのためのHTMLテンプレートを作成しましょう。
$PROJECT_NAME$
Project $PROJECT_NAME$:
Classes number
Lines number
$CLASSES_NUMBER$
$LINES_NUMBER$
そして、ビルド中にそれを投入します:
public class ProjectStatsBuildWrapper extends BuildWrapper {
@Override
public Environment setUp(
AbstractBuild build,
Launcher launcher,
BuildListener listener) {
return new Environment() {
@Override
public boolean tearDown(
AbstractBuild build, BuildListener listener)
throws IOException, InterruptedException {
ProjectStats stats = buildStats(build.getWorkspace());
String report = generateReport(
build.getProject().getDisplayName(),
stats);
File artifactsDir = build.getArtifactsDir();
String path = artifactsDir.getCanonicalPath() + REPORT_TEMPLATE_PATH;
File reportFile = new File("path");
// write report's text to the report's file
}
};
}
}
5. 使用法
これまでに作成したすべてのものを組み合わせて、実際の動作を確認するときが来ました。
Jenkinsがローカル環境で稼働していることを前提としています。 それ以外の場合は、installation detailsを参照してください。
5.1. プラグインをJenkinsに追加します
それでは、プラグインを作成しましょう。
mvn install
これにより、targetディレクトリに*.hpiファイルが作成されます。 Jenkinsプラグインディレクトリ(デフォルトでは~/.jenkins/plugin)にコピーする必要があります。
cp ./target/jenkins-hello-world.hpi ~/.jenkins/plugins/
最後に、サーバーを再起動して、プラグインが適用されていることを確認しましょう。
-
http://localhost:8080でCIダッシュボードを開く
-
Manage Jenkinsに移動します| Manage Plugins | Installed
-
プラグインを見つける
5.2. Jenkinsジョブを構成する
オープンソースのApachecommons-langプロジェクトの新しいジョブを作成し、そこでGitリポジトリへのパスを構成しましょう。
そのためにプラグインを有効にする必要もあります。
6. 結論
このチュートリアルでは、Jenkinsプラグインを最初から作成し、それが機能することを確認しました。
当然、CI拡張機能の開発のすべての側面を網羅しているわけではなく、基本的な概要、設計のアイデア、および初期設定を提供しただけです。
そして、いつものように、ソースコードはover on GitHubで見つけることができます。