GeekFactory

int128.hatenablog.com

SonarQube GitHub PluginをGitBucketで使用する(失敗)

SonarQube GitHub Pluginを使うと、静的解析の結果をPull Requestのステータスやコメントに反映できます。この便利な機能がGitBucketでも使えるか試してみましたが、残念ながら無理でした。何かの知見になればと残しておきます。

プラグインはPull Requestで変更されたファイルに対してのみ静的解析を行うようです。

How To Configure SonarQube GitHub Plugin With Jenkins - Stack Overflow

The analysis is automatically filtered based on the files in the pull request. We were testing with pull requests that only had changes in pom.xml and readme files. Once a functional change was introduced, everything lit up on the GitHub Pull Request view as expected.

プラグインはPull Requestで変更されたファイルを取得するため、以下のAPIを利用します。

https://developer.github.com/v3/pulls/#list-pull-requests-files

このAPIはGitBucketでは未実装(404が返される)のため、エラーになります。Gradle SonarQube Pluginを利用している場合はデバッグレベルで実行すると以下のようなログを確認できます。

21:15:42.972 [DEBUG] [sun.net.www.protocol.http.HttpURLConnection] sun.net.www.MessageHeader@5144a1927 pairs: {GET /api/v3/repos/example/hello/pulls/73/comments HTTP/1.1: null}{Authorization: token ****}{Accept-Encoding: gzip}{User-Agent: Java/1.8.0_102}{Host: git.example.com}{Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2}{Connection: keep-alive}
21:15:43.037 [DEBUG] [sun.net.www.protocol.http.HttpURLConnection] sun.net.www.MessageHeader@43fbb6477 pairs: {GET /api/v3/repos/example/hello/pulls/73/files HTTP/1.1: null}{Authorization: token ****}{Accept-Encoding: gzip}{User-Agent: Java/1.8.0_102}{Host: git.example.com}{Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2}{Connection: keep-alive}

今後の機能追加に期待です。Pull Requestの画面ではファイル一覧を表示しているので、APIで返すのはそれほど難しくないかもしれません。

Jenkins MultibranchでPull Requestをビルド

JenkinsのMultibranch Pipelineを利用してPull Requestをビルドしたい場合、ジョブをどのように設定すべきか調べてみました。

Branch SourcesでGitHub *1 を追加すると、以下を選択できます。

  • Build origin branches
  • Build origin branches also filed as PRs
  • Build origin PRs (merged with base branch)
  • Build origin PRs (unmerged head)
  • Build fork PRs (merged with base branch)
  • Build fork PRs (unmerged head)

デフォルトの設定

デフォルトでは以下が選択されています。

  • Build origin branches
  • Build origin branches also filed as PRs
  • Build fork PRs (merged with base branch)

この場合、以下の振る舞いになります。

  • ブランチがpushされたら、ブランチをビルドする。
  • 同一リポジトリでPull Requestが作成されても何もしない。
  • フォークリポジトリからPull Requestを受けた場合は、ベースブランチとマージした上でビルドを行う。(最新版にマージしてビルド)

特に要件がなければ、この振る舞いで問題ないでしょう。

ベースブランチとマージした上でビルドしたい

Pull Requestが作成された場合にベースブランチとマージした上でビルドを行うには、以下を有効にします。

  • Build origin PRs (merged with base branch)
  • Build fork PRs (merged with base branch)

これらを有効にすると、Pull Requestはちゃんとビルドできたけどmasterにマージしたらビルドが失敗した、といったことを予防できます。

ビルド時にPull Requestに関する情報を取得したい

ビルド時にPull Request Numberなどを取得したい場合、以下のいずれかを有効にします。

  • Build origin PRs (merged with base branch)
  • Build origin PRs (unmerged head)

以下の環境変数でPull Requestに関する情報が取得できるようになります。

Key Value
BRANCH_NAME Pull Request Number PR-6
CHANGE_ID Pull Request Number 6
CHANGE_URL Pull RequestのURL
CHANGE_TITLE Pull Requestのタイトル
CHANGE_AUTHOR Pull Requestの作成者
CHANGE_AUTHOR_DISPLAY_NAME Pull Requestの作成者
CHANGE_AUTHOR_EMAIL Pull Requestの作成者
CHANGE_TARGET ベースブランチ master

ビルド時に静的解析を行い、Pull Requestにコメントを付けるといった場合に活用できます。

ただし、ブランチのビルドとPull Requestのビルドが両方とも実行されるため、CIの所要時間が2倍になります。通常のテストはブランチのビルドで行い、Pull Requestにコメントするといった特殊な要件のみPull Requestのビルドで行うとよいと思います。

*1:GitBucketでも使えます

Swagger CodegenでPHPクライアントを生成する

Swagger Codegenが生成するPHPクライアントを使う機会があったので、使い方を記事に残しておきます。

Swagger Codegenが生成するファイル

Swagger CodegenPHPテンプレートを指定すると、以下のファイル群が生成されます。

  • SwaggerClient-php/
    • autoload.php
    • composer.json
    • lib/
      • Api/
        • APIクライアントのクラス群(例: PetApi.php
      • Model/
        • モデルクラス群(例: Pet.php

Petstoreの例が参考になります。 swagger-codegen/samples/client/petstore/php at master · swagger-api/swagger-codegen · GitHub から参照できます。

APIクライアントの使い方

APIクライアントのインスタンスを生成し、メソッドを実行します。

require_once(__DIR__ . '/SwaggerClient-php/autoload.php');

// APIクライアントの生成
$pet_api = new Swagger\Client\Api\PetApi();

// APIの実行
$the_pet = $pet_api->getPetById(1);

この例ではID=1のPetモデルを取得しています。getPetById メソッドはAPIクライアントクラス(PetApi.php)で定義されています。

    /**
     * Operation getPetById
     *
     * Find pet by ID
     *
     * @param int $pet_id ID of pet to return (required)
     * @throws \Swagger\Client\ApiException on non-2xx response
     * @return \Swagger\Client\Model\Pet
     */
    public function getPetById($pet_id)

また、getPetById メソッドが返すモデルはモデルクラス(Pet.php)で定義されています。

/**
 * Pet Class Doc Comment
 *
 * @category    Class
 * @package     Swagger\Client
 * @author      Swagger Codegen team
 * @link        https://github.com/swagger-api/swagger-codegen
 */
class Pet implements ArrayAccess

モデルクラスはArrayAccessを実装しているため、配列としてアクセスできるように設計されています。また、GetterとSetterでもアクセスできるようになっています。

$the_pet->getName();
$the_pet['name'];

$the_pet->setName('foo');
$the_pet['name'] = 'foo';

例外処理

APIが200番台以外のステータスコードを返した場合は例外が発生します。ステータスコードやレスポンスは例外オブジェクトから取得できます。

try {
    $the_pet = $pet_api->getPetById(1);
} catch (Swagger\Client\ApiException $e) {
    echo 'Caught exception: ', $e->getMessage(), "\n";
    echo 'HTTP response headers: ', $e->getResponseHeaders(), "\n";
    echo 'HTTP response body: ', $e->getResponseBody(), "\n";
    echo 'HTTP status code: ', $e->getCode(), "\n";
}

APIクライアントの設定とカスタマイズ

APIクライアントの getConfig メソッドでヘッダやOAuthなどを設定できるようになっています。

$pet_api->getApiClient()->getConfig();

詳しくは swagger-codegen/Configuration.php at master · swagger-api/swagger-codegen · GitHub が参考になります。

今のところ、APIクライアントにはインターセプタの仕組みは用意されていないようです。共通処理を入れたい場合は ApiClient クラスを継承した独自クラスを定義し、APIクライアントのコンストラクタに渡すとよいでしょう。

class MyApiClient extends Swagger\Client\ApiClient
{
    public function callApi($resourcePath, $method, $queryParams, $postData, $headerParams, $responseType = null, $endpointPath = null)
    {
        // TODO: 事前処理
        $response = parent::callApi($resourcePath, $method, $queryParams, $postData, $headerParams, $responseType, $endpointPath);
        // TODO: 事後処理
        return $response;
    }
}
$pet_api = new Swagger\Client\Api\PetApi(new MyApiClient());

依存関係の管理

composer.jsonとautoload.phpが生成されるので、Composerで依存関係を管理することも可能です。ここで力尽きたので詳細は割愛します。