メインコンテンツへスキップ
このドキュメントでは、ClickHouseのバックポートポリシーと、それを実装する自動化システムについて説明します。

リリースモデル

ClickHouse のバージョンは YY.M.patch.build-type という形式に従います。ここで、YY は西暦の下 2 桁、M はリリース月 (先頭に 0 は付きません) 、patch はそのブランチ内のパッチ番号、build は単調増加するビルド番号、typestable または lts のいずれかです。 例: 25.3.8.23-lts — 2025 年 3 月の LTS、パッチ 8、ビルド 23。 リリーストラックは 2 つあります。
  • Stable リリースは、おおむね毎月公開されます。直近 3 つの stable リリースに対してパッチが提供されるため、各リリースのアクティブサポート期間はおよそ 3 か月です。
  • LTS (Long-Term Support) リリースは、毎年 3 月と 8 月に公開されます。2 つの LTS バージョンが同時にサポートされ、それぞれ少なくとも 12 か月間サポートされます。
本番ワークロードを実行しているユーザーには、最新の stable または LTS リリースのいずれかを使用し、新しいパッチバージョンへ速やかにアップグレードすることを推奨します。パッチリリースで互換性を損なう変更が導入されることはありません。

バックポートポリシー

すべての変更がバックポートされるわけではありません。リリースブランチの安定性を保つため、バックポートの対象範囲は意図的に限定されています。
  • セキュリティ修正 — 常にバックポートされます。
  • 重大なバグ修正 (例外 (論理エラー) 、データ損失、誤った結果、RBAC の問題) — 一般的なバックポートルールに基づいて自動的にバックポート対象に選ばれます。これは pr-critical-bugfix ラベルで識別され、このラベルにより pr-must-backport が自動的に追加されます。
  • 安定性やリグレッションの修正 — バグを残すリスクに比べて変更のリスクが低い場合にバックポートされます。これは、メンテナーが手動で追加する pr-must-backport によって識別されます。
  • 回避策がある軽微なバグ修正 — リリースブランチの安定性を損なうのを避けるため、通常はバックポートされません。
  • 新機能、改善、パフォーマンス関連の作業 — バックポートされません。
pr-must-backport ラベルは、PR をバックポート対象として示すためにメンテナーが使う手動オーバーライドです。pr-critical-bugfix ラベルが付くと、CI フックによって pr-must-backport が自動的に追加されます (pr_labels_and_category.py を参照) 。 競合のエスカレーション。 自動バックポートでマージ競合を解決できない場合でも、cherry-pick PR は引き続き作成し、元の PR の著者、マージした人、既存の 担当者 に割り当てる必要があります。これにより、人手で競合を解決し、バックポートを完了できます。

Backport Tool

上で説明したバックポートポリシーは、tests/ci/cherry_pick.py の自動化ツールで実装されています。このツールは ClickHouse のインフラストラクチャ上で GitHub Actions ワークフローとして実行され、アクティブなリリースブランチの検出、バックポート対象となるプルリクエストの選定、2 段階の cherry-pick とバックポート手順の実行、競合の管理、遅延ポリシーの適用、ラベルの同期維持など、必要な要件をすべてカバーしています。 長期的な目標は、この実装を、他のプロジェクトでも採用できるスタンドアロンのオープンソース Python ツールとして切り出すことです。想定している設計は次のとおりです。
  • 設定可能 — すべてのポリシーパラメーター (対象ラベル、遅延期間、古いプルリクエストのしきい値、rolling-out 時の挙動など) を設定ファイルで表現し、コードを変更しなくても、あらゆるプロジェクトのバックポート要件に合わせてツールを適応できるようにします。
  • 配布可能 — ClickHouse の CI インフラストラクチャに依存せず、PyPI からインストール可能な自己完結型の Python wheel としてパッケージ化します。
  • プログラム可能 — プルリクエスト、ラベル、リリースブランチを表す明確なオブジェクトモデルを公開し、ユーザーがコアエンジンの上に独自のワークフローをスクリプト化できるようにします。

テスト

スタンドアロンツールの構成要素として計画されているものの 1 つに、軽量なテスト用インフラストラクチャを備えた専用のテストスイートがあります。このインフラストラクチャでは、以下があらかじめ用意された一時的な GitHub リポジトリ (またはローカルでの同等の環境) を起動できるようになります。
  • リリースラインを表す、設定可能な一連のブランチ
  • さまざまな組み合わせのバックポートラベルが付いたプルリクエスト
  • リリースブランチを対象とし、release ラベルが付いたリリース PR
これによりテストでは、本番環境の状態に影響を与えることなく、実在するものの使い捨て可能なリポジトリを使って、ラベル検出、cherry-pick ブランチの作成、競合処理、バックポート PR の作成、担当者の割り当てロジック、rolling-out のスキップ、遅延ポリシーといった自動化ループ全体を検証できます。同じインフラストラクチャは、ポリシー変更をデプロイする前に回帰テストを行うためにも再利用できます。

アクティブなリリースブランチ

アクティブなリリースブランチとは、対応するリリース PR (release ラベル付き) が GitHub 上でまだオープンになっているブランチを指します。バックポートの自動化では、実行のたびにこれらを動的に検出するため、新しいリリースが作成されたときや古いリリースがサポート終了を迎えたときでも、設定を変更する必要はありません。 新しいリリースのデプロイ中は、リリースブランチが rolling-out 状態 (リリース PR に rolling-out ラベルが付いている状態) になることがあります。ロールアウトを複雑にしないため、rolling-out 状態のブランチでは通常のバックポートは一時停止されます。バージョン固有のラベル (例: v25.3-must-backport) はこの動作を上書きし、ロールアウト中であってもバックポートを強制します。

実装

概要

バックポート自動化は、CherryPick GitHub Actions ワークフロー (.github/workflows/cherry_pick.yml) として 1 時間ごとに実行され、tests/ci/cherry_pick.py に実装されています。GitHub API と、セルフホストの style-checker-aarch64 ランナー上でのローカルな git 操作によって動作します。 このプロセスは、各 (元の PR、リリースブランチ) ペアごとに 2 段階で進みます。
  1. 実際のマージ先から競合解決を切り離すために、cherry-pick PR が作成されます。競合がなければ、自動的にマージされます。
  2. 実際のリリースブランチに対して バックポート PR が作成され、チェリーピックされた変更は 1 つのコミットにまとめられます。

ラベル

元の PR に付いたラベルによって、バックポートを行うかどうかと、どこにバックポートするかが決まります。
ラベル効果
pr-must-backportアクティブなすべてのリリースブランチにバックポートします (rolling-out が付いたブランチはスキップ)
pr-must-backport-forcerolling-out の制限を無視して、アクティブなすべてのリリースブランチにバックポートします
pr-critical-bugfixpr-must-backport を自動的にトリガーします (pr_labels_and_category.py 内の AUTO_BACKPORT 経由)
v{VER}-must-backport (例: v25.3-must-backport)その特定のリリースブランチにのみバックポートします。そのブランチでは rolling-out によるスキップより優先されます
pr-backports-created必要なバックポート PR がすべて作成されるとボットによって設定されます。cherry-pick PR が再オープンされると解除されます
pr-cherrypickボットが作成した cherry-pick PR に適用されます
pr-backportボットが作成したバックポート PR に適用されます
do not testcherry-pick PR で CI が実行されないように適用されます
rolling-outそのブランチが現在ロールアウト中であることを示すために、リリース PR に設定されます。通常のバックポートではこのブランチはスキップされます

ブランチと PR の命名

各 元の PR 番号 N とリリースブランチ release/X.Y について:
  • cherry-pick ブランチ: cherrypick/release/X.Y/N
  • バックポートブランチ: backport/release/X.Y/N
  • cherry-pick PR タイトル: Cherry pick #N to release/X.Y: <original title>
  • バックポート PR タイトル: Backport #N to release/X.Y: <original title>

手順

1. アクティブなリリースを特定する

BackportPRs.receive_release_prs は、release ラベルが付いたオープンな PR をすべて GitHub に対して照会します。これらの PR の head ref がリリースブランチ名です (例: release/25.3) 。そこから、v25.3-must-backport などの互換性ラベルのセットが導き出されます。

2. バックポート対象のPRを見つける

BackportPRs.receive_prs_for_backport は GitHub Search API を使って、次の条件を満たすマージ済みPRを検索します。
  • 少なくとも 1 つのバックポートラベル (pr-must-backportpr-must-backport-forcepr-critical-bugfix、またはバージョン固有のラベル) が付いており、
  • まだ pr-backports-created が付与されておらず、
  • いずれかのリリースブランチで見つかった最も古いコミット日より後にマージされており、
  • 過去 90 日以内に更新されている (検索クエリの効率を保つため) 。

3. rolling-out ブランチの処理

リリース PR に rolling-out ラベルが付いている場合、一般的なバックポートラベル (pr-must-backportpr-critical-bugfix) ではそのブランチはスキップされます。ボットは、そのブランチ向けに以前作成された cherry-pick または バックポート PR を、説明コメント付きでクローズします。バージョン固有のラベル (例: v25.3-must-backport) は、常にこの動作より優先されます。pr-must-backport-force は、すべてのブランチで rolling-out チェックを無視します。

4. Cherry-pick 段階 (ReleaseBranch.create_cherrypick)

まだ cherry-pick PR が存在しない各 (元の PR、リリースブランチ) の組について:
  1. リリースブランチ をチェックアウトし、そこから バックポートブランチ (backport/release/X.Y/N) を作成します。
  2. マージコミットの第1親に対して git merge -s ours を実行し、内容変更を伴わない合成マージベースを作成します。
  3. 元の PR のマージコミットを直接指す cherry-pick branch (cherrypick/release/X.Y/N) を強制的に作成します。
  4. cherry-pick branch を backport branch に git merge --no-commit --no-ff でマージします。
    • すでに最新であれば、その変更は リリースブランチ にすでに含まれているため、完了としてマークしてスキップします。
    • それ以外の場合は (競合の有無にかかわらず) 、両方のブランチをリセットして push します。
  5. cherrypick/release/X.Y/N から backport/release/X.Y/N への cherry-pick PR を作成し、pr-cherrypickdo not test の label を付与します。
  6. 該当する場合は、元の PR から pr-bugfix または pr-critical-bugfix を引き継ぎます。
  7. この時点では 担当者 は設定しません。担当者 が追加されるのは、競合が検出された場合のみです。

5. 競合のない cherry-pick PR の自動マージ

cherry-pick PR をマージ可能な状態 (競合なし) であれば、ボットは GitHub API を通じて自動的にマージし、直ちに backport 段階に進みます。

6. バックポート段階 (ReleaseBranch.create_backport)

cherry-pick PR がマージされたら、次の手順を実行します。
  1. バックポートブランチをチェックアウトし、pull します。
  2. リリースブランチとバックポートブランチの間の merge-base を見つけます。
  3. merge-base に対して git reset --soft を実行し、cherry-pick したすべてのコミットを 1 つにまとめます。
  4. バックポート PR のタイトルをメッセージとしてコミットします。
  5. バックポートブランチを force-push し、実際のリリースブランチを対象とするバックポート PR を作成します。
  6. PR に pr-backport のラベルを付けます (必要に応じて pr-bugfix / pr-critical-bugfix も付けます) 。
  7. PR を、元の PR の著者、マージしたユーザー、および既存の担当者 (ロボットアカウントを除く) に割り当てます。

7. 完了

特定の元の PRに対応するすべてのリリースブランチへのバックポートが完了すると、ボットはその元の PRにpr-backports-createdを追加します。

8. 事前チェック

PR の作業を開始する前に、ReleaseBranch.pre_checkgit merge-base --is-ancestor を実行し、そのマージコミットがリリースブランチからすでにたどれる状態にないことを確認します。すでにたどれる状態にある場合、その PR はすでにバックポート済みと見なされ、スキップされます。

Stale Cherry-pick PR の処理

CherryPickPRs クラスは毎時実行の開始時に動作し、次の 2 つのケースを処理します。
  • 孤立した cherry-pick PR: cherry-pick PR のリリースブランチに対応するオープンな release PR が存在しなくなった場合 (つまりリリースがクローズされた場合) 、その cherry-pick PR は自動的にクローズされます。
  • 再オープンされた cherry-pick PR: original PR にすでに pr-backports-created が付いていても、それに対応する cherry-pick PR がまだオープンであれば、original PR から pr-backports-created ラベルが削除され、再処理できるようになります。
手動での競合解決を待っている cherry-pick PR については、次のように動作します。
  • 3 日間更新がない場合、bot は 担当者 にメンションする ping コメントを投稿します。
  • 7 日間更新がない場合、bot はクローズする旨のコメントを投稿し、その PR をクローズします。

競合の解決

cherry-pick で競合が発生した場合、cherry-pick PR は人手で解決できるよう、開いたままになります。ボットはその PR を original PR の著者、マージした人、および 担当者 に割り当てます。競合が解決されて cherry-pick PR がマージされると、ボットは次の毎時実行時にバックポート PR を作成します。 バックポートを完全に破棄するには、cherry-pick PR をクローズしてください。ボットはそれを意図的にスキップされたものとして扱います。 問題のある cherry-pick PR を最初から作り直すには:
  1. cherry-pick PR から pr-cherrypick ラベルを削除します。
  2. cherrypick/... ブランチを削除します。
  3. original PR に pr-backports-created があれば削除します。

バックポート PR 向け CI

バックポート PR はリリースブランチを対象とするため、標準のプルリクエスト用ワークフローではなく、専用の CI ワークフロー (ci/workflows/backport_branches.py で定義されている BackportPR) を使用します。このワークフローでは、CI の主要な一部として、ASan/UBSan および TSan ビルド、リリースビルド、macOS ビルド、ASan での機能テスト、TSan でのストレステスト、結合テストを実行します。また、バックポートブランチにコミットが 1〜50 件あり、変更されたファイルが少なくとも 1 つ含まれていることを確認します (check_backport_branch.py によって強制されます) 。

認証

このワークフローでは、git の push 操作に SSH 秘密鍵 (ROBOT_CLICKHOUSE_SSH_KEY) を使用します。GitHub API の呼び出しでは get_best_robot_token による認証を使用し、この関数は SSM (/github-tokens) に保存されたプールから、残り QUOTA が最も多いトークンを選択します。ROBOT_CLICKHOUSE_COMMIT_TOKEN は API 呼び出し用ではなく、Actions ワークフローの checkout step で使用されます。担当者を割り当てる際は、ロボットアカウント (robot-clickhouseclickhouse-gh) は除外されます。

GitHub API キャッシュ

GitHubCache (cache_utils.py 内) は PyGithub のオブジェクトcacheを S3 に永続化し、毎時の実行をまたぐ API 呼び出しを削減します。cache は各実行の開始時にダウンロードされ、終了時にアップロードされます。

エラー処理

個々の PR の処理中に発生したエラーは捕捉・記録されますが、実行は停止しません。すべての PR の処理が完了したあと、エラーが 1 件でも発生していた場合は BackportException が送出されます。CI では、これをトリガーとして CIBuddy 経由でチームチャットに通知されます。
最終更新日 2026年6月10日