1. 概要

Jenkinsはオープンソースの継続的インテグレーションサーバーであり、特定のタスク/環境用のカスタムプラグイン作成を作成できます。

この記事では、ビルド出力に統計、つまりクラスの数とコードの行を追加する拡張機能を作成するプロセス全体について説明します。

2. 設定

最初に行うことは、プロジェクトを設定することです。 幸いなことに、Jenkinsはそのための便利なMavenアーキタイプを提供しています。

シェルから以下のコマンドを実行するだけです。

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.)

次に、最初のオプションを選択し、インタラクティブモードでグループ/アーティファクト/パッケージを定義します。 その後、 pom.xml に改良を加える必要があります。これには、TODOプラグインなどのエントリが含まれているためです。

3. Jenkinsプラグインの設計

3.1. 拡張ポイント

Jenkinsは、いくつかの拡張ポイントを提供します。これらは、特定のユースケースのコントラクトを定義し、他のプラグインがそれらを実装できるようにするインターフェイスまたは抽象クラスです。

たとえば、すべてのビルドはいくつかのステップで構成されています。 「VCSからのチェックアウト」「コンパイル」「テスト」、 「組み立て」、など。 Jenkinsはhudson.tasks.BuildStep拡張ポイントを定義しているので、それを実装して、構成可能なカスタムステップを提供できます。

もう1つの例は、 hudson.tasks.BuildWrapper です。これにより、事前/事後アクションを定義できます。

また、 hudson.plugins.emailext.plugins.RecipientProvider 拡張ポイントを定義する非コア電子メール拡張プラグインがあり、電子メール受信者を提供できます。 実装例は、hudson.plugins.emailext.plugins.recipients.UpstreamComitterRecipientProviderにあります。

注:プラグインクラスがhudson.Pluginを拡張する必要があるレガシーアプローチがあります。 ただし、代わりに拡張ポイントを使用することをお勧めします。

3.2. プラグインの初期化

ジェンキンスに私たちの拡張機能とそれをインスタンス化する方法について伝える必要があります。

まず、プラグイン内で静的内部クラスを定義し、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によって自動的に配信されます。

例えば Mavenプラグインを検討してください。

@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<FilePath> 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テンプレートを作成しましょう。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>$PROJECT_NAME$</title>
</head>
<body>
Project $PROJECT_NAME$:
<table border="1">
    <tr>
        <th>Classes number</th>
        <th>Lines number</th>
    </tr>
    <tr>
        <td>$CLASSES_NUMBER$</td>
        <td>$LINES_NUMBER$</td>
    </tr>
</table>
</body>
</html>

そして、ビルド中にそれを移入します:

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がローカル環境で稼働していることを前提としています。 それ以外の場合は、インストールの詳細を参照してください。

5.1. プラグインをJenkinsに追加します

それでは、プラグインを作成しましょう。

mvn install

これにより、targetディレクトリに*。hpiファイルが作成されます。 Jenkinsプラグインディレクトリ(デフォルトでは〜/ .jenkins / plugin )にコピーする必要があります。

cp ./target/jenkins-hello-world.hpi ~/.jenkins/plugins/

最後に、サーバーを再起動して、プラグインが適用されていることを確認しましょう。

  1. http:// localhost:8080でCIダッシュボードを開きます
  2. Jenkinsの管理に移動します| プラグインの管理| インストール済み
  3. プラグインを探す

5.2. Jenkinsジョブを構成する

オープンソースのApachecommons-langプロジェクトの新しいジョブを作成し、そこでGitリポジトリへのパスを構成しましょう。

また、そのためのプラグインを有効にする必要があります。

5.3. 結果を確認する

これですべての設定が完了しました。どのように機能するかを確認しましょう。

プロジェクトをビルドして、結果に移動できます。 stats.htmlファイルがここで利用可能であることがわかります。

それを開きましょう:

それが私たちが期待していたことです。3行のコードを持つ単一のクラスです。

6. 結論

このチュートリアルでは、 Jenkins プラグインを最初から作成し、それが機能することを確認しました。

当然、CI拡張機能の開発のすべての側面を網羅しているわけではなく、基本的な概要、設計のアイデア、および初期設定を提供しただけです。

そして、いつものように、ソースコードはGitHubにあります。