> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-fix-nav-issues.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Visão geral da política de backport e da automação do ClickHouse

# Backport System

Este documento descreve a política de backport do ClickHouse e o sistema automatizado que a implementa.

<div id="release-model">
  ## Modelo de lançamento
</div>

As versões do ClickHouse seguem o formato `YY.M.patch.build-type`, em que `YY` é o ano com dois dígitos, `M` é o mês do lançamento (sem zero à esquerda), `patch` é o número do patch dentro da branch, `build` é um número de build que cresce monotonamente, e `type` é `stable` ou `lts`.

Exemplo: `25.3.8.23-lts` — LTS de março de 2025, patch 8, build 23.

Há dois canais de lançamento:

* As versões **Stable** são publicadas aproximadamente uma vez por mês. As três versões stable mais recentes recebem patches, o que garante aproximadamente três meses de suporte ativo para cada versão.
* As versões **LTS (Long-Term Support)** são publicadas em março e agosto de cada ano. Duas versões LTS têm suporte simultaneamente, cada uma por pelo menos 12 meses.

Recomenda-se que os usuários que executam workloads de produção usem a versão stable mais recente ou uma versão LTS e atualizem rapidamente para novas versões de patch, já que versões de patch não introduzem mudanças incompatíveis.

<div id="backport-policy">
  ## Política de backport
</div>

Nem todas as mudanças passam por backport. O objetivo é manter as branches de release estáveis, por isso o escopo dos backports é intencionalmente limitado:

* **Correções de segurança** — sempre passam por backport.
* **Correções de bugs críticos** (exceptions (erros lógicos), perda de dados, resultados incorretos, problemas de RBAC) — selecionadas automaticamente para backport de acordo com as regras gerais de backport; identificadas pelo rótulo `pr-critical-bugfix`, que faz com que `pr-must-backport` seja adicionado automaticamente.
* **Correções de estabilidade e regressões** — passam por backport quando o risco da mudança é baixo em relação ao risco de deixar o bug sem correção; identificadas por `pr-must-backport`, adicionado manualmente pelos maintainers.
* **Correções de bugs menores com workaround disponível** — em geral, não passam por backport para evitar desestabilizar as branches de release.
* **Novos recursos, melhorias e trabalho de performance** — não passam por backport.

O rótulo `pr-must-backport` é a substituição manual usada pelos maintainers para marcar um PR para backport. O rótulo `pr-critical-bugfix` faz com que `pr-must-backport` seja adicionado automaticamente pelo hook de CI (consulte `pr_labels_and_category.py`).

**Escalonamento de conflitos.** Quando o backport automático não consegue resolver conflitos de merge, ainda assim um cherry-pick PR deve ser criado e atribuído ao autor, a quem fez o merge e às pessoas já atribuídas no PR original, para que alguém resolva os conflitos e conclua o backport.

<div id="backport-tool">
  ## Ferramenta de Backport
</div>

A política de backport descrita acima é implementada pela ferramenta automatizada em `tests/ci/cherry_pick.py`. A ferramenta é executada como um workflow do GitHub Actions na infraestrutura do ClickHouse e cobre todos os requisitos: descobrir branches de release ativas, selecionar PRs qualificadas para backport, executar o procedimento de cherry-pick e backport em duas etapas, gerenciar conflitos, aplicar a política de atraso e manter os rótulos sincronizados.

O objetivo de longo prazo é extrair essa implementação para uma ferramenta open-source independente em Python que outros projetos possam adotar. O design pretendido é:

* **Configurável** — todos os parâmetros da política (rótulos de qualificação, janela de atraso, limites para PRs desatualizadas, comportamento durante rolling-out etc.) expressos em um arquivo de configuração, para que a ferramenta possa ser adaptada aos requisitos de backport de qualquer projeto sem alterações no código.
* **Distribuível** — empacotada como uma wheel Python autocontida, instalável via PyPI, sem dependência da infraestrutura de CI do ClickHouse.
* **Programável** — expondo um modelo de objetos claro para pull requests, rótulos e branches de release, para que os usuários possam criar scripts e workflows personalizados sobre o engine principal.

<div id="testing">
  ### Testes
</div>

Uma parte planejada da ferramenta independente é uma suíte de testes dedicada, juntamente com uma infraestrutura de testes leve. A infraestrutura será capaz de criar temporariamente repositórios do GitHub (ou equivalentes locais) já preenchidos com:

* um conjunto configurável de branches que representam linhas de release,
* pull requests com várias combinações de rótulos de backport,
* PRs de release com o rótulo `release` apontando para as branches de release.

Isso permite que os testes exercitem todo o ciclo de automação — detecção de rótulos, criação de branch de cherry-pick, tratamento de conflitos, criação de PR de backport, lógica de atribuição de responsáveis, omissão durante rolling-out e política de atraso — em um repositório real, mas descartável, sem afetar o estado de produção. A mesma infraestrutura também pode ser reutilizada para testes de regressão de mudanças de política antes da implantação.

<div id="active-release-branches">
  ## Branches de release ativas
</div>

Uma branch de release ativa é qualquer branch cujo PR de release correspondente (com o rótulo `release`) ainda esteja aberto no GitHub. A automação de backport detecta essas branches dinamicamente a cada execução, portanto não é necessário fazer alterações de configuração quando uma nova release é criada ou quando uma antiga chega ao fim de vida.

Uma branch de release pode estar no estado **rolling-out** (seu PR de release tem o rótulo `rolling-out`) durante o período em que uma nova release está sendo implantada. Os backports gerais são pausados para branches em rolling-out para evitar complicar o rollout. Rótulos específicas de versão (por exemplo, `v25.3-must-backport`) substituem esse comportamento e forçam o backport mesmo durante um rollout.

<div id="implementation">
  ## Implementação
</div>

<div id="overview">
  ### Visão geral
</div>

A automação de backport é executada a cada hora como o workflow `CherryPick` do GitHub Actions (`.github/workflows/cherry_pick.yml`), implementado em `tests/ci/cherry_pick.py`. Ela opera por meio da API do GitHub e de operações locais do git em um runner `style-checker-aarch64` self-hosted.

O processo ocorre em duas etapas para cada par (PR original, branch de release):

1. Um **PR de cherry-pick** é criado para isolar a resolução de conflitos do destino real do merge. Se não houver conflitos, ele será mesclado automaticamente.
2. Um **PR de backport** é criado na branch de release real, com as alterações aplicadas via cherry-pick consolidadas em um único commit.

<div id="labels">
  ### Rótulos
</div>

Os rótulos no PR original controlam se e onde o backport será feito.

| Rótulo                                                      | Efeito                                                                                                                             |
| ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `pr-must-backport`                                          | Backport para todas as branches de release ativas (ignorando branches marcadas como `rolling-out`)                                 |
| `pr-must-backport-force`                                    | Backport para todas as branches de release ativas, ignorando as restrições de `rolling-out`                                        |
| `pr-critical-bugfix`                                        | Aciona `pr-must-backport` automaticamente (via `AUTO_BACKPORT` em `pr_labels_and_category.py`)                                     |
| `v{VER}-must-backport` (por exemplo, `v25.3-must-backport`) | Backport apenas para essa branch de release específica; sobrescreve o comportamento de ignorar `rolling-out` para essa branch      |
| `pr-backports-created`                                      | Definido pelo bot quando todos os PRs de backport obrigatórios tiverem sido criados; removido se um PR de cherry-pick for reaberto |
| `pr-cherrypick`                                             | Aplicado aos PRs de cherry-pick criados pelo bot                                                                                   |
| `pr-backport`                                               | Aplicado aos PRs de backport criados pelo bot                                                                                      |
| `do not test`                                               | Aplicado aos PRs de cherry-pick para que o CI não seja executado neles                                                             |
| `rolling-out`                                               | Definido em um **PR de release** para indicar que sua branch está em rollout no momento; backports gerais a ignoram                |

<div id="branch-and-pr-naming">
  ### Nomenclatura de branches e PRs
</div>

Para cada número de PR original `N` e branch de release `release/X.Y`:

* Branch de cherry-pick: `cherrypick/release/X.Y/N`
* Branch de backport: `backport/release/X.Y/N`
* Título da PR de cherry-pick: `Cherry pick #N to release/X.Y: <original title>`
* Título da PR de backport: `Backport #N to release/X.Y: <original title>`

<div id="step-by-step-process">
  ### Processo passo a passo
</div>

<div id="discover-active-releases">
  #### 1. Identifique as releases ativas
</div>

`BackportPRs.receive_release_prs` consulta o GitHub em busca de todos os PRs abertos com o rótulo `release`. As refs de origem desses PRs correspondem aos nomes dos branches de release (por exemplo, `release/25.3`). A partir delas, é gerado um conjunto de rótulos de compatibilidade: `v25.3-must-backport` etc.

<div id="find-prs-to-backport">
  #### 2. Encontrar PRs para backport
</div>

`BackportPRs.receive_prs_for_backport` usa a API de busca do GitHub para encontrar PRs mesclados que:

* tenham pelo menos um rótulo de backport (`pr-must-backport`, `pr-must-backport-force`, `pr-critical-bugfix` ou um rótulo específico da versão), e
* **não** já tenham `pr-backports-created`, e
* tenham sido mesclados após a data do commit mais antigo encontrada em qualquer release branch, e
* tenham sido atualizados nos últimos 90 dias (para manter a consulta de busca eficiente).

<div id="rolling-out-branch-handling">
  #### 3. Tratamento de branch em `rolling-out`
</div>

Quando uma PR de release recebe o rótulo `rolling-out`, os rótulos gerais de backport (`pr-must-backport`, `pr-critical-bugfix`) ignoram esse branch. O bot fecha todas as PRs de cherry-pick ou backport criadas anteriormente para esse branch com um comentário explicativo. Um rótulo específico da versão (por exemplo, `v25.3-must-backport`) sempre prevalece sobre isso. `pr-must-backport-force` ignora a verificação de `rolling-out` para todos os branches.

<div id="cherry-pick-stage">
  #### 4. Etapa de cherry-pick (`ReleaseBranch.create_cherrypick`)
</div>

Para cada par (PR original, branch de release) em que ainda não exista um PR de cherry-pick:

1. Faça checkout da branch de release e crie uma **branch de backport** (`backport/release/X.Y/N`) a partir dela.
2. Execute `git merge -s ours` contra o primeiro parent do commit de merge para criar uma base de merge sintética, sem alterações de conteúdo.
3. Crie à força uma **branch de cherry-pick** (`cherrypick/release/X.Y/N`) apontando diretamente para o commit de merge do PR original.
4. Tente executar `git merge --no-commit --no-ff` da branch de cherry-pick na branch de backport:
   * Se já estiver atualizada, a alteração já está presente na branch de release — marque como concluído e pule esta etapa.
   * Caso contrário (com ou sem conflitos), faça reset e envie ambas as branches.
5. Crie o PR de cherry-pick com destino a `backport/release/X.Y/N` a partir de `cherrypick/release/X.Y/N`, com os rótulos `pr-cherrypick` e `do not test`.
6. Propague `pr-bugfix` ou `pr-critical-bugfix` do PR original, se aplicável.
7. Os responsáveis **não** são definidos neste momento; eles só são adicionados quando forem detectados conflitos.

<div id="auto-merge-conflict-free-cherry-pick-prs">
  #### 5. Mesclagem automática de PRs de cherry-pick sem conflitos
</div>

Se o PR de cherry-pick puder ser mesclado (sem conflitos), o bot o mescla automaticamente pela API do GitHub e prossegue imediatamente para a etapa de backport.

<div id="backport-stage">
  #### 6. Etapa de backport (`ReleaseBranch.create_backport`)
</div>

Depois que a PR de cherry-pick é mesclada:

1. Faça checkout da branch de backport e faça pull.
2. Encontre a `merge-base` entre a branch de release e a branch de backport.
3. Execute `git reset --soft` até a `merge-base`, consolidando todos os commits de cherry-pick em um só.
4. Faça um commit usando o título da PR de backport como mensagem.
5. Faça force-push da branch de backport e abra uma PR de backport voltada para a branch de release real.
6. Adicione à PR o label `pr-backport` (e `pr-bugfix` / `pr-critical-bugfix`, se aplicável).
7. Atribua a PR ao autor da PR original, à pessoa que fez o merge e aos responsáveis já atribuídos (excluindo contas de robô).

<div id="completion">
  #### 7. Conclusão
</div>

Quando o backport é concluído em todas as branches de release de um determinado PR original, o bot adiciona `pr-backports-created` ao PR original.

<div id="pre-check">
  #### 8. Pré-verificação
</div>

Antes de iniciar qualquer trabalho em um PR, `ReleaseBranch.pre_check` executa `git merge-base --is-ancestor` para verificar se o commit de merge ainda não é alcançável a partir da branch de release. Se for, considera-se que o PR já foi backportado e ele é ignorado.

<div id="stale-cherry-pick-pr-handling">
  ### Tratamento de Cherry-pick PRs Inativos
</div>

A classe `CherryPickPRs` é executada no início de cada execução horária e trata de dois cenários:

* **PRs de cherry-pick órfãos**: se a branch de release de um PR de cherry-pick não tiver mais um PR de release aberto (ou seja, o release foi fechado), o PR de cherry-pick será fechado automaticamente.
* **PRs de cherry-pick reabertos**: se um PR original já tiver o rótulo `pr-backports-created`, mas um PR de cherry-pick correspondente ainda estiver aberto, o rótulo `pr-backports-created` será removido do PR original para que ele possa ser reprocessado.

Para PRs de cherry-pick que aguardam resolução manual de conflitos:

* Após **3 dias** sem atualizações, o bot publica um comentário de ping mencionando os responsáveis atribuídos.
* Após **7 dias** sem atualizações, o bot publica um comentário de encerramento e fecha o PR.

<div id="conflict-resolution">
  ### Resolução de conflitos
</div>

Quando um `cherry-pick` gera conflitos, a PR de `cherry-pick` permanece aberta para resolução manual. O bot a atribui ao autor da PR original, a quem fez o merge e aos responsáveis designados. Depois que os conflitos são resolvidos e a PR de `cherry-pick` é mesclada, o bot cria a PR de backport na próxima execução horária.

Para descartar um backport completamente, feche a PR de `cherry-pick`. O bot a tratará como intencionalmente ignorada.

Para recriar do zero uma PR de `cherry-pick` com falha:

1. Remova o rótulo `pr-cherrypick` da PR de `cherry-pick`.
2. Exclua a branch `cherrypick/...`.
3. Remova `pr-backports-created` da PR original, se estiver presente.

<div id="ci-for-backport-prs">
  ### CI para PRs de backport
</div>

Os PRs de backport têm como destino branches de release, por isso usam um workflow de CI dedicado (`BackportPR`, definido em `ci/workflows/backport_branches.py`) em vez do workflow padrão de pull request. Esse workflow executa um subconjunto representativo da CI: builds com ASan/UBSan e TSan, builds de release, builds de macOS, testes funcionais com ASan, testes de estresse com TSan e testes de integração. Ele verifica se a branch de backport tem entre 1 e 50 commits e pelo menos um arquivo alterado (conforme validado por `check_backport_branch.py`).

<div id="authentication">
  ### Autenticação
</div>

O workflow usa uma chave SSH (`ROBOT_CLICKHOUSE_SSH_KEY`) para operações de `git push`. As chamadas à API do GitHub são autenticadas via `get_best_robot_token`, que seleciona o token com a maior cota restante de um conjunto armazenado no SSM (`/github-tokens`). `ROBOT_CLICKHOUSE_COMMIT_TOKEN` é usado pela etapa de checkout no workflow do Actions, não para chamadas de API. As contas de robô (`robot-clickhouse`, `clickhouse-gh`) são excluídas ao atribuir um responsável.

<div id="github-api-cache">
  ### Cache da API do GitHub
</div>

`GitHubCache` (de `cache_utils.py`) salva o cache de objetos do PyGithub no S3, reduzindo as chamadas à API entre execuções horárias. O cache é baixado no início e enviado ao final de cada execução.

<div id="error-handling">
  ### Tratamento de erros
</div>

Erros durante o processamento individual de PRs são capturados e registrados em log, mas não interrompem a execução. Depois que todos os PRs forem processados, se tiver ocorrido algum erro, uma `BackportException` será gerada. No CI, isso dispara uma notificação via `CIBuddy` para o chat da equipe.
