プルリクエストのバックポートで負け犬からヒーローへ

Red Hat で Solution Architect として Quarkus を担当している伊藤ちひろ(@chiroito)です。

この記事は、Quarkus.io のブログ記事、From zero to hero on backporting pull requests の翻訳記事です。

Quarkus プロジェクトの動きは速いです。バグフィックスリリースを準備するときには、通常、バックポートするためのプルリクエストが数十件発生します。バックポートするためのプルリクエストの数は膨大です。GitHub の UI を使って行うのは不便ですし、時間もかかります (PR をクリックし、コミットハッシュを入念に選択してコピー/貼り付けて、ラベルを削除し、マイルストーンを割り当て、すべての修正済みの課題にマイルストーンを割り当て、次へ)。また、UI にはいくつかの制限があります。そこで、この作業を自動化することにして、アプリケーションを構築しました。もちろん、Quarkus と一緒です!

解決策を掘り下げる前に、リリースのプロセスを簡単に説明します。

リリースプロセス

Quarkus チームは、メジャー.マイナー.パッチ.分類子(例:1.7.0.CR1、1.7.0.Final)のバージョンパターンを採用しています。上がったバージョンによって、異なるプロセスが採用されています。

メジャーとマイナーのリリース

私たちのマスターブランチは、次のメジャー、マイナーリリースに向けて常に準備ができています。このプロセスは通常、非常にスムーズで、バックポートを伴いません。

パッチや分類子のリリース

Quarkus で新しいパッチが適用されたバージョン(または2つ目のCR)がリリースされるたびに、リリースチームはマスターブランチにマージされたプルリクエストからのコミットをバックポートし始めます。彼らはどうやってどのプルリクエストを得るのかを知っているのでしょうか?私たちはトリアージ/バックポートのラベルがあります?このラベルは今後のパッチリリースで使用する価値のある機能のリクエストを引き出すためにチームが追加するものです。

どうやって自動化するの?

このアプリケーションは基本的に、GitHub リポジトリのマージされたプルリクエストと、特定のラベルを含むクローズ済みの課題を照会します(GitHubが公開しているGraphQL APIを使用)。そして、それらのマイルストーンを UI で選択したものに変更します(その後、特定のラベルを削除します)。これらのプルリクエスト (別名:チェリーピック) でもたらされた変更を適用することは、各プルリクエストの隣にボタンを用意して、必要な git cherry-pick コマンドをクリップボードにコピーすることで簡単になりました。このステップは、リリースエンジニアが手動で行うことを推奨します。

スクリーンショット

マイルストーンの選択

https://raw.githubusercontent.com/quarkusio/quarkus-backports/master/documentation/screenshots/index.png

バックポートするプルリクエストの選択

https://raw.githubusercontent.com/quarkusio/quarkus-backports/master/documentation/screenshots/backports.png

Quarkusの実績

ここでは、バックポートアプリケーションで使用されている拡張機能の概要を紹介しています。

  • ArC (CDI):サービスのライフサイクルを管理
  • MicroProfile Config:プロパティを外部化
  • RESTEasy:UI が消費できるエンドポイントを公開また、Qute のType-safe テンプレートを使ったUIも提供(Qute参照)
  • Qute:すべてのテンプレート(UI および GraphQL クエリ ペイロード)で使用
  • Rest Client:GitHub の GraphQL エンドポイントを呼び出す
  • Cache:GitHub の GraphQL エンドポイントから開いているマイルストーンをキャッシュ
  • Hibernate Validator:入力の有効性を確認
  • Jackson (JSON ライブラリ):GitHub GraphQL エンドポイントから結果をパース

ライブコーディング

ライブコーディングは Quarkus の素晴らしい機能で、開発中にクラスやメソッドが変更されている間に素早くフィードバックを提供してくれました。経験則として、Quarkus アプリケーションの開発中は常に ./mvnw quarkus:dev を使用してください。

MicroProfile Config

どの GitHub リポジトリを使うか (テストを使うか、Quarkus 以外のリポジトリを使うか) と GitHub 認証トークン (必要に応じて別のバックポートラベルも) を設定すれば、ソースコードを変更することなく簡単に設定できるはずです。Quarkus は Microprofile Config を使用しているので、これらのプロパティを外部化しました。Quarkus は .env ファイルもサポートしており、テスト中に使用しました。これにより、アプリケーションを実行する前に application.properties を直接変更したり、環境やシステムのプロパティを設定したりする必要がないため、ローカルテストが簡単になりました。

Qute

Qute はテンプレートエンジンです。UI を生成したり、GraphQL 変数を使うだけでは不十分な場合に GraphQL クエリを生成するために使用しました。例えば、課題番号のリストから課題データを取得します型安全のテンプレートを使って UI と GraphQL クエリを生成しました。

Rest Client

GraphQL とは、簡単に言えば、JSON データを HTTP エンドポイントに POST し、その結果を JSON ドキュメントとして解析することを意味します。単純にそれだけです。Microprofile REST Client は、このタスクを実行するのに適しているということで、こんなことを思いつきました。

import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.core.HttpHeaders;

import io.vertx.core.json.JsonObject; 
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

@RegisterRestClient(baseUri = "https://api.github.com/graphql") public interface GraphQLClient {

    @POST
    JsonObject graphql(@HeaderParam(HttpHeaders.AUTHORIZATION) String authentication, JsonObject query);
}

GitHubService で GraphQLClient オブジェクトを使えるようになりました。

    @Inject
    @RestClient
    GraphQLClient graphQLClient;

クライアントがどのように起動されるかは、ここで見ることができます。

次のステップ

動的クエリの性質を考えると、SmallRye GraphQL 拡張機能は使わないことにしました。ですが、拡張機能がその機能をサポートするようになれば、変更できます。

感謝

このアプリケーションは開発に約 1 週間かかりました(GraphQLの学習も含まれています)。それが可能になったのは、以下の Quarkus チームのメンバーのおかげです。

  • https://github.com/gsmet.png?v=3&s=96 Guillaume Smet 氏:美しいフロントエンドの仕事
  • https://github.com/gastaldi.png?v=3&s=96 George Gastaldi 氏:バックエンドの開発と GraphQL の統合を楽しむ
  • https://github.com/dmlloyd.png?v=3&s=96 David Lloyd 氏:コミットメッセージで課題番号を抽出するために必要なクレイジーな正規表現

詳細情報

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません。その内容については非公式見解を含みます。