GeekFactory

int128.hatenablog.com

Jenkins GitHub PluginをGitBucketで利用する

JenkinsとGitBucketの連携にGitHub Pluginが使えるか調べてみました。GitBucket APIGitHubと互換性があるので、理論上はGitHub Pluginが使えるはずです。

結論

GitHub互換のURL形式でリダイレクトを設定することで、GitHub PluginでもGitBucketのWebhookを受けてジョブを実行できました。

ただし、GitHub PluginでできることはGitBucket Pluginとほぼ同じです。GitHub PluginのメリットはPipelineに対応していること、CIのステータスを設定できることでしょうか。

方法

ジョブ設定のGit URLに https://gitbucket.example.org/user/repo.git の形式を指定します。これによってGitHub PluginがWebhookを認識できるようになります。

実際にはこのURLでgit fetchできないため、GitBucketのフロントにリバースプロキシを入れて、以下のリダイレクトを設定します。

リダイレクト元 リダイレクト先
https://gitbucket.example.org/user/repo.git https://gitbucket.example.org/git/user/repo.git
https://gitbucket.example.org/user/repo.git/... https://gitbucket.example.org/git/user/repo.git/...

Nginxの場合は以下の設定になります。

  location ~ ^/[^/]+/[^/]+\.git.*$ {
    return 301 https://gitbucket.example.org/git$request_uri;
  }
  location / {
    proxy_pass http://gitbucket:8080;
    #client_max_body_size 略
    #proxy_set_header 略
  }

なぜデフォルトでGitHub Pluginが動作しないのか

なぜリダイレクトを設定しないとGitHub Pluginがジョブを実行しないのか調べてみました。

GitBucketからJenkinsへのWebhookの送信は以下の流れで行われます。

  1. GitBucketがpushイベントのWebhookを https://gitbucket.example.org/jenkins/github-webhook/ にPOSTする。
  2. Jenkins GitHub PluginがWebhookを受信する。
  3. Jenkins GitHub PluginはWebhookからリポジトリ情報を取り出す。
  4. Jenkins GitHub Pluginはリポジトリ情報に対応するジョブを探して実行する。

GitHub PluginがGit URLを解析する実装を見ると、以下のように http://host/user/repo の形式になっていました。

    private static final Pattern[] URL_PATTERNS = {
            /**
             * The first set of patterns extract the host, owner and repository names
             * from URLs that include a '.git' suffix, removing the suffix from the
             * repository name.
             */
            Pattern.compile("git@(.+):([^/]+)/([^/]+)\\.git"),
            Pattern.compile("https?://[^/]+@([^/]+)/([^/]+)/([^/]+)\\.git"),
            Pattern.compile("https?://([^/]+)/([^/]+)/([^/]+)\\.git"),
            Pattern.compile("git://([^/]+)/([^/]+)/([^/]+)\\.git"),
            Pattern.compile("ssh://(?:git@)?([^/]+)/([^/]+)/([^/]+)\\.git"),
            /**
             * The second set of patterns extract the host, owner and repository names
             * from all other URLs. Note that these patterns must be processed *after*
             * the first set, to avoid any '.git' suffix that may be present being included
             * in the repository name.
             */
            Pattern.compile("git@(.+):([^/]+)/([^/]+)/?"),
            Pattern.compile("https?://[^/]+@([^/]+)/([^/]+)/([^/]+)/?"),
            Pattern.compile("https?://([^/]+)/([^/]+)/([^/]+)/?"),
            Pattern.compile("git://([^/]+)/([^/]+)/([^/]+)/?"),
            Pattern.compile("ssh://(?:git@)?([^/]+)/([^/]+)/([^/]+)/?")
    };

ということはジョブ設定のGit URLを http://host/user/repo 形式にする必要があります。GitBucketのGit URLは http://host/git/user/repo なのでGitHubと互換性がないのです。

リバースプロキシのレイヤではなくGitBucketのScalatraでリダイレクトできそうな感じです。Jenkinsに限らず、GitHubと同じ形式のURLでgit fetchできることはメリットがあると思います。Pull Requestを送ってみようかな。

もともと解決したかったこと

GitBucket Pluginを使うとPull Requestをマージした契機でジョブが実行されない問題があります。この問題はGitBucket PluginでもGitHub Pluginでも解決できませんでした。そもそもGitBucketはPull Requestをマージした時にpushイベントを投げないようです。

(23:35追記)Multibranch Pipelineを使うと、Pull Requestのマージを契機にジョブを実行できました。ざっくり以下の方法になります。

  • GitHub互換URLでアクセスできるようにリダイレクトを設定する(上述)
  • GitBucketでWebhookを設定する。 https://git.example.org/jenkins/github-webhook/ に対してpushイベントとpull requestイベントを送信する。
  • Jenkinsの設定でGitHub EnterpriseにGitBucket APIhttps://git.example.org/api/v3)を指定する。
  • JenkinsでMultibranch Pipelineジョブを作成し、ブランチソースにGitHubを追加する。その際にAPI endpointにGitBucketを指定する。

詳しくは別の記事にします。