Skip to content
Apothem
Runbooks

Ceremonia de fusión de PR para mantenedor único

Cuándo el mantenedor puede fusionar directamente su propia pull request, y la ceremonia para una protección de rama que exige una aprobación y la aplica a los administradores.

Referencia canónica para autofusionar PR bajo la protección de rama del proyecto. La protección vigente en main exige 0 revisiones de aprobación y deja enforce_admins desactivado, tal como se registra en la página Protección de ramas. Por lo tanto, el mantenedor fusiona directamente su propia pull request. La ceremonia de alternancia temporal de esta página se aplica solo cuando la protección exige una aprobación y la aplica a los administradores.


1. El bloqueo mutuo

La protección vigente de main incluye:

  • required_pull_request_reviews.required_approving_review_count: 0
  • enforce_admins: false

Con estos ajustes no hay bloqueo mutuo. Una pull request del mantenedor se fusiona con gh pr merge <pr-number> --squash --delete-branch una vez que sus verificaciones de estado requeridas están en verde y sus conversaciones de revisión están resueltas.

Solo existe un bloqueo mutuo cuando la protección incluye estos dos ajustes más estrictos:

  • required_pull_request_reviews.required_approving_review_count: 1
  • enforce_admins: true

Estas reglas son correctas para escenarios con varios mantenedores (cada cambio llega a main a través de una PR revisada por pares; los administradores no están exentos). Producen un bloqueo mutuo para los mantenedores únicos: la política de GitHub no permite autoaprobar una PR de la que eres autor, y enforce_admins=true bloquea la anulación gh pr merge --admin del requisito de aprobación de revisión. Con enforce_admins: false, --admin omite el requisito de aprobación y no hace falta ninguna alternancia, pero también omite las verificaciones requeridas en rojo, así que confirma que estén en verde antes de usarlo.

Existen tres rutas de resolución:

RutaCuándo usarla
Establecer permanentemente required_approving_review_count: 0 (ajuste vigente)Adóptala solo si el repositorio seguirá teniendo un único mantenedor indefinidamente; revierte la intención de revisión de la protección
Ceremonia de alternancia temporalAutofusiones de mantenedor único mientras la protección exige una aprobación con enforce_admins=true; preserva el invariante de la protección fuera de la ventana de fusión
Aprovisionar una identidad de bot de CI con acceso de escrituraAdóptala solo si la incorporación de varios mantenedores es inminente; la aprobación por bot socava la intención de revisión humana de la protección

Actualmente este repositorio usa la ruta de cero aprobaciones permanente. La ceremonia de alternancia temporal es la ruta canónica siempre que la protección exija una aprobación y la aplique a los administradores.

2. La ceremonia de alternancia temporal

El invariante de la ceremonia: el estado de la protección al inicio de la ceremonia es igual al estado de la protección al final. La relajación existe únicamente dentro de la ventana de fusión.

Forma manual:

# 1. Open the PR, push branch, wait for CI green.
gh pr create --base main --head <feature-branch> --title "..." --body "..."
gh pr checks <pr-number>            # poll until all green

# 2. Relax approver-count to 0.
gh api repos/<owner>/<repo>/branches/main/protection/required_pull_request_reviews \
    -X PATCH -F required_approving_review_count=0

# 3. Squash-merge with admin override (admin override now succeeds because the
#    review-approval requirement is the only block enforce_admins refuses).
gh pr merge <pr-number> --squash --delete-branch --admin

# 4. Restore approver-count to 1.
gh api repos/<owner>/<repo>/branches/main/protection/required_pull_request_reviews \
    -X PATCH -F required_approving_review_count=1

Forma envuelta: consulta scripts/dev/admin_merge.py para ver el envoltorio atómico de Python que ejecuta los pasos 2 → 3 → 4 en una sola secuencia no interactiva, con seguridad de reversión mediante try / finally ante un fallo en el paso 3.

python scripts/dev/admin_merge.py <pr-number>

3. Invariantes

  • Ventana de alternancia minimizada. Los pasos 2 → 3 → 4 se ejecutan en una sola secuencia no interactiva. La protección está en su estado relajado solo durante la llamada a la API de fusión: menos de un segundo en cada ejecución observada.
  • La restauración es incondicional. El paso 4 se ejecuta incluso cuando el paso 3 falla (la cláusula try / finally del envoltorio garantiza la restauración en cualquier ruta de salida). Un intento de fusión fallido no deja la protección relajada.
  • El control de CI se preserva en todo momento, mientras enforce_admins está activado. required_status_checks no se ve afectado por la alternancia; con enforce_admins: true, la fusión sigue requiriendo que los contextos de verificación de estado configurados estén en verde. Con enforce_admins: false, la fusión --admin del paso 3 también omite las verificaciones requeridas en rojo, así que no ejecutes la ceremonia en ese estado.
  • Rastro de auditoría visible. La anotación gh pr merge --admin aparece en los metadatos de fusión de la PR; las alternancias de la API de protección aparecen en el registro de auditoría del repositorio bajo la identidad del mantenedor.

4. Cuándo NO usar la ceremonia

Mientras la protección exija 0 revisiones de aprobación o deje enforce_admins desactivado, la ceremonia es innecesaria: fusiona directamente como se describe en la sección 1.

La ceremonia es para la autofusión de las PR del propio mantenedor. Cuando hay un revisor par disponible (un colaborador con acceso de escritura), la ruta estándar gh pr review --approve + gh pr merge --squash --delete-branch es la correcta y la ceremonia es innecesaria.

Si el repositorio incorpora a un segundo mantenedor, retira la ceremonia: el flujo estándar de revisión de PR restaura la intención de revisión humana de la protección sin ninguna alternancia.

5. Auditar una ejecución pasada

Cada invocación de la ceremonia queda registrada en tres superficies duraderas que un operador puede inspeccionar a posteriori:

  • Los metadatos de fusión de la PR. gh pr view <pr-number> --json mergedBy,mergedAt,mergeCommit devuelve el actor de la fusión, la marca de tiempo de la fusión y el SHA del commit de squash. El actor mergedBy coincide con la identidad del mantenedor que ejecutó el paso 3.
  • El registro de auditoría del repositorio. gh api /repos/<owner>/<repo>/actions/runs --jq '.workflow_runs[] | select(.event=="push")' correlaciona la ejecución de CI posterior a la fusión con el commit de fusión; el registro de auditoría de las reglas de protección del repositorio (el historial de gh api /repos/<owner>/<repo>/branches/main/protection, a través de la interfaz Settings → Branches) muestra las alternancias de los pasos 2 y 4 que delimitan la ventana de fusión.
  • El historial de git del mantenedor. git log main --first-parent --oneline enumera cada commit de squash-merge en main con el número de PR correspondiente en el asunto del commit (sufijo (#<pr-number>) según el valor predeterminado de gh pr merge --squash), lo que permite al operador rastrear cualquier integración anterior hasta su PR y su invocación de la ceremonia.

Cuando scripts/dev/admin_merge.py es el punto de entrada, su registro no interactivo (stderr) nombra en secuencia las tres llamadas a la API de protección y la llamada a la API de fusión; canalizar su stderr a tee (2>&1 | tee) captura un fragmento de auditoría por ejecución sin depender de la retención de registros del lado de GitHub.

On this page