This is an automated email from the ASF dual-hosted git repository. potiuk pushed a commit to branch fork-ci-diagrams-prek in repository https://gitbox.apache.org/repos/asf/airflow.git
commit 64c72f8e64acde905382ebb8ef50702c79dc16db Author: Jarek Potiuk <[email protected]> AuthorDate: Tue Nov 10 06:30:19 2026 -0700 Generate the fork CI diagrams from one source with the diagrams prek hook The fork CI design document drew its architecture as ASCII art and its reconciler states and pull request lifecycle in Mermaid, while the ADIP-12 wiki page, which cannot render Mermaid, needs images. Keeping both copies would let them drift. Make Graphviz sources (diagram_fork_ci_*.py under dev/breeze/doc/ci/images/) the only copy: the generate-airflow-diagrams prek hook regenerates each SVG when its source changes, like the other diagrams in the repository, and the design document an [...] Generated-by: Claude Opus 5 --- .pre-commit-config.yaml | 3 +- .../doc/ci/08_fork_ci_for_external_contributors.md | 98 +-------- .../ci/images/diagram_fork_ci_architecture.md5sum | 1 + .../doc/ci/images/diagram_fork_ci_architecture.py | 80 +++++++ .../doc/ci/images/diagram_fork_ci_architecture.svg | 157 ++++++++++++++ .../doc/ci/images/diagram_fork_ci_lifecycle.md5sum | 1 + .../doc/ci/images/diagram_fork_ci_lifecycle.py | 88 ++++++++ .../doc/ci/images/diagram_fork_ci_lifecycle.svg | 234 +++++++++++++++++++++ .../doc/ci/images/diagram_fork_ci_states.md5sum | 1 + dev/breeze/doc/ci/images/diagram_fork_ci_states.py | 92 ++++++++ .../doc/ci/images/diagram_fork_ci_states.svg | 230 ++++++++++++++++++++ 11 files changed, 893 insertions(+), 92 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 28a88003170..7e92cf418ca 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1039,7 +1039,8 @@ repos: ^airflow-core/docs/.*/diagram_[^/]*\.py$| ^contributing-docs/images/diagram_[^/]*\.py$| ^docs/images/.*\.py$| - ^airflow-ctl/docs/images/diagrams/.*\.py$ + ^airflow-ctl/docs/images/diagrams/.*\.py$| + ^dev/breeze/doc/ci/images/diagram_[^/]*\.py$ pass_filenames: true - id: prevent-deprecated-sqlalchemy-usage name: Prevent deprecated sqlalchemy usage diff --git a/dev/breeze/doc/ci/08_fork_ci_for_external_contributors.md b/dev/breeze/doc/ci/08_fork_ci_for_external_contributors.md index 36118c452c6..f060c4199fe 100644 --- a/dev/breeze/doc/ci/08_fork_ci_for_external_contributors.md +++ b/dev/breeze/doc/ci/08_fork_ci_for_external_contributors.md @@ -78,26 +78,7 @@ Non-goals: ## Overview -``` - contributor fork apache/airflow - ┌──────────────────────────────────┐ ┌───────────────────────────────────────────┐ - │ git push feature-branch │ │ pull_request event │ - │ └─ ci-amd.yml (push trigger) │ │ └─ ci-amd.yml │ - │ ├─ gate job: fork -> run │ │ └─ gate job: eligibility -> skip │ - │ ├─ build-info: fork mode │ │ (build-info and everything after │ - │ │ changed files from │ │ are skipped for gated PRs) │ - │ │ compare API vs upstream │ │ │ - │ └─ public runners only │ │ fork-ci-monitor.yml (every 15 minutes) │ - └──────────────────────────────────┘ │ └─ breeze ci fork-ci-reconcile │ - ▲ │ ├─ discover new gated PRs -> label │ - │ GraphQL: checkSuites │ ├─ per labelled PR: fork state -> │ - │ REST: workflow state │ │ draft/undraft, labels, comment, │ - └───────────────────────│ │ commit status with run link, │ - │ │ close after 30 days or when the │ - │ │ PR tampered with the gate │ - │ └─ unknown failures -> Slack │ - └───────────────────────────────────────────┘ -``` + Four pieces, in dependency order: @@ -109,6 +90,10 @@ Four pieces, in dependency order: Plus `breeze ci audit` for the contributor's local setup, and documentation. +The diagrams in this document are SVG files in [`images/`](images/), generated from their +`diagram_fork_ci_*.py` Graphviz sources by the `generate-airflow-diagrams` prek hook whenever a +source changes. The ADIP-12 wiki page embeds the same files. Edit the source, not the SVG. + ### Pull request lifecycle What a gated pull request shows, and who acts next, from the moment it is opened until it is merged @@ -116,39 +101,7 @@ or closed. The [state machine](#state-machine) below is the reconciler's view of diagram is the contributor's and the maintainer's view. Pull requests of committers, collaborators and exempted organisations are not gated and follow the usual project CI flow. -```mermaid -%%{init: {'theme': 'neutral'}}%% -stateDiagram-v2 - state "Waiting for the author: draft, fork CI not set up or no run for the head commit" as waiting - state "Fork CI running" as running - state "Fork CI failed: out of the review queue" as failed - state "Green: ready for maintainer review, CI passed" as ready - state "Green, base too old: ready for maintainer review, CI passed pending until a rebase" as rebase - state "Green, CI files changed: needs project ci" as needs_project_ci - state "Project CI: use project ci" as project_ci - state "Approved" as approved - state "Merged" as merged - state "Closed after 30 days without fork CI activity" as closed - - [*] --> waiting: an external contributor opens a pull request - waiting --> running: the author enables the fork workflow and pushes - running --> failed: a job fails, times out or is cancelled, or the run cannot start - running --> ready: the run passes on a current base - running --> rebase: the run passes, but the base is 200+ commits behind or changed the same files - running --> needs_project_ci: the run passes, and the pull request changes CI-defining files - failed --> running: the author pushes a fix - rebase --> running: the author rebases and pushes - ready --> running: the author pushes - ready --> approved: a maintainer approves - rebase --> approved: a maintainer approves, the merge waits for the rebase - ready --> project_ci: a maintainer adds use project ci - needs_project_ci --> project_ci: a maintainer reviews the CI change and adds use project ci - project_ci --> approved: project CI passes and a maintainer approves - approved --> merged: merged, or auto-merged once CI passed is green - waiting --> closed: 30 days without fork CI activity - closed --> waiting: the author reopens it - merged --> [*] -``` + - **Draft** is used only while the pull request waits for its author to set up fork CI or push. A failed run leaves the draft state unchanged and removes `ready for maintainer review`, so a flaky @@ -589,44 +542,7 @@ pull requests without a fork run for their head commit, not by the total. ### State machine -```mermaid -%%{init: {'theme': 'neutral'}}%% -stateDiagram-v2 - [*] --> gated: discovery adds fork ci required - state gated { - [*] --> setup_required: workflow not enabled in the fork - [*] --> awaiting_push: workflow enabled, no run for the head commit - [*] --> running: fork run in progress - setup_required --> awaiting_push: author enables the workflow - awaiting_push --> running: author pushes - running --> failed: run fails, is cancelled or times out - running --> green: run passes, no CI-defining change - running --> green_unverified: run passes, CI-defining change - failed --> running: author pushes - green --> running: author pushes - green_unverified --> running: author pushes - running --> setup_required: workflow disabled - awaiting_push --> setup_required: workflow disabled - state green { - [*] --> green_ready: not a draft, or the bot's draft - [*] --> green_author_draft: the author's draft - green_ready --> green_author_draft: author converts to draft - green_author_draft --> green_ready: author marks it ready - } - state green_unverified { - [*] --> unverified_ready: not a draft, or the bot's draft - [*] --> unverified_author_draft: the author's draft - unverified_ready --> unverified_author_draft: author converts to draft - unverified_author_draft --> unverified_ready: author marks it ready - } - } - gated --> closed: setup_required or awaiting_push for close_after_days (30 days) - gated --> released: maintainer adds use project ci - gated --> ungated: base branch without fork CI, e.g. v3-3-test - gated --> gate_modified: pull request changes the gate - gated --> gate_bypassed: project CI ran without use project ci (gate tampering) - closed --> gated: reopened -``` + The draft state and the two review labels depend only on the state and on whether the pull request is the author's draft: a draft whose last convert-to-draft event was not by diff --git a/dev/breeze/doc/ci/images/diagram_fork_ci_architecture.md5sum b/dev/breeze/doc/ci/images/diagram_fork_ci_architecture.md5sum new file mode 100644 index 00000000000..49c405e73ef --- /dev/null +++ b/dev/breeze/doc/ci/images/diagram_fork_ci_architecture.md5sum @@ -0,0 +1 @@ +0680ff8001f6f267b5b900af33ac16e3 diff --git a/dev/breeze/doc/ci/images/diagram_fork_ci_architecture.py b/dev/breeze/doc/ci/images/diagram_fork_ci_architecture.py new file mode 100644 index 00000000000..6efe475797d --- /dev/null +++ b/dev/breeze/doc/ci/images/diagram_fork_ci_architecture.py @@ -0,0 +1,80 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# /// script +# requires-python = ">=3.11" +# dependencies = [ +# "rich>=13.6.0", +# "graphviz>=0.20.1", +# ] +# /// +"""Where fork CI runs: the contributor fork and apache/airflow. Used in dev/breeze/doc/ci/08_fork_ci_for_external_contributors.md and on the ADIP-12 wiki page.""" + +from __future__ import annotations + +from pathlib import Path + +import graphviz +from rich.console import Console + +MY_DIR = Path(__file__).parent +MY_FILENAME = Path(__file__).with_suffix("").name + +console = Console(width=400, color_system="standard") + +DOT = r""" +digraph arch { + graph [rankdir=LR, fontname="Helvetica", fontsize=11, nodesep=0.4, ranksep=0.7, compound=true, bgcolor="white"]; + node [shape=box, style="rounded,filled", fillcolor="#f2f4f7", color="#5b6b80", fontname="Helvetica", fontsize=11]; + edge [fontname="Helvetica", fontsize=9, color="#5b6b80", fontcolor="#33404d"]; + + subgraph cluster_fork { + label="contributor's fork (GitHub-hosted runners, contributor's token)"; style="rounded"; color="#3d8b57"; fontname="Helvetica"; + push [label="git push feature-branch"]; + ci [label="Tests (AMD) workflow\npush trigger"]; + gatef [label="gate job:\nfork -> run"]; + bi [label="build-info in fork mode\nchanged files vs upstream\n(compare API)"]; + tests [label="tests and checks\non public runners"]; + push -> ci -> gatef -> bi -> tests; + } + + subgraph cluster_apache { + label="apache/airflow"; style="rounded"; color="#5b6b80"; fontname="Helvetica"; + pr [label="pull_request event"]; + gatea [label="gate job:\neligibility -> skip\n(build-info and all later jobs skipped)"]; + mon [label="fork-ci-monitor.yml\n(scheduled, never runs PR code)"]; + rec [label="breeze ci fork-ci-reconcile"]; + out [label="per gated PR: draft state, labels,\nstate comment, commit statuses\n(Fork CI / Tests (AMD), CI passed),\nclose after 30 days or on gate tampering"]; + slack [label="unknown failures -> Slack", fillcolor="#eceff3"]; + pr -> gatea; + mon -> rec -> out; + rec -> slack [style=dashed]; + } + + tests -> rec [label="GraphQL: check suites\nREST: runs, jobs, workflow state\n(read by the monitor)", dir=back, style=dashed]; +} +""" + + +def generate_diagram() -> None: + image_file = MY_DIR / f"{MY_FILENAME}.svg" + console.print(f"[bright_blue]Generating {image_file}") + graphviz.Source(DOT).render(outfile=image_file, format="svg", cleanup=True) + console.print(f"[green]Generated {image_file}") + + +if __name__ == "__main__": + generate_diagram() diff --git a/dev/breeze/doc/ci/images/diagram_fork_ci_architecture.svg b/dev/breeze/doc/ci/images/diagram_fork_ci_architecture.svg new file mode 100644 index 00000000000..2ce33697709 --- /dev/null +++ b/dev/breeze/doc/ci/images/diagram_fork_ci_architecture.svg @@ -0,0 +1,157 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<!-- Generated by graphviz version 16.1.0 (20260904.0139) + --> +<!-- Title: arch Pages: 1 --> +<svg width="1502pt" height="269pt" + viewBox="0.00 0.00 1502.00 269.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 265)"> +<title>arch</title> +<polygon fill="white" stroke="none" points="-4,4 -4,-265 1497.75,-265 1497.75,4 -4,4"/> +<g id="clust1" class="cluster"> +<title>cluster_fork</title> +<path fill="white" stroke="#3d8b57" d="M20,-173C20,-173 807.88,-173 807.88,-173 813.88,-173 819.88,-179 819.88,-185 819.88,-185 819.88,-241 819.88,-241 819.88,-247 813.88,-253 807.88,-253 807.88,-253 20,-253 20,-253 14,-253 8,-247 8,-241 8,-241 8,-185 8,-185 8,-179 14,-173 20,-173"/> +<text xml:space="preserve" text-anchor="middle" x="413.94" y="-238.55" font-family="Helvetica,sans-Serif" font-size="11.00">contributor's fork (GitHub-hosted runners, contributor's token)</text> +</g> +<g id="clust2" class="cluster"> +<title>cluster_apache</title> +<path fill="white" stroke="#5b6b80" d="M679.5,-8C679.5,-8 1473.75,-8 1473.75,-8 1479.75,-8 1485.75,-14 1485.75,-20 1485.75,-20 1485.75,-153 1485.75,-153 1485.75,-159 1479.75,-165 1473.75,-165 1473.75,-165 679.5,-165 679.5,-165 673.5,-165 667.5,-159 667.5,-153 667.5,-153 667.5,-20 667.5,-20 667.5,-14 673.5,-8 679.5,-8"/> +<text xml:space="preserve" text-anchor="middle" x="1076.62" y="-150.55" font-family="Helvetica,sans-Serif" font-size="11.00">apache/airflow</text> +</g> +<!-- push --> +<g id="node1" class="node"> +<title>push</title> +<path fill="#f2f4f7" stroke="#5b6b80" d="M131,-221C131,-221 28,-221 28,-221 22,-221 16,-215 16,-209 16,-209 16,-197 16,-197 16,-191 22,-185 28,-185 28,-185 131,-185 131,-185 137,-185 143,-191 143,-197 143,-197 143,-209 143,-209 143,-215 137,-221 131,-221"/> +<text xml:space="preserve" text-anchor="middle" x="79.5" y="-198.55" font-family="Helvetica,sans-Serif" font-size="11.00">git push feature-branch</text> +</g> +<!-- ci --> +<g id="node2" class="node"> +<title>ci</title> +<path fill="#f2f4f7" stroke="#5b6b80" d="M303.75,-221C303.75,-221 206,-221 206,-221 200,-221 194,-215 194,-209 194,-209 194,-197 194,-197 194,-191 200,-185 206,-185 206,-185 303.75,-185 303.75,-185 309.75,-185 315.75,-191 315.75,-197 315.75,-197 315.75,-209 315.75,-209 315.75,-215 309.75,-221 303.75,-221"/> +<text xml:space="preserve" text-anchor="middle" x="254.88" y="-204.55" font-family="Helvetica,sans-Serif" font-size="11.00">Tests (AMD) workflow</text> +<text xml:space="preserve" text-anchor="middle" x="254.88" y="-192.55" font-family="Helvetica,sans-Serif" font-size="11.00">push trigger</text> +</g> +<!-- push->ci --> +<g id="edge1" class="edge"> +<title>push->ci</title> +<path fill="none" stroke="#5b6b80" d="M143.09,-203C155.85,-203 169.35,-203 182.39,-203"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="182.18,-206.5 192.18,-203 182.18,-199.5 182.18,-206.5"/> +</g> +<!-- gatef --> +<g id="node3" class="node"> +<title>gatef</title> +<path fill="#f2f4f7" stroke="#5b6b80" d="M421,-221C421,-221 378.75,-221 378.75,-221 372.75,-221 366.75,-215 366.75,-209 366.75,-209 366.75,-197 366.75,-197 366.75,-191 372.75,-185 378.75,-185 378.75,-185 421,-185 421,-185 427,-185 433,-191 433,-197 433,-197 433,-209 433,-209 433,-215 427,-221 421,-221"/> +<text xml:space="preserve" text-anchor="middle" x="399.88" y="-204.55" font-family="Helvetica,sans-Serif" font-size="11.00">gate job:</text> +<text xml:space="preserve" text-anchor="middle" x="399.88" y="-192.55" font-family="Helvetica,sans-Serif" font-size="11.00">fork -> run</text> +</g> +<!-- ci->gatef --> +<g id="edge2" class="edge"> +<title>ci->gatef</title> +<path fill="none" stroke="#5b6b80" d="M316.11,-203C329.18,-203 342.77,-203 355.06,-203"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="354.88,-206.5 364.88,-203 354.88,-199.5 354.88,-206.5"/> +</g> +<!-- bi --> +<g id="node4" class="node"> +<title>bi</title> +<path fill="#f2f4f7" stroke="#5b6b80" d="M612.5,-225C612.5,-225 496,-225 496,-225 490,-225 484,-219 484,-213 484,-213 484,-193 484,-193 484,-187 490,-181 496,-181 496,-181 612.5,-181 612.5,-181 618.5,-181 624.5,-187 624.5,-193 624.5,-193 624.5,-213 624.5,-213 624.5,-219 618.5,-225 612.5,-225"/> +<text xml:space="preserve" text-anchor="middle" x="554.25" y="-210.55" font-family="Helvetica,sans-Serif" font-size="11.00">build-info in fork mode</text> +<text xml:space="preserve" text-anchor="middle" x="554.25" y="-198.55" font-family="Helvetica,sans-Serif" font-size="11.00">changed files vs upstream</text> +<text xml:space="preserve" text-anchor="middle" x="554.25" y="-186.55" font-family="Helvetica,sans-Serif" font-size="11.00">(compare API)</text> +</g> +<!-- gatef->bi --> +<g id="edge3" class="edge"> +<title>gatef->bi</title> +<path fill="none" stroke="#5b6b80" d="M433.19,-203C444.84,-203 458.56,-203 472.49,-203"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="472.16,-206.5 482.16,-203 472.16,-199.5 472.16,-206.5"/> +</g> +<!-- tests --> +<g id="node5" class="node"> +<title>tests</title> +<path fill="#f2f4f7" stroke="#5b6b80" d="M799.88,-219C799.88,-219 725.38,-219 725.38,-219 719.38,-219 713.38,-213 713.38,-207 713.38,-207 713.38,-195 713.38,-195 713.38,-189 719.38,-183 725.38,-183 725.38,-183 799.88,-183 799.88,-183 805.88,-183 811.88,-189 811.88,-195 811.88,-195 811.88,-207 811.88,-207 811.88,-213 805.88,-219 799.88,-219"/> +<text xml:space="preserve" text-anchor="middle" x="762.62" y="-202.55" font-family="Helvetica,sans-Serif" font-size="11.00">tests and checks</text> +<text xml:space="preserve" text-anchor="middle" x="762.62" y="-190.55" font-family="Helvetica,sans-Serif" font-size="11.00">on public runners</text> +</g> +<!-- bi->tests --> +<g id="edge4" class="edge"> +<title>bi->tests</title> +<path fill="none" stroke="#5b6b80" d="M624.83,-202.33C649.77,-202.08 677.65,-201.81 701.7,-201.58"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="701.69,-205.08 711.66,-201.48 701.62,-198.08 701.69,-205.08"/> +</g> +<!-- rec --> +<g id="node9" class="node"> +<title>rec</title> +<path fill="#f2f4f7" stroke="#5b6b80" d="M1181.25,-137C1181.25,-137 1067,-137 1067,-137 1061,-137 1055,-131 1055,-125 1055,-125 1055,-113 1055,-113 1055,-107 1061,-101 1067,-101 1067,-101 1181.25,-101 1181.25,-101 1187.25,-101 1193.25,-107 1193.25,-113 1193.25,-113 1193.25,-125 1193.25,-125 1193.25,-131 1187.25,-137 1181.25,-137"/> +<text xml:space="preserve" text-anchor="middle" x="1124.12" y="-114.55" font-family="Helvetica,sans-Serif" font-size="11.00">breeze ci fork-ci-reconcile</text> +</g> +<!-- tests->rec --> +<g id="edge9" class="edge"> +<title>tests->rec</title> +<path fill="none" stroke="#5b6b80" stroke-dasharray="5,2" d="M823.16,-187.42C886.81,-172.9 987.61,-149.91 1054.55,-134.64"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="822.56,-183.97 813.58,-189.6 824.11,-190.79 822.56,-183.97"/> +<text xml:space="preserve" text-anchor="middle" x="940" y="-195.18" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">GraphQL: check suites</text> +<text xml:space="preserve" text-anchor="middle" x="940" y="-185.43" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">REST: runs, jobs, workflow state</text> +<text xml:space="preserve" text-anchor="middle" x="940" y="-175.68" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">(read by the monitor)</text> +</g> +<!-- pr --> +<g id="node6" class="node"> +<title>pr</title> +<path fill="#f2f4f7" stroke="#5b6b80" d="M802.5,-62C802.5,-62 722.75,-62 722.75,-62 716.75,-62 710.75,-56 710.75,-50 710.75,-50 710.75,-38 710.75,-38 710.75,-32 716.75,-26 722.75,-26 722.75,-26 802.5,-26 802.5,-26 808.5,-26 814.5,-32 814.5,-38 814.5,-38 814.5,-50 814.5,-50 814.5,-56 808.5,-62 802.5,-62"/> +<text xml:space="preserve" text-anchor="middle" x="762.62" y="-39.55" font-family="Helvetica,sans-Serif" font-size="11.00">pull_request event</text> +</g> +<!-- gatea --> +<g id="node7" class="node"> +<title>gatea</title> +<path fill="#f2f4f7" stroke="#5b6b80" d="M1206,-66C1206,-66 1042.25,-66 1042.25,-66 1036.25,-66 1030.25,-60 1030.25,-54 1030.25,-54 1030.25,-34 1030.25,-34 1030.25,-28 1036.25,-22 1042.25,-22 1042.25,-22 1206,-22 1206,-22 1212,-22 1218,-28 1218,-34 1218,-34 1218,-54 1218,-54 1218,-60 1212,-66 1206,-66"/> +<text xml:space="preserve" text-anchor="middle" x="1124.12" y="-51.55" font-family="Helvetica,sans-Serif" font-size="11.00">gate job:</text> +<text xml:space="preserve" text-anchor="middle" x="1124.12" y="-39.55" font-family="Helvetica,sans-Serif" font-size="11.00">eligibility -> skip</text> +<text xml:space="preserve" text-anchor="middle" x="1124.12" y="-27.55" font-family="Helvetica,sans-Serif" font-size="11.00">(build-info and all later jobs skipped)</text> +</g> +<!-- pr->gatea --> +<g id="edge5" class="edge"> +<title>pr->gatea</title> +<path fill="none" stroke="#5b6b80" d="M814.75,-44C867.53,-44 951.37,-44 1018.32,-44"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="1018.24,-47.5 1028.24,-44 1018.24,-40.5 1018.24,-47.5"/> +</g> +<!-- mon --> +<g id="node8" class="node"> +<title>mon</title> +<path fill="#f2f4f7" stroke="#5b6b80" d="M837.75,-137C837.75,-137 687.5,-137 687.5,-137 681.5,-137 675.5,-131 675.5,-125 675.5,-125 675.5,-113 675.5,-113 675.5,-107 681.5,-101 687.5,-101 687.5,-101 837.75,-101 837.75,-101 843.75,-101 849.75,-107 849.75,-113 849.75,-113 849.75,-125 849.75,-125 849.75,-131 843.75,-137 837.75,-137"/> +<text xml:space="preserve" text-anchor="middle" x="762.62" y="-120.55" font-family="Helvetica,sans-Serif" font-size="11.00">fork-ci-monitor.yml</text> +<text xml:space="preserve" text-anchor="middle" x="762.62" y="-108.55" font-family="Helvetica,sans-Serif" font-size="11.00">(scheduled, never runs PR code)</text> +</g> +<!-- mon->rec --> +<g id="edge6" class="edge"> +<title>mon->rec</title> +<path fill="none" stroke="#5b6b80" d="M850.19,-119C909.02,-119 986.24,-119 1043.53,-119"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="1043.2,-122.5 1053.2,-119 1043.2,-115.5 1043.2,-122.5"/> +</g> +<!-- out --> +<g id="node10" class="node"> +<title>out</title> +<path fill="#f2f4f7" stroke="#5b6b80" d="M1465.75,-72C1465.75,-72 1281,-72 1281,-72 1275,-72 1269,-66 1269,-60 1269,-60 1269,-28 1269,-28 1269,-22 1275,-16 1281,-16 1281,-16 1465.75,-16 1465.75,-16 1471.75,-16 1477.75,-22 1477.75,-28 1477.75,-28 1477.75,-60 1477.75,-60 1477.75,-66 1471.75,-72 1465.75,-72"/> +<text xml:space="preserve" text-anchor="middle" x="1373.38" y="-57.55" font-family="Helvetica,sans-Serif" font-size="11.00">per gated PR: draft state, labels,</text> +<text xml:space="preserve" text-anchor="middle" x="1373.38" y="-45.55" font-family="Helvetica,sans-Serif" font-size="11.00">state comment, commit statuses</text> +<text xml:space="preserve" text-anchor="middle" x="1373.38" y="-33.55" font-family="Helvetica,sans-Serif" font-size="11.00">(Fork CI / Tests (AMD), CI passed),</text> +<text xml:space="preserve" text-anchor="middle" x="1373.38" y="-21.55" font-family="Helvetica,sans-Serif" font-size="11.00">close after 30 days or on gate tampering</text> +</g> +<!-- rec->out --> +<g id="edge7" class="edge"> +<title>rec->out</title> +<path fill="none" stroke="#5b6b80" d="M1185.93,-100.56C1210.54,-93.09 1239.68,-84.25 1267.52,-75.81"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="1268.52,-79.16 1277.08,-72.91 1266.49,-72.46 1268.52,-79.16"/> +</g> +<!-- slack --> +<g id="node11" class="node"> +<title>slack</title> +<path fill="#eceff3" stroke="#5b6b80" d="M1431.25,-137C1431.25,-137 1315.5,-137 1315.5,-137 1309.5,-137 1303.5,-131 1303.5,-125 1303.5,-125 1303.5,-113 1303.5,-113 1303.5,-107 1309.5,-101 1315.5,-101 1315.5,-101 1431.25,-101 1431.25,-101 1437.25,-101 1443.25,-107 1443.25,-113 1443.25,-113 1443.25,-125 1443.25,-125 1443.25,-131 1437.25,-137 1431.25,-137"/> +<text xml:space="preserve" text-anchor="middle" x="1373.38" y="-114.55" font-family="Helvetica,sans-Serif" font-size="11.00">unknown failures -> Slack</text> +</g> +<!-- rec->slack --> +<g id="edge8" class="edge"> +<title>rec->slack</title> +<path fill="none" stroke="#5b6b80" stroke-dasharray="5,2" d="M1193.67,-119C1224.09,-119 1260.1,-119 1291.8,-119"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="1291.75,-122.5 1301.75,-119 1291.75,-115.5 1291.75,-122.5"/> +</g> +</g> +</svg> diff --git a/dev/breeze/doc/ci/images/diagram_fork_ci_lifecycle.md5sum b/dev/breeze/doc/ci/images/diagram_fork_ci_lifecycle.md5sum new file mode 100644 index 00000000000..b424a0be35d --- /dev/null +++ b/dev/breeze/doc/ci/images/diagram_fork_ci_lifecycle.md5sum @@ -0,0 +1 @@ +f0006cdaf4d566c6ded754fd92f8abad diff --git a/dev/breeze/doc/ci/images/diagram_fork_ci_lifecycle.py b/dev/breeze/doc/ci/images/diagram_fork_ci_lifecycle.py new file mode 100644 index 00000000000..33e9691dfe1 --- /dev/null +++ b/dev/breeze/doc/ci/images/diagram_fork_ci_lifecycle.py @@ -0,0 +1,88 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# /// script +# requires-python = ">=3.11" +# dependencies = [ +# "rich>=13.6.0", +# "graphviz>=0.20.1", +# ] +# /// +"""What a gated pull request shows, and who acts next, from opening to merge or close. Used in dev/breeze/doc/ci/08_fork_ci_for_external_contributors.md and on the ADIP-12 wiki page.""" + +from __future__ import annotations + +from pathlib import Path + +import graphviz +from rich.console import Console + +MY_DIR = Path(__file__).parent +MY_FILENAME = Path(__file__).with_suffix("").name + +console = Console(width=400, color_system="standard") + +DOT = r""" +digraph lifecycle { + graph [rankdir=TB, fontname="Helvetica", fontsize=11, nodesep=0.5, ranksep=0.55, bgcolor="white"]; + node [shape=box, style="rounded,filled", fillcolor="#f2f4f7", color="#5b6b80", fontname="Helvetica", fontsize=11, margin="0.15,0.08"]; + edge [fontname="Helvetica", fontsize=9, color="#5b6b80", fontcolor="#33404d"]; + + start [shape=circle, label="", width=0.22, fillcolor="#33404d", color="#33404d"]; + done [shape=doublecircle, label="", width=0.18, fillcolor="#33404d", color="#33404d"]; + + waiting [label="Waiting for the author\n(draft: fork CI not set up,\nor no run for the head commit)"]; + running [label="Fork CI running"]; + failed [label="Fork CI failed\n(out of the review queue)", fillcolor="#fde8e8", color="#b54848"]; + ready [label="Green\nready for maintainer review\nCI passed", fillcolor="#e6f4ea", color="#3d8b57"]; + rebase [label="Green, base too old\nready for maintainer review\nCI passed pending until a rebase", fillcolor="#fff6db", color="#b38a1d"]; + needs [label="Green, CI files changed\nneeds project ci", fillcolor="#fff6db", color="#b38a1d"]; + project [label="Project CI\n(use project ci)"]; + approved[label="Approved"]; + merged [label="Merged", fillcolor="#e6f4ea", color="#3d8b57"]; + closed [label="Closed after 30 days\nwithout fork CI activity", fillcolor="#eceff3", color="#8a96a3"]; + + start -> waiting [label="external contributor\nopens a pull request"]; + waiting -> running [label="author enables the fork\nworkflow and pushes"]; + running -> failed [label="a job fails, times out,\nis cancelled, or the\nrun cannot start"]; + running -> ready [label="passes on a\ncurrent base"]; + running -> rebase [label="passes, base 200+ commits\nbehind or changed\nthe same files"]; + running -> needs [label="passes, changes\nCI-defining files"]; + failed -> running [label="author pushes a fix"]; + rebase -> running [label="author rebases\nand pushes"]; + ready -> running [label="author pushes", style=dashed]; + ready -> approved [label="maintainer approves"]; + rebase -> approved [label="maintainer approves;\nmerge waits for the rebase", style=dashed]; + ready -> project [label="maintainer adds\nuse project ci", style=dashed]; + needs -> project [label="maintainer reviews the\nCI change, adds use project ci"]; + project -> approved [label="project CI passes,\nmaintainer approves"]; + approved -> merged [label="merged, or auto-merged\nonce CI passed is green"]; + waiting -> closed [label="30 days without\nfork CI activity"]; + closed -> waiting [label="author reopens", style=dashed]; + merged -> done; +} +""" + + +def generate_diagram() -> None: + image_file = MY_DIR / f"{MY_FILENAME}.svg" + console.print(f"[bright_blue]Generating {image_file}") + graphviz.Source(DOT).render(outfile=image_file, format="svg", cleanup=True) + console.print(f"[green]Generated {image_file}") + + +if __name__ == "__main__": + generate_diagram() diff --git a/dev/breeze/doc/ci/images/diagram_fork_ci_lifecycle.svg b/dev/breeze/doc/ci/images/diagram_fork_ci_lifecycle.svg new file mode 100644 index 00000000000..95c91474c00 --- /dev/null +++ b/dev/breeze/doc/ci/images/diagram_fork_ci_lifecycle.svg @@ -0,0 +1,234 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<!-- Generated by graphviz version 16.1.0 (20260904.0139) + --> +<!-- Title: lifecycle Pages: 1 --> +<svg width="790pt" height="692pt" + viewBox="0.00 0.00 790.00 692.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 687.59)"> +<title>lifecycle</title> +<polygon fill="white" stroke="none" points="-4,4 -4,-687.59 786.19,-687.59 786.19,4 -4,4"/> +<!-- start --> +<g id="node1" class="node"> +<title>start</title> +<ellipse fill="#33404d" stroke="#33404d" cx="524.8" cy="-675.67" rx="7.92" ry="7.92"/> +</g> +<!-- waiting --> +<g id="node3" class="node"> +<title>waiting</title> +<path fill="#f2f4f7" stroke="#5b6b80" d="M596.35,-608.25C596.35,-608.25 453.25,-608.25 453.25,-608.25 447.25,-608.25 441.25,-602.25 441.25,-596.25 441.25,-596.25 441.25,-572.73 441.25,-572.73 441.25,-566.73 447.25,-560.73 453.25,-560.73 453.25,-560.73 596.35,-560.73 596.35,-560.73 602.35,-560.73 608.35,-566.73 608.35,-572.73 608.35,-572.73 608.35,-596.25 608.35,-596.25 608.35,-602.25 602.35,-608.25 596.35,-608.25"/> +<text xml:space="preserve" text-anchor="middle" x="524.8" y="-592.04" font-family="Helvetica,sans-Serif" font-size="11.00">Waiting for the author</text> +<text xml:space="preserve" text-anchor="middle" x="524.8" y="-580.04" font-family="Helvetica,sans-Serif" font-size="11.00">(draft: fork CI not set up,</text> +<text xml:space="preserve" text-anchor="middle" x="524.8" y="-568.04" font-family="Helvetica,sans-Serif" font-size="11.00">or no run for the head commit)</text> +</g> +<!-- start->waiting --> +<g id="edge1" class="edge"> +<title>start->waiting</title> +<path fill="none" stroke="#5b6b80" d="M524.8,-667.37C524.8,-656.98 524.8,-637.23 524.8,-619.74"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="528.3,-619.92 524.8,-609.92 521.3,-619.92 528.3,-619.92"/> +<text xml:space="preserve" text-anchor="middle" x="566.42" y="-639.2" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">external contributor</text> +<text xml:space="preserve" text-anchor="middle" x="566.42" y="-629.45" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">opens a pull request</text> +</g> +<!-- done --> +<g id="node2" class="node"> +<title>done</title> +<ellipse fill="#33404d" stroke="#33404d" cx="529.8" cy="-10.48" rx="6.48" ry="6.48"/> +<ellipse fill="none" stroke="#33404d" cx="529.8" cy="-10.48" rx="10.48" ry="10.48"/> +</g> +<!-- running --> +<g id="node4" class="node"> +<title>running</title> +<path fill="#f2f4f7" stroke="#5b6b80" d="M426.1,-501.23C426.1,-501.23 353.5,-501.23 353.5,-501.23 347.5,-501.23 341.5,-495.23 341.5,-489.23 341.5,-489.23 341.5,-477.23 341.5,-477.23 341.5,-471.23 347.5,-465.23 353.5,-465.23 353.5,-465.23 426.1,-465.23 426.1,-465.23 432.1,-465.23 438.1,-471.23 438.1,-477.23 438.1,-477.23 438.1,-489.23 438.1,-489.23 438.1,-495.23 432.1,-501.23 426.1,-501.23"/> +<text xml:space="preserve" text-anchor="middle" x="389.8" y="-478.78" font-family="Helvetica,sans-Serif" font-size="11.00">Fork CI running</text> +</g> +<!-- waiting->running --> +<g id="edge2" class="edge"> +<title>waiting->running</title> +<path fill="none" stroke="#5b6b80" d="M440.92,-562.86C429.15,-557.17 418.02,-549.93 409.05,-540.73 401.67,-533.16 397.11,-522.64 394.3,-512.73"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="397.73,-512.03 392.08,-503.07 390.91,-513.6 397.73,-512.03"/> +<text xml:space="preserve" text-anchor="middle" x="455.93" y="-532.18" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">author enables the fork</text> +<text xml:space="preserve" text-anchor="middle" x="455.93" y="-522.43" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">workflow and pushes</text> +</g> +<!-- closed --> +<g id="node12" class="node"> +<title>closed</title> +<path fill="#eceff3" stroke="#8a96a3" d="M634.1,-501.23C634.1,-501.23 531.5,-501.23 531.5,-501.23 525.5,-501.23 519.5,-495.23 519.5,-489.23 519.5,-489.23 519.5,-477.23 519.5,-477.23 519.5,-471.23 525.5,-465.23 531.5,-465.23 531.5,-465.23 634.1,-465.23 634.1,-465.23 640.1,-465.23 646.1,-471.23 646.1,-477.23 646.1,-477.23 646.1,-489.23 646.1,-489.23 646.1,-495.23 640.1,-501.23 634.1,-501.23"/> +<text xml:space="preserve" text-anchor="middle" x="582.8" y="-484.78" font-family="Helvetica,sans-Serif" font-size="11.00">Closed after 30 days</text> +<text xml:space="preserve" text-anchor="middle" x="582.8" y="-472.78" font-family="Helvetica,sans-Serif" font-size="11.00">without fork CI activity</text> +</g> +<!-- waiting->closed --> +<g id="edge16" class="edge"> +<title>waiting->closed</title> +<path fill="none" stroke="#5b6b80" d="M570.96,-560.28C577.74,-554.82 583.78,-548.32 587.8,-540.73 592.27,-532.29 592.64,-522.13 591.36,-512.77"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="594.8,-512.1 589.37,-503.01 587.94,-513.5 594.8,-512.1"/> +<text xml:space="preserve" text-anchor="middle" x="623.88" y="-532.18" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">30 days without</text> +<text xml:space="preserve" text-anchor="middle" x="623.88" y="-522.43" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">fork CI activity</text> +</g> +<!-- failed --> +<g id="node5" class="node"> +<title>failed</title> +<path fill="#fde8e8" stroke="#b54848" d="M129.6,-390.22C129.6,-390.22 12,-390.22 12,-390.22 6,-390.22 0,-384.22 0,-378.22 0,-378.22 0,-366.22 0,-366.22 0,-360.22 6,-354.22 12,-354.22 12,-354.22 129.6,-354.22 129.6,-354.22 135.6,-354.22 141.6,-360.22 141.6,-366.22 141.6,-366.22 141.6,-378.22 141.6,-378.22 141.6,-384.22 135.6,-390.22 129.6,-390.22"/> +<text xml:space="preserve" text-anchor="middle" x="70.8" y="-373.77" font-family="Helvetica,sans-Serif" font-size="11.00">Fork CI failed</text> +<text xml:space="preserve" text-anchor="middle" x="70.8" y="-361.77" font-family="Helvetica,sans-Serif" font-size="11.00">(out of the review queue)</text> +</g> +<!-- running->failed --> +<g id="edge3" class="edge"> +<title>running->failed</title> +<path fill="none" stroke="#5b6b80" d="M341.04,-477.89C300.26,-473.14 241.11,-463.61 192.3,-445.23 160.23,-433.16 126.97,-412.81 103.37,-396.81"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="105.66,-394.14 95.44,-391.34 101.69,-399.9 105.66,-394.14"/> +<text xml:space="preserve" text-anchor="middle" x="233.55" y="-436.68" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">a job fails, times out,</text> +<text xml:space="preserve" text-anchor="middle" x="233.55" y="-426.93" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">is cancelled, or the</text> +<text xml:space="preserve" text-anchor="middle" x="233.55" y="-417.18" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">run cannot start</text> +</g> +<!-- ready --> +<g id="node6" class="node"> +<title>ready</title> +<path fill="#e6f4ea" stroke="#3d8b57" d="M533.85,-395.98C533.85,-395.98 405.75,-395.98 405.75,-395.98 399.75,-395.98 393.75,-389.98 393.75,-383.98 393.75,-383.98 393.75,-360.46 393.75,-360.46 393.75,-354.46 399.75,-348.46 405.75,-348.46 405.75,-348.46 533.85,-348.46 533.85,-348.46 539.85,-348.46 545.85,-354.46 545.85,-360.46 545.85,-360.46 545.85,-383.98 545.85,-383.98 545.85,-389.98 539.85,-395.98 533.85,-395.98"/> +<text xml:space="preserve" text-anchor="middle" x="469.8" y="-379.77" font-family="Helvetica,sans-Serif" font-size="11.00">Green</text> +<text xml:space="preserve" text-anchor="middle" x="469.8" y="-367.77" font-family="Helvetica,sans-Serif" font-size="11.00">ready for maintainer review</text> +<text xml:space="preserve" text-anchor="middle" x="469.8" y="-355.77" font-family="Helvetica,sans-Serif" font-size="11.00">CI passed</text> +</g> +<!-- running->ready --> +<g id="edge4" class="edge"> +<title>running->ready</title> +<path fill="none" stroke="#5b6b80" d="M427.54,-464.91C435.85,-459.6 443.92,-453.06 449.8,-445.23 457.98,-434.35 462.81,-420.3 465.67,-407.5"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="469.1,-408.18 467.5,-397.71 462.22,-406.9 469.1,-408.18"/> +<text xml:space="preserve" text-anchor="middle" x="488.99" y="-431.81" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">passes on a</text> +<text xml:space="preserve" text-anchor="middle" x="488.99" y="-422.06" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">current base</text> +</g> +<!-- rebase --> +<g id="node7" class="node"> +<title>rebase</title> +<path fill="#fff6db" stroke="#b38a1d" d="M762.35,-395.98C762.35,-395.98 607.25,-395.98 607.25,-395.98 601.25,-395.98 595.25,-389.98 595.25,-383.98 595.25,-383.98 595.25,-360.46 595.25,-360.46 595.25,-354.46 601.25,-348.46 607.25,-348.46 607.25,-348.46 762.35,-348.46 762.35,-348.46 768.35,-348.46 774.35,-354.46 774.35,-360.46 774.35,-360.46 774.35,-383.98 774.35,-383.98 774.35,-389.98 768.35,-395.98 762.35,-395.98"/> +<text xml:space="preserve" text-anchor="middle" x="684.8" y="-379.77" font-family="Helvetica,sans-Serif" font-size="11.00">Green, base too old</text> +<text xml:space="preserve" text-anchor="middle" x="684.8" y="-367.77" font-family="Helvetica,sans-Serif" font-size="11.00">ready for maintainer review</text> +<text xml:space="preserve" text-anchor="middle" x="684.8" y="-355.77" font-family="Helvetica,sans-Serif" font-size="11.00">CI passed pending until a rebase</text> +</g> +<!-- running->rebase --> +<g id="edge5" class="edge"> +<title>running->rebase</title> +<path fill="none" stroke="#5b6b80" d="M438.57,-474.7C458.21,-471.7 481.07,-468.25 501.8,-465.23 533.55,-460.6 618.34,-463.38 644.8,-445.23 658.24,-436.01 667.64,-420.73 673.93,-406.61"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="677.09,-408.15 677.59,-397.57 670.6,-405.53 677.09,-408.15"/> +<text xml:space="preserve" text-anchor="middle" x="725.57" y="-436.68" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">passes, base 200+ commits</text> +<text xml:space="preserve" text-anchor="middle" x="725.57" y="-426.93" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">behind or changed</text> +<text xml:space="preserve" text-anchor="middle" x="725.57" y="-417.18" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">the same files</text> +</g> +<!-- needs --> +<g id="node8" class="node"> +<title>needs</title> +<path fill="#fff6db" stroke="#b38a1d" d="M333.23,-390.22C333.23,-390.22 222.38,-390.22 222.38,-390.22 216.38,-390.22 210.38,-384.22 210.38,-378.22 210.38,-378.22 210.38,-366.22 210.38,-366.22 210.38,-360.22 216.38,-354.22 222.38,-354.22 222.38,-354.22 333.23,-354.22 333.23,-354.22 339.23,-354.22 345.23,-360.22 345.23,-366.22 345.23,-366.22 345.23,-378.22 345.23,-378.22 345.23,-384.22 339.23,-390.22 333.23,-390.22"/> +<text xml:space="preserve" text-anchor="middle" x="277.8" y="-373.77" font-family="Helvetica,sans-Serif" font-size="11.00">Green, CI files changed</text> +<text xml:space="preserve" text-anchor="middle" x="277.8" y="-361.77" font-family="Helvetica,sans-Serif" font-size="11.00">needs project ci</text> +</g> +<!-- running->needs --> +<g id="edge6" class="edge"> +<title>running->needs</title> +<path fill="none" stroke="#5b6b80" d="M341.39,-471.52C325.96,-465.97 310,-457.64 298.8,-445.23 288.06,-433.33 282.79,-416.22 280.22,-401.67"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="283.75,-401.61 278.89,-392.19 276.81,-402.58 283.75,-401.61"/> +<text xml:space="preserve" text-anchor="middle" x="333.3" y="-431.81" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">passes, changes</text> +<text xml:space="preserve" text-anchor="middle" x="333.3" y="-422.06" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">CI-defining files</text> +</g> +<!-- failed->running --> +<g id="edge7" class="edge"> +<title>failed->running</title> +<path fill="none" stroke="#5b6b80" d="M56.66,-390.62C45.49,-406.58 33.86,-429.98 47.55,-445.23 66.04,-465.83 237.03,-475.99 330.1,-480.03"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="329.67,-483.52 339.81,-480.45 329.96,-476.53 329.67,-483.52"/> +<text xml:space="preserve" text-anchor="middle" x="86.18" y="-426.93" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">author pushes a fix</text> +</g> +<!-- ready->running --> +<g id="edge9" class="edge"> +<title>ready->running</title> +<path fill="none" stroke="#5b6b80" stroke-dasharray="5,2" d="M401.79,-396.32C394.07,-401.62 387.22,-408.09 382.3,-415.98 375.31,-427.18 376.04,-441.55 378.99,-454.05"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="375.56,-454.8 381.75,-463.4 382.28,-452.82 375.56,-454.8"/> +<text xml:space="preserve" text-anchor="middle" x="411.55" y="-426.93" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">author pushes</text> +</g> +<!-- project --> +<g id="node9" class="node"> +<title>project</title> +<path fill="#f2f4f7" stroke="#5b6b80" d="M445.85,-288.96C445.85,-288.96 377.75,-288.96 377.75,-288.96 371.75,-288.96 365.75,-282.96 365.75,-276.96 365.75,-276.96 365.75,-264.96 365.75,-264.96 365.75,-258.96 371.75,-252.96 377.75,-252.96 377.75,-252.96 445.85,-252.96 445.85,-252.96 451.85,-252.96 457.85,-258.96 457.85,-264.96 457.85,-264.96 457.85,-276.96 457.85,-276.96 457.85,-282.96 451.85,-288.96 445.85,-288.96"/> +<text xml:space="preserve" text-anchor="middle" x="411.8" y="-272.51" font-family="Helvetica,sans-Serif" font-size="11.00">Project CI</text> +<text xml:space="preserve" text-anchor="middle" x="411.8" y="-260.51" font-family="Helvetica,sans-Serif" font-size="11.00">(use project ci)</text> +</g> +<!-- ready->project --> +<g id="edge12" class="edge"> +<title>ready->project</title> +<path fill="none" stroke="#5b6b80" stroke-dasharray="5,2" d="M449.54,-348.07C444.69,-341.93 439.78,-335.14 435.8,-328.46 430.47,-319.51 425.72,-309.15 421.87,-299.77"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="425.25,-298.8 418.34,-290.76 418.73,-301.35 425.25,-298.8"/> +<text xml:space="preserve" text-anchor="middle" x="468.8" y="-319.91" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">maintainer adds</text> +<text xml:space="preserve" text-anchor="middle" x="468.8" y="-310.16" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">use project ci</text> +</g> +<!-- approved --> +<g id="node10" class="node"> +<title>approved</title> +<path fill="#f2f4f7" stroke="#5b6b80" d="M551.85,-193.46C551.85,-193.46 507.75,-193.46 507.75,-193.46 501.75,-193.46 495.75,-187.46 495.75,-181.46 495.75,-181.46 495.75,-169.46 495.75,-169.46 495.75,-163.46 501.75,-157.46 507.75,-157.46 507.75,-157.46 551.85,-157.46 551.85,-157.46 557.85,-157.46 563.85,-163.46 563.85,-169.46 563.85,-169.46 563.85,-181.46 563.85,-181.46 563.85,-187.46 557.85,-193.46 551.85,-193.46"/> +<text xml:space="preserve" text-anchor="middle" x="529.8" y="-171.01" font-family="Helvetica,sans-Serif" font-size="11.00">Approved</text> +</g> +<!-- ready->approved --> +<g id="edge10" class="edge"> +<title>ready->approved</title> +<path fill="none" stroke="#5b6b80" d="M493.94,-348.04C498.91,-342.1 503.6,-335.41 506.8,-328.46 525.24,-288.44 529.46,-236.83 530.13,-205.21"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="533.63,-205.3 530.23,-195.27 526.63,-205.24 533.63,-205.3"/> +<text xml:space="preserve" text-anchor="middle" x="568.42" y="-267.29" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">maintainer approves</text> +</g> +<!-- rebase->running --> +<g id="edge8" class="edge"> +<title>rebase->running</title> +<path fill="none" stroke="#5b6b80" d="M619.81,-396.43C604.68,-402.36 588.77,-409.04 574.3,-415.98 550.91,-427.19 547.72,-435.2 523.8,-445.23 500.17,-455.14 473.09,-463.2 449.48,-469.23"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="448.89,-465.77 440.03,-471.58 450.58,-472.57 448.89,-465.77"/> +<text xml:space="preserve" text-anchor="middle" x="605.05" y="-431.81" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">author rebases</text> +<text xml:space="preserve" text-anchor="middle" x="605.05" y="-422.06" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">and pushes</text> +</g> +<!-- rebase->approved --> +<g id="edge11" class="edge"> +<title>rebase->approved</title> +<path fill="none" stroke="#5b6b80" stroke-dasharray="5,2" d="M675.26,-348.37C664.18,-323.38 644.24,-282.91 619.8,-252.96 603.68,-233.21 581.99,-214.6 563.94,-200.68"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="566.19,-197.99 556.09,-194.76 561.97,-203.57 566.19,-197.99"/> +<text xml:space="preserve" text-anchor="middle" x="698.37" y="-272.16" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">maintainer approves;</text> +<text xml:space="preserve" text-anchor="middle" x="698.37" y="-262.41" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">merge waits for the rebase</text> +</g> +<!-- needs->project --> +<g id="edge13" class="edge"> +<title>needs->project</title> +<path fill="none" stroke="#5b6b80" d="M277.87,-353.72C278.86,-339.88 282.43,-320.94 293.8,-308.96 309.59,-292.32 332.77,-283.12 354.4,-278.06"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="354.96,-281.51 364.05,-276.07 353.55,-274.66 354.96,-281.51"/> +<text xml:space="preserve" text-anchor="middle" x="355.3" y="-319.91" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">maintainer reviews the</text> +<text xml:space="preserve" text-anchor="middle" x="355.3" y="-310.16" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">CI change, adds use project ci</text> +</g> +<!-- project->approved --> +<g id="edge14" class="edge"> +<title>project->approved</title> +<path fill="none" stroke="#5b6b80" d="M409.06,-252.55C408.13,-240.33 409.07,-224.29 417.8,-213.46 433.82,-193.6 460.78,-184.31 484.24,-180"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="484.57,-183.49 493.91,-178.49 483.49,-176.57 484.57,-183.49"/> +<text xml:space="preserve" text-anchor="middle" x="459.8" y="-224.41" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">project CI passes,</text> +<text xml:space="preserve" text-anchor="middle" x="459.8" y="-214.66" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">maintainer approves</text> +</g> +<!-- merged --> +<g id="node11" class="node"> +<title>merged</title> +<path fill="#e6f4ea" stroke="#3d8b57" d="M546.97,-97.96C546.97,-97.96 512.62,-97.96 512.62,-97.96 506.62,-97.96 500.62,-91.96 500.62,-85.96 500.62,-85.96 500.62,-73.96 500.62,-73.96 500.62,-67.96 506.62,-61.96 512.62,-61.96 512.62,-61.96 546.97,-61.96 546.97,-61.96 552.97,-61.96 558.97,-67.96 558.97,-73.96 558.97,-73.96 558.97,-85.96 558.97,-85.96 558.97,-91.96 552.97,-97.96 546.97,-97.96"/> +<text xml:space="preserve" text-anchor="middle" x="529.8" y="-75.51" font-family="Helvetica,sans-Serif" font-size="11.00">Merged</text> +</g> +<!-- approved->merged --> +<g id="edge15" class="edge"> +<title>approved->merged</title> +<path fill="none" stroke="#5b6b80" d="M529.8,-157.31C529.8,-143.95 529.8,-125.11 529.8,-109.49"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="533.3,-109.83 529.8,-99.83 526.3,-109.83 533.3,-109.83"/> +<text xml:space="preserve" text-anchor="middle" x="579.3" y="-128.91" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">merged, or auto-merged</text> +<text xml:space="preserve" text-anchor="middle" x="579.3" y="-119.16" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">once CI passed is green</text> +</g> +<!-- merged->done --> +<g id="edge18" class="edge"> +<title>merged->done</title> +<path fill="none" stroke="#5b6b80" d="M529.8,-61.58C529.8,-52.78 529.8,-42.01 529.8,-32.71"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="533.3,-32.79 529.8,-22.79 526.3,-32.79 533.3,-32.79"/> +</g> +<!-- closed->waiting --> +<g id="edge17" class="edge"> +<title>closed->waiting</title> +<path fill="none" stroke="#5b6b80" stroke-dasharray="5,2" d="M536.43,-501.63C528.49,-506.72 521.28,-513.16 516.55,-521.23 511.59,-529.68 511.13,-539.87 512.62,-549.53"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="509.15,-550.05 514.78,-559.02 515.97,-548.5 509.15,-550.05"/> +<text xml:space="preserve" text-anchor="middle" x="547.67" y="-527.31" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">author reopens</text> +</g> +</g> +</svg> diff --git a/dev/breeze/doc/ci/images/diagram_fork_ci_states.md5sum b/dev/breeze/doc/ci/images/diagram_fork_ci_states.md5sum new file mode 100644 index 00000000000..629b8f412d2 --- /dev/null +++ b/dev/breeze/doc/ci/images/diagram_fork_ci_states.md5sum @@ -0,0 +1 @@ +1570edf2d31def0a094a6b94b3c457d0 diff --git a/dev/breeze/doc/ci/images/diagram_fork_ci_states.py b/dev/breeze/doc/ci/images/diagram_fork_ci_states.py new file mode 100644 index 00000000000..a6da4e581ea --- /dev/null +++ b/dev/breeze/doc/ci/images/diagram_fork_ci_states.py @@ -0,0 +1,92 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# /// script +# requires-python = ">=3.11" +# dependencies = [ +# "rich>=13.6.0", +# "graphviz>=0.20.1", +# ] +# /// +"""The fork CI reconciler's states for a gated pull request. Used in dev/breeze/doc/ci/08_fork_ci_for_external_contributors.md and on the ADIP-12 wiki page.""" + +from __future__ import annotations + +from pathlib import Path + +import graphviz +from rich.console import Console + +MY_DIR = Path(__file__).parent +MY_FILENAME = Path(__file__).with_suffix("").name + +console = Console(width=400, color_system="standard") + +DOT = r""" +digraph states { + graph [rankdir=TB, fontname="Helvetica", fontsize=11, nodesep=0.45, ranksep=0.5, compound=true, bgcolor="white"]; + node [shape=box, style="rounded,filled", fillcolor="#f2f4f7", color="#5b6b80", fontname="Helvetica", fontsize=11]; + edge [fontname="Helvetica", fontsize=9, color="#5b6b80", fontcolor="#33404d"]; + + start [shape=circle, label="", width=0.22, fillcolor="#33404d", color="#33404d"]; + + subgraph cluster_gated { + label="gated (label: fork ci required)"; fontname="Helvetica"; fontsize=12; style="rounded"; color="#8a96a3"; + setup_required [label="setup_required\nworkflow not enabled in the fork\n(draft)"]; + awaiting_push [label="awaiting_push\nworkflow enabled, no run\nfor the head commit (draft)"]; + running [label="running\nfork run in progress"]; + failed [label="failed\nrun failed, cancelled, timed out\nor could not start", fillcolor="#fde8e8", color="#b54848"]; + green [label="green\nno CI-defining change\nready for maintainer review", fillcolor="#e6f4ea", color="#3d8b57"]; + green_unverified [label="green_unverified\nCI-defining change\nneeds project ci", fillcolor="#fff6db", color="#b38a1d"]; + } + + closed [label="closed\nsetup_required or awaiting_push\nfor 30 days", fillcolor="#eceff3", color="#8a96a3"]; + released [label="released\nmaintainer added use project ci"]; + ungated [label="ungated\nbase branch without fork CI"]; + gate_modified [label="gate_modified\nPR changes the gate (closed)", fillcolor="#fde8e8", color="#b54848"]; + gate_bypassed [label="gate_bypassed\nproject CI ran without\nuse project ci (closed)", fillcolor="#fde8e8", color="#b54848"]; + + start -> setup_required [label="discovery adds\nfork ci required", lhead=cluster_gated]; + setup_required -> awaiting_push [label="author enables\nthe workflow"]; + awaiting_push -> running [label="author pushes"]; + running -> failed [label="run fails"]; + running -> green [label="run passes"]; + running -> green_unverified [label="run passes,\nCI files changed"]; + failed -> running [label="author pushes", style=dashed]; + green -> running [label="author pushes", style=dashed]; + green_unverified -> running [label="author pushes", style=dashed]; + running -> setup_required [label="workflow disabled", style=dotted]; + awaiting_push -> setup_required [label="workflow disabled", style=dotted]; + + awaiting_push -> closed [label="30 days", ltail=cluster_gated]; + closed -> awaiting_push [label="reopened", style=dashed, lhead=cluster_gated]; + green_unverified -> released [label="maintainer adds\nuse project ci", ltail=cluster_gated]; + green -> ungated [label="base without fork CI", ltail=cluster_gated]; + failed -> gate_modified [label="PR changes the gate", ltail=cluster_gated]; + running -> gate_bypassed [label="gate tampering", ltail=cluster_gated]; +} +""" + + +def generate_diagram() -> None: + image_file = MY_DIR / f"{MY_FILENAME}.svg" + console.print(f"[bright_blue]Generating {image_file}") + graphviz.Source(DOT).render(outfile=image_file, format="svg", cleanup=True) + console.print(f"[green]Generated {image_file}") + + +if __name__ == "__main__": + generate_diagram() diff --git a/dev/breeze/doc/ci/images/diagram_fork_ci_states.svg b/dev/breeze/doc/ci/images/diagram_fork_ci_states.svg new file mode 100644 index 00000000000..2509036529c --- /dev/null +++ b/dev/breeze/doc/ci/images/diagram_fork_ci_states.svg @@ -0,0 +1,230 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<!-- Generated by graphviz version 16.1.0 (20260904.0139) + --> +<!-- Title: states Pages: 1 --> +<svg width="749pt" height="522pt" + viewBox="0.00 0.00 749.00 522.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 518.34)"> +<title>states</title> +<polygon fill="white" stroke="none" points="-4,4 -4,-518.34 745.38,-518.34 745.38,4 -4,4"/> +<g id="clust1" class="cluster"> +<title>cluster_gated</title> +<path fill="white" stroke="#8a96a3" d="M20,-83.5C20,-83.5 549,-83.5 549,-83.5 555,-83.5 561,-89.5 561,-95.5 561,-95.5 561,-441 561,-441 561,-447 555,-453 549,-453 549,-453 20,-453 20,-453 14,-453 8,-447 8,-441 8,-441 8,-95.5 8,-95.5 8,-89.5 14,-83.5 20,-83.5"/> +<text xml:space="preserve" text-anchor="middle" x="284.5" y="-437.6" font-family="Helvetica,sans-Serif" font-size="12.00">gated (label: fork ci required)</text> +</g> +<!-- start --> +<g id="node1" class="node"> +<title>start</title> +<ellipse fill="#33404d" stroke="#33404d" cx="370" cy="-506.42" rx="7.92" ry="7.92"/> +</g> +<!-- setup_required --> +<g id="node2" class="node"> +<title>setup_required</title> +<path fill="#f2f4f7" stroke="#5b6b80" d="M442.12,-424.25C442.12,-424.25 297.88,-424.25 297.88,-424.25 291.88,-424.25 285.88,-418.25 285.88,-412.25 285.88,-412.25 285.88,-392.25 285.88,-392.25 285.88,-386.25 291.88,-380.25 297.88,-380.25 297.88,-380.25 442.12,-380.25 442.12,-380.25 448.12,-380.25 454.12,-386.25 454.12,-392.25 454.12,-392.25 454.12,-412.25 454.12,-412.25 454.12,-418.25 448.12,-424.25 442.12,-424.25"/> +<text xml:space="preserve" text-anchor="middle" x="370" y="-409.8" font-family="Helvetica,sans-Serif" font-size="11.00">setup_required</text> +<text xml:space="preserve" text-anchor="middle" x="370" y="-397.8" font-family="Helvetica,sans-Serif" font-size="11.00">workflow not enabled in the fork</text> +<text xml:space="preserve" text-anchor="middle" x="370" y="-385.8" font-family="Helvetica,sans-Serif" font-size="11.00">(draft)</text> +</g> +<!-- start->setup_required --> +<g id="edge1" class="edge"> +<title>start->setup_required</title> +<path fill="none" stroke="#5b6b80" d="M370,-498.07C370,-490.53 370,-478 370,-464.49"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="373.5,-464.51 370,-454.51 366.5,-464.51 373.5,-464.51"/> +<text xml:space="preserve" text-anchor="middle" x="400.75" y="-471.95" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">discovery adds</text> +<text xml:space="preserve" text-anchor="middle" x="400.75" y="-462.2" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">fork ci required</text> +</g> +<!-- awaiting_push --> +<g id="node3" class="node"> +<title>awaiting_push</title> +<path fill="#f2f4f7" stroke="#5b6b80" d="M540.75,-324.75C540.75,-324.75 421.25,-324.75 421.25,-324.75 415.25,-324.75 409.25,-318.75 409.25,-312.75 409.25,-312.75 409.25,-292.75 409.25,-292.75 409.25,-286.75 415.25,-280.75 421.25,-280.75 421.25,-280.75 540.75,-280.75 540.75,-280.75 546.75,-280.75 552.75,-286.75 552.75,-292.75 552.75,-292.75 552.75,-312.75 552.75,-312.75 552.75,-318.75 546.75,-324.75 540.75,-324.75"/> +<text xml:space="preserve" text-anchor="middle" x="481" y="-310.3" font-family="Helvetica,sans-Serif" font-size="11.00">awaiting_push</text> +<text xml:space="preserve" text-anchor="middle" x="481" y="-298.3" font-family="Helvetica,sans-Serif" font-size="11.00">workflow enabled, no run</text> +<text xml:space="preserve" text-anchor="middle" x="481" y="-286.3" font-family="Helvetica,sans-Serif" font-size="11.00">for the head commit (draft)</text> +</g> +<!-- setup_required->awaiting_push --> +<g id="edge2" class="edge"> +<title>setup_required->awaiting_push</title> +<path fill="none" stroke="#5b6b80" d="M420.51,-379.82C429.23,-374.81 437.8,-368.95 445,-362.25 453.21,-354.61 460.24,-344.7 465.86,-335.21"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="468.88,-336.97 470.65,-326.53 462.75,-333.59 468.88,-336.97"/> +<text xml:space="preserve" text-anchor="middle" x="491.33" y="-353.7" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">author enables</text> +<text xml:space="preserve" text-anchor="middle" x="491.33" y="-343.95" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">the workflow</text> +</g> +<!-- awaiting_push->setup_required --> +<g id="edge11" class="edge"> +<title>awaiting_push->setup_required</title> +<path fill="none" stroke="#5b6b80" stroke-dasharray="1,5" d="M409.02,-320.22C388.33,-326.49 369.66,-334.21 363.5,-342.75 358.12,-350.21 357.32,-359.65 358.56,-368.76"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="355.12,-369.46 360.68,-378.48 361.96,-367.96 355.12,-369.46"/> +<text xml:space="preserve" text-anchor="middle" x="400.25" y="-348.82" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">workflow disabled</text> +</g> +<!-- running --> +<g id="node4" class="node"> +<title>running</title> +<path fill="#f2f4f7" stroke="#5b6b80" d="M346.5,-231C346.5,-231 261.5,-231 261.5,-231 255.5,-231 249.5,-225 249.5,-219 249.5,-219 249.5,-207 249.5,-207 249.5,-201 255.5,-195 261.5,-195 261.5,-195 346.5,-195 346.5,-195 352.5,-195 358.5,-201 358.5,-207 358.5,-207 358.5,-219 358.5,-219 358.5,-225 352.5,-231 346.5,-231"/> +<text xml:space="preserve" text-anchor="middle" x="304" y="-214.55" font-family="Helvetica,sans-Serif" font-size="11.00">running</text> +<text xml:space="preserve" text-anchor="middle" x="304" y="-202.55" font-family="Helvetica,sans-Serif" font-size="11.00">fork run in progress</text> +</g> +<!-- awaiting_push->running --> +<g id="edge3" class="edge"> +<title>awaiting_push->running</title> +<path fill="none" stroke="#5b6b80" d="M437.7,-280.28C410.84,-266.97 376.38,-249.88 349.18,-236.4"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="351,-233.4 340.49,-232.09 347.9,-239.67 351,-233.4"/> +<text xml:space="preserve" text-anchor="middle" x="427.06" y="-254.2" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">author pushes</text> +</g> +<!-- closed --> +<g id="node8" class="node"> +<title>closed</title> +<path fill="#eceff3" stroke="#8a96a3" d="M729.38,-235C729.38,-235 580.62,-235 580.62,-235 574.62,-235 568.62,-229 568.62,-223 568.62,-223 568.62,-203 568.62,-203 568.62,-197 574.62,-191 580.62,-191 580.62,-191 729.38,-191 729.38,-191 735.38,-191 741.38,-197 741.38,-203 741.38,-203 741.38,-223 741.38,-223 741.38,-229 735.38,-235 729.38,-235"/> +<text xml:space="preserve" text-anchor="middle" x="655" y="-220.55" font-family="Helvetica,sans-Serif" font-size="11.00">closed</text> +<text xml:space="preserve" text-anchor="middle" x="655" y="-208.55" font-family="Helvetica,sans-Serif" font-size="11.00">setup_required or awaiting_push</text> +<text xml:space="preserve" text-anchor="middle" x="655" y="-196.55" font-family="Helvetica,sans-Serif" font-size="11.00">for 30 days</text> +</g> +<!-- awaiting_push->closed --> +<g id="edge12" class="edge"> +<title>awaiting_push->closed</title> +<path fill="none" stroke="#5b6b80" d="M561,-250.35C568.46,-246.67 576.29,-243.13 584.11,-239.81"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="585.26,-243.12 593.16,-236.06 582.58,-236.65 585.26,-243.12"/> +<text xml:space="preserve" text-anchor="middle" x="571.88" y="-254.2" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">30 days</text> +</g> +<!-- running->setup_required --> +<g id="edge10" class="edge"> +<title>running->setup_required</title> +<path fill="none" stroke="#5b6b80" stroke-dasharray="1,5" d="M304.09,-231.47C304.72,-253.8 307.63,-293.33 319.5,-324.75 325.66,-341.04 335.78,-357.38 345.35,-370.76"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="342.48,-372.77 351.25,-378.71 348.1,-368.6 342.48,-372.77"/> +<text xml:space="preserve" text-anchor="middle" x="356.25" y="-299.07" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">workflow disabled</text> +</g> +<!-- failed --> +<g id="node5" class="node"> +<title>failed</title> +<path fill="#fde8e8" stroke="#b54848" d="M170.75,-135.5C170.75,-135.5 33.25,-135.5 33.25,-135.5 27.25,-135.5 21.25,-129.5 21.25,-123.5 21.25,-123.5 21.25,-103.5 21.25,-103.5 21.25,-97.5 27.25,-91.5 33.25,-91.5 33.25,-91.5 170.75,-91.5 170.75,-91.5 176.75,-91.5 182.75,-97.5 182.75,-103.5 182.75,-103.5 182.75,-123.5 182.75,-123.5 182.75,-129.5 176.75,-135.5 170.75,-135.5"/> +<text xml:space="preserve" text-anchor="middle" x="102" y="-121.05" font-family="Helvetica,sans-Serif" font-size="11.00">failed</text> +<text xml:space="preserve" text-anchor="middle" x="102" y="-109.05" font-family="Helvetica,sans-Serif" font-size="11.00">run failed, cancelled, timed out</text> +<text xml:space="preserve" text-anchor="middle" x="102" y="-97.05" font-family="Helvetica,sans-Serif" font-size="11.00">or could not start</text> +</g> +<!-- running->failed --> +<g id="edge4" class="edge"> +<title>running->failed</title> +<path fill="none" stroke="#5b6b80" d="M249.19,-211.8C181.07,-210.24 70.58,-203.01 44.75,-173 35.96,-162.79 41.54,-152.11 52.04,-142.72"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="53.96,-145.66 59.69,-136.75 49.65,-140.15 53.96,-145.66"/> +<text xml:space="preserve" text-anchor="middle" x="60.88" y="-159.57" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">run fails</text> +</g> +<!-- green --> +<g id="node6" class="node"> +<title>green</title> +<path fill="#e6f4ea" stroke="#3d8b57" d="M352.25,-135.5C352.25,-135.5 229.75,-135.5 229.75,-135.5 223.75,-135.5 217.75,-129.5 217.75,-123.5 217.75,-123.5 217.75,-103.5 217.75,-103.5 217.75,-97.5 223.75,-91.5 229.75,-91.5 229.75,-91.5 352.25,-91.5 352.25,-91.5 358.25,-91.5 364.25,-97.5 364.25,-103.5 364.25,-103.5 364.25,-123.5 364.25,-123.5 364.25,-129.5 358.25,-135.5 352.25,-135.5"/> +<text xml:space="preserve" text-anchor="middle" x="291" y="-121.05" font-family="Helvetica,sans-Serif" font-size="11.00">green</text> +<text xml:space="preserve" text-anchor="middle" x="291" y="-109.05" font-family="Helvetica,sans-Serif" font-size="11.00">no CI-defining change</text> +<text xml:space="preserve" text-anchor="middle" x="291" y="-97.05" font-family="Helvetica,sans-Serif" font-size="11.00">ready for maintainer review</text> +</g> +<!-- running->green --> +<g id="edge5" class="edge"> +<title>running->green</title> +<path fill="none" stroke="#5b6b80" d="M249.3,-201.32C234.03,-195.55 219.12,-186.66 210,-173 201.98,-160.99 207.75,-150.6 219.18,-142.05"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="221.06,-145.01 227.62,-136.69 217.3,-139.1 221.06,-145.01"/> +<text xml:space="preserve" text-anchor="middle" x="232.5" y="-159.57" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">run passes</text> +</g> +<!-- green_unverified --> +<g id="node7" class="node"> +<title>green_unverified</title> +<path fill="#fff6db" stroke="#b38a1d" d="M522.38,-135.5C522.38,-135.5 439.62,-135.5 439.62,-135.5 433.62,-135.5 427.62,-129.5 427.62,-123.5 427.62,-123.5 427.62,-103.5 427.62,-103.5 427.62,-97.5 433.62,-91.5 439.62,-91.5 439.62,-91.5 522.38,-91.5 522.38,-91.5 528.38,-91.5 534.38,-97.5 534.38,-103.5 534.38,-103.5 534.38,-123.5 534.38,-123.5 534.38,-129.5 528.38,-135.5 522.38,-135.5"/> +<text xml:space="preserve" text-anchor="middle" x="481" y="-121.05" font-family="Helvetica,sans-Serif" font-size="11.00">green_unverified</text> +<text xml:space="preserve" text-anchor="middle" x="481" y="-109.05" font-family="Helvetica,sans-Serif" font-size="11.00">CI-defining change</text> +<text xml:space="preserve" text-anchor="middle" x="481" y="-97.05" font-family="Helvetica,sans-Serif" font-size="11.00">needs project ci</text> +</g> +<!-- running->green_unverified --> +<g id="edge6" class="edge"> +<title>running->green_unverified</title> +<path fill="none" stroke="#5b6b80" d="M325.98,-194.76C342.46,-182.33 365.89,-165.66 388,-153.5 397.22,-148.43 407.24,-143.59 417.18,-139.15"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="418.3,-142.48 426.07,-135.28 415.51,-136.06 418.3,-142.48"/> +<text xml:space="preserve" text-anchor="middle" x="421" y="-164.45" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">run passes,</text> +<text xml:space="preserve" text-anchor="middle" x="421" y="-154.7" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">CI files changed</text> +</g> +<!-- gate_bypassed --> +<g id="node12" class="node"> +<title>gate_bypassed</title> +<path fill="#fde8e8" stroke="#b54848" d="M677.12,-135.5C677.12,-135.5 580.88,-135.5 580.88,-135.5 574.88,-135.5 568.88,-129.5 568.88,-123.5 568.88,-123.5 568.88,-103.5 568.88,-103.5 568.88,-97.5 574.88,-91.5 580.88,-91.5 580.88,-91.5 677.12,-91.5 677.12,-91.5 683.12,-91.5 689.12,-97.5 689.12,-103.5 689.12,-103.5 689.12,-123.5 689.12,-123.5 689.12,-129.5 683.12,-135.5 677.12,-135.5"/> +<text xml:space="preserve" text-anchor="middle" x="629" y="-121.05" font-family="Helvetica,sans-Serif" font-size="11.00">gate_bypassed</text> +<text xml:space="preserve" text-anchor="middle" x="629" y="-109.05" font-family="Helvetica,sans-Serif" font-size="11.00">project CI ran without</text> +<text xml:space="preserve" text-anchor="middle" x="629" y="-97.05" font-family="Helvetica,sans-Serif" font-size="11.00">use project ci (closed)</text> +</g> +<!-- running->gate_bypassed --> +<g id="edge17" class="edge"> +<title>running->gate_bypassed</title> +<path fill="none" stroke="#5b6b80" d="M561,-162.29C572.52,-156.1 583.57,-149.03 593.29,-142.27"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="594.98,-145.36 601.07,-136.69 590.91,-139.67 594.98,-145.36"/> +<text xml:space="preserve" text-anchor="middle" x="605.69" y="-159.57" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">gate tampering</text> +</g> +<!-- failed->running --> +<g id="edge7" class="edge"> +<title>failed->running</title> +<path fill="none" stroke="#5b6b80" stroke-dasharray="5,2" d="M110.73,-135.9C116.95,-148.52 126.51,-163.79 139.5,-173 168.09,-193.27 205.81,-203.12 237.91,-207.85"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="237.13,-211.28 247.5,-209.13 238.05,-204.34 237.13,-211.28"/> +<text xml:space="preserve" text-anchor="middle" x="168.75" y="-159.57" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">author pushes</text> +</g> +<!-- gate_modified --> +<g id="node11" class="node"> +<title>gate_modified</title> +<path fill="#fde8e8" stroke="#b54848" d="M169.25,-36C169.25,-36 34.75,-36 34.75,-36 28.75,-36 22.75,-30 22.75,-24 22.75,-24 22.75,-12 22.75,-12 22.75,-6 28.75,0 34.75,0 34.75,0 169.25,0 169.25,0 175.25,0 181.25,-6 181.25,-12 181.25,-12 181.25,-24 181.25,-24 181.25,-30 175.25,-36 169.25,-36"/> +<text xml:space="preserve" text-anchor="middle" x="102" y="-19.55" font-family="Helvetica,sans-Serif" font-size="11.00">gate_modified</text> +<text xml:space="preserve" text-anchor="middle" x="102" y="-7.55" font-family="Helvetica,sans-Serif" font-size="11.00">PR changes the gate (closed)</text> +</g> +<!-- failed->gate_modified --> +<g id="edge16" class="edge"> +<title>failed->gate_modified</title> +<path fill="none" stroke="#5b6b80" d="M102,-83.5C102,-72.17 102,-59.21 102,-47.89"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="105.5,-47.89 102,-37.89 98.5,-47.89 105.5,-47.89"/> +<text xml:space="preserve" text-anchor="middle" x="144.75" y="-60.08" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">PR changes the gate</text> +</g> +<!-- green->running --> +<g id="edge8" class="edge"> +<title>green->running</title> +<path fill="none" stroke="#5b6b80" stroke-dasharray="5,2" d="M290.22,-135.74C290.14,-146.9 290.57,-160.76 292.5,-173 293.05,-176.51 293.83,-180.15 294.73,-183.73"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="291.35,-184.63 297.45,-193.29 298.08,-182.72 291.35,-184.63"/> +<text xml:space="preserve" text-anchor="middle" x="321.75" y="-159.57" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">author pushes</text> +</g> +<!-- ungated --> +<g id="node10" class="node"> +<title>ungated</title> +<path fill="#f2f4f7" stroke="#5b6b80" d="M353,-36C353,-36 229,-36 229,-36 223,-36 217,-30 217,-24 217,-24 217,-12 217,-12 217,-6 223,0 229,0 229,0 353,0 353,0 359,0 365,-6 365,-12 365,-12 365,-24 365,-24 365,-30 359,-36 353,-36"/> +<text xml:space="preserve" text-anchor="middle" x="291" y="-19.55" font-family="Helvetica,sans-Serif" font-size="11.00">ungated</text> +<text xml:space="preserve" text-anchor="middle" x="291" y="-7.55" font-family="Helvetica,sans-Serif" font-size="11.00">base branch without fork CI</text> +</g> +<!-- green->ungated --> +<g id="edge15" class="edge"> +<title>green->ungated</title> +<path fill="none" stroke="#5b6b80" d="M291,-83.5C291,-72.17 291,-59.21 291,-47.89"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="294.5,-47.89 291,-37.89 287.5,-47.89 294.5,-47.89"/> +<text xml:space="preserve" text-anchor="middle" x="331.12" y="-60.08" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">base without fork CI</text> +</g> +<!-- green_unverified->running --> +<g id="edge9" class="edge"> +<title>green_unverified->running</title> +<path fill="none" stroke="#5b6b80" stroke-dasharray="5,2" d="M477.58,-135.96C474.5,-148.45 468.73,-163.55 458,-173 433.96,-194.18 400.03,-204.16 370.13,-208.76"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="369.85,-205.26 360.4,-210.06 370.78,-212.2 369.85,-205.26"/> +<text xml:space="preserve" text-anchor="middle" x="500.78" y="-159.57" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">author pushes</text> +</g> +<!-- released --> +<g id="node9" class="node"> +<title>released</title> +<path fill="#f2f4f7" stroke="#5b6b80" d="M551.62,-36C551.62,-36 410.38,-36 410.38,-36 404.38,-36 398.38,-30 398.38,-24 398.38,-24 398.38,-12 398.38,-12 398.38,-6 404.38,0 410.38,0 410.38,0 551.62,0 551.62,0 557.62,0 563.62,-6 563.62,-12 563.62,-12 563.62,-24 563.62,-24 563.62,-30 557.62,-36 551.62,-36"/> +<text xml:space="preserve" text-anchor="middle" x="481" y="-19.55" font-family="Helvetica,sans-Serif" font-size="11.00">released</text> +<text xml:space="preserve" text-anchor="middle" x="481" y="-7.55" font-family="Helvetica,sans-Serif" font-size="11.00">maintainer added use project ci</text> +</g> +<!-- green_unverified->released --> +<g id="edge14" class="edge"> +<title>green_unverified->released</title> +<path fill="none" stroke="#5b6b80" d="M481,-83.5C481,-72.17 481,-59.21 481,-47.89"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="484.5,-47.89 481,-37.89 477.5,-47.89 484.5,-47.89"/> +<text xml:space="preserve" text-anchor="middle" x="514" y="-64.95" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">maintainer adds</text> +<text xml:space="preserve" text-anchor="middle" x="514" y="-55.2" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">use project ci</text> +</g> +<!-- closed->awaiting_push --> +<g id="edge13" class="edge"> +<title>closed->awaiting_push</title> +<path fill="none" stroke="#5b6b80" stroke-dasharray="5,2" d="M631.14,-235.4C619.86,-244.72 605.85,-255.22 592,-262.75 583.04,-267.62 573.35,-272.08 563.56,-276.1"/> +<polygon fill="#5b6b80" stroke="#5b6b80" points="569.98,-269.27 562.37,-276.65 572.92,-275.62 569.98,-269.27"/> +<text xml:space="preserve" text-anchor="middle" x="626.73" y="-254.2" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#33404d">reopened</text> +</g> +</g> +</svg>
