This is an automated email from the ASF dual-hosted git repository.

uranusjr pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new fce3a58334 Implement context accessor for DatasetEvent extra (#38481)
fce3a58334 is described below

commit fce3a583348162f655282d032eca654dcb67b497
Author: Tzu-ping Chung <uranu...@gmail.com>
AuthorDate: Fri Mar 29 10:06:02 2024 +0800

    Implement context accessor for DatasetEvent extra (#38481)
---
 .pre-commit-config.yaml                            |   5 +
 airflow/datasets/__init__.py                       |  11 +-
 airflow/models/taskinstance.py                     |  14 ++-
 airflow/utils/context.py                           |  34 ++++++
 airflow/utils/context.pyi                          |  12 ++-
 contributing-docs/08_static_code_checks.rst        |   2 +
 dev/breeze/doc/images/output_static-checks.svg     | 114 +++++++++++----------
 dev/breeze/doc/images/output_static-checks.txt     |   2 +-
 dev/breeze/src/airflow_breeze/pre_commit_ids.py    |   1 +
 .../authoring-and-scheduling/datasets.rst          |  31 +++++-
 docs/apache-airflow/templates-ref.rst              |   2 +
 .../pre_commit_template_context_key_sync.py        |   0
 tests/models/test_taskinstance.py                  |  67 +++++++++++-
 tests/operators/test_python.py                     |   1 +
 14 files changed, 228 insertions(+), 68 deletions(-)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 1829f9b200..2f347b1c88 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -629,6 +629,11 @@ repos:
         entry: ./scripts/ci/pre_commit/pre_commit_sync_init_decorator.py
         pass_filenames: false
         files: 
^airflow/models/dag\.py$|^airflow/(?:decorators|utils)/task_group\.py$
+      - id: check-template-context-variable-in-sync
+        name: Check all template context variable references are in sync
+        language: python
+        entry: ./scripts/ci/pre_commit/pre_commit_template_context_key_sync.py
+        files: 
^airflow/models/taskinstance\.py$|^airflow/utils/context\.pyi?$|^docs/apache-airflow/templates-ref\.rst$
       - id: check-base-operator-usage
         language: pygrep
         name: Check BaseOperator core imports
diff --git a/airflow/datasets/__init__.py b/airflow/datasets/__init__.py
index 2507c69d01..d20d3b578e 100644
--- a/airflow/datasets/__init__.py
+++ b/airflow/datasets/__init__.py
@@ -42,7 +42,14 @@ def _get_uri_normalizer(scheme: str) -> 
Callable[[SplitResult], SplitResult] | N
     return ProvidersManager().dataset_uri_handlers.get(scheme)
 
 
-def _sanitize_uri(uri: str) -> str:
+def sanitize_uri(uri: str) -> str:
+    """Sanitize a dataset URI.
+
+    This checks for URI validity, and normalizes the URI if needed. A fully
+    normalized URI is returned.
+
+    :meta private:
+    """
     if not uri:
         raise ValueError("Dataset URI cannot be empty")
     if uri.isspace():
@@ -110,7 +117,7 @@ class Dataset(os.PathLike, BaseDatasetEventInput):
     """A representation of data dependencies between workflows."""
 
     uri: str = attr.field(
-        converter=_sanitize_uri,
+        converter=sanitize_uri,
         validator=[attr.validators.min_len(1), attr.validators.max_len(3000)],
     )
     extra: dict[str, Any] | None = None
diff --git a/airflow/models/taskinstance.py b/airflow/models/taskinstance.py
index 8bb9947327..c9bd2ce617 100644
--- a/airflow/models/taskinstance.py
+++ b/airflow/models/taskinstance.py
@@ -104,7 +104,13 @@ from airflow.templates import SandboxedEnvironment
 from airflow.ti_deps.dep_context import DepContext
 from airflow.ti_deps.dependencies_deps import REQUEUEABLE_DEPS, RUNNING_DEPS
 from airflow.utils import timezone
-from airflow.utils.context import ConnectionAccessor, Context, 
VariableAccessor, context_merge
+from airflow.utils.context import (
+    ConnectionAccessor,
+    Context,
+    DatasetEventAccessors,
+    VariableAccessor,
+    context_merge,
+)
 from airflow.utils.email import send_email
 from airflow.utils.helpers import prune_dict, render_template_to_string
 from airflow.utils.log.logging_mixin import LoggingMixin
@@ -766,6 +772,7 @@ def _get_template_context(
         "dag_run": dag_run,
         "data_interval_end": timezone.coerce_datetime(data_interval.end),
         "data_interval_start": timezone.coerce_datetime(data_interval.start),
+        "dataset_events": DatasetEventAccessors(),
         "ds": ds,
         "ds_nodash": ds_nodash,
         "execution_date": logical_date,
@@ -2569,7 +2576,7 @@ class TaskInstance(Base, LoggingMixin):
                 session.add(Log(self.state, self))
                 session.merge(self).task = self.task
                 if self.state == TaskInstanceState.SUCCESS:
-                    self._register_dataset_changes(session=session)
+                    
self._register_dataset_changes(events=context["dataset_events"], 
session=session)
 
                 session.commit()
                 if self.state == TaskInstanceState.SUCCESS:
@@ -2579,7 +2586,7 @@ class TaskInstance(Base, LoggingMixin):
 
             return None
 
-    def _register_dataset_changes(self, *, session: Session) -> None:
+    def _register_dataset_changes(self, *, events: DatasetEventAccessors, 
session: Session) -> None:
         if TYPE_CHECKING:
             assert self.task
 
@@ -2590,6 +2597,7 @@ class TaskInstance(Base, LoggingMixin):
                 dataset_manager.register_dataset_change(
                     task_instance=self,
                     dataset=obj,
+                    extra=events[obj].extra,
                     session=session,
                 )
 
diff --git a/airflow/utils/context.py b/airflow/utils/context.py
index 3501ca7dbc..033b7aa39d 100644
--- a/airflow/utils/context.py
+++ b/airflow/utils/context.py
@@ -36,8 +36,10 @@ from typing import (
     ValuesView,
 )
 
+import attrs
 import lazy_object_proxy
 
+from airflow.datasets import Dataset, sanitize_uri
 from airflow.exceptions import RemovedInAirflow3Warning
 from airflow.utils.types import NOTSET
 
@@ -54,6 +56,7 @@ KNOWN_CONTEXT_KEYS: set[str] = {
     "dag_run",
     "data_interval_end",
     "data_interval_start",
+    "dataset_events",
     "ds",
     "ds_nodash",
     "execution_date",
@@ -146,6 +149,37 @@ class ConnectionAccessor:
             return default_conn
 
 
+@attrs.define()
+class DatasetEventAccessor:
+    """Wrapper to access a DatasetEvent instance in template."""
+
+    extra: dict[str, Any]
+
+
+class DatasetEventAccessors(Mapping[str, DatasetEventAccessor]):
+    """Lazy mapping of dataset event accessors."""
+
+    def __init__(self) -> None:
+        self._dict: dict[str, DatasetEventAccessor] = {}
+
+    def __iter__(self) -> Iterator[str]:
+        return iter(self._dict)
+
+    def __len__(self) -> int:
+        return len(self._dict)
+
+    def __getitem__(self, key: str | Dataset) -> DatasetEventAccessor:
+        if isinstance(key, str):
+            uri = sanitize_uri(key)
+        elif isinstance(key, Dataset):
+            uri = key.uri
+        else:
+            return NotImplemented
+        if uri not in self._dict:
+            self._dict[uri] = DatasetEventAccessor({})
+        return self._dict[uri]
+
+
 class AirflowContextDeprecationWarning(RemovedInAirflow3Warning):
     """Warn for usage of deprecated context variables in a task."""
 
diff --git a/airflow/utils/context.pyi b/airflow/utils/context.pyi
index eb08201248..8b5deb4746 100644
--- a/airflow/utils/context.pyi
+++ b/airflow/utils/context.pyi
@@ -26,11 +26,12 @@
 # declare "these are defined, but don't error if others are accessed" someday.
 from __future__ import annotations
 
-from typing import Any, Collection, Container, Iterable, Mapping, overload
+from typing import Any, Collection, Container, Iterable, Iterator, Mapping, 
overload
 
 from pendulum import DateTime
 
 from airflow.configuration import AirflowConfigParser
+from airflow.datasets import Dataset
 from airflow.models.baseoperator import BaseOperator
 from airflow.models.dag import DAG
 from airflow.models.dagrun import DagRun
@@ -55,6 +56,14 @@ class VariableAccessor:
 class ConnectionAccessor:
     def get(self, key: str, default_conn: Any = None) -> Any: ...
 
+class DatasetEventAccessor:
+    extra: dict[str, Any]
+
+class DatasetEventAccessors(Mapping[str, DatasetEventAccessor]):
+    def __iter__(self) -> Iterator[str]: ...
+    def __len__(self) -> int: ...
+    def __getitem__(self, key: str | Dataset) -> DatasetEventAccessor: ...
+
 # NOTE: Please keep this in sync with the following:
 # * KNOWN_CONTEXT_KEYS in airflow/utils/context.py
 # * Table in docs/apache-airflow/templates-ref.rst
@@ -65,6 +74,7 @@ class Context(TypedDict, total=False):
     dag_run: DagRun | DagRunPydantic
     data_interval_end: DateTime
     data_interval_start: DateTime
+    dataset_events: DatasetEventAccessors
     ds: str
     ds_nodash: str
     exception: BaseException | str | None
diff --git a/contributing-docs/08_static_code_checks.rst 
b/contributing-docs/08_static_code_checks.rst
index 0b331bf3e9..c7be51b6a7 100644
--- a/contributing-docs/08_static_code_checks.rst
+++ b/contributing-docs/08_static_code_checks.rst
@@ -222,6 +222,8 @@ require Breeze Docker image to be built locally.
 
+-----------------------------------------------------------+--------------------------------------------------------------+---------+
 | check-system-tests-tocs                                   | Check that 
system tests is properly added                    |         |
 
+-----------------------------------------------------------+--------------------------------------------------------------+---------+
+| check-template-context-variable-in-sync                   | Check all 
template context variable references are in sync   |         |
++-----------------------------------------------------------+--------------------------------------------------------------+---------+
 | check-tests-in-the-right-folders                          | Check if tests 
are in the right folders                      |         |
 
+-----------------------------------------------------------+--------------------------------------------------------------+---------+
 | check-tests-unittest-testcase                             | Check that unit 
tests do not inherit from unittest.TestCase  |         |
diff --git a/dev/breeze/doc/images/output_static-checks.svg 
b/dev/breeze/doc/images/output_static-checks.svg
index 679db3dfee..a709f8070c 100644
--- a/dev/breeze/doc/images/output_static-checks.svg
+++ b/dev/breeze/doc/images/output_static-checks.svg
@@ -1,4 +1,4 @@
-<svg class="rich-terminal" viewBox="0 0 1482 2099.6" 
xmlns="http://www.w3.org/2000/svg";>
+<svg class="rich-terminal" viewBox="0 0 1482 2124.0" 
xmlns="http://www.w3.org/2000/svg";>
     <!-- Generated with Rich https://www.textualize.io -->
     <style>
 
@@ -43,7 +43,7 @@
 
     <defs>
     <clipPath id="breeze-static-checks-clip-terminal">
-      <rect x="0" y="0" width="1463.0" height="2048.6" />
+      <rect x="0" y="0" width="1463.0" height="2073.0" />
     </clipPath>
     <clipPath id="breeze-static-checks-line-0">
     <rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -294,9 +294,12 @@
 <clipPath id="breeze-static-checks-line-82">
     <rect x="0" y="2002.3" width="1464" height="24.65"/>
             </clipPath>
+<clipPath id="breeze-static-checks-line-83">
+    <rect x="0" y="2026.7" width="1464" height="24.65"/>
+            </clipPath>
     </defs>
 
-    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="2097.6" rx="8"/><text 
class="breeze-static-checks-title" fill="#c5c8c6" text-anchor="middle" x="740" 
y="27">Command:&#160;static-checks</text>
+    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="2122" rx="8"/><text 
class="breeze-static-checks-title" fill="#c5c8c6" text-anchor="middle" x="740" 
y="27">Command:&#160;static-checks</text>
             <g transform="translate(26,22)">
             <circle cx="0" cy="0" r="7" fill="#ff5f57"/>
             <circle cx="22" cy="0" r="7" fill="#febc2e"/>
@@ -338,58 +341,59 @@
 </text><text class="breeze-static-checks-r5" x="0" y="727.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-29)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="727.6" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-29)">check-pydevd-left-in-code&#160;|&#160;check-revision-heads-map&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</t
 [...]
 </text><text class="breeze-static-checks-r5" x="0" y="752" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-30)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="752" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-30)">check-safe-filter-usage-in-html&#160;|&#160;check-sql-dependency-common-data-structure&#160;|&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="752" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-30) [...]
 </text><text class="breeze-static-checks-r5" x="0" y="776.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-31)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="776.4" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-31)">check-start-date-not-used-in-defaults&#160;|&#160;check-system-tests-present&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="776.4" textLen [...]
-</text><text class="breeze-static-checks-r5" x="0" y="800.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-32)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="800.8" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-32)">check-system-tests-tocs&#160;|&#160;check-tests-in-the-right-folders&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static [...]
-</text><text class="breeze-static-checks-r5" x="0" y="825.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-33)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="825.2" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-33)">check-tests-unittest-testcase&#160;|&#160;check-urlparse-usage-in-code&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5 [...]
-</text><text class="breeze-static-checks-r5" x="0" y="849.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-34)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="849.6" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-34)">check-usage-of-re2-over-re&#160;|&#160;check-xml&#160;|&#160;codespell&#160;|&#160;compile-www-assets&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="849.6" textLength=" [...]
-</text><text class="breeze-static-checks-r5" x="0" y="874" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-35)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="874" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-35)">compile-www-assets-dev&#160;|&#160;create-missing-init-py-files-tests&#160;|&#160;debug-statements&#160;|&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="874" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-35) [...]
-</text><text class="breeze-static-checks-r5" x="0" y="898.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-36)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="898.4" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-36)">detect-private-key&#160;|&#160;doctoc&#160;|&#160;end-of-file-fixer&#160;|&#160;fix-encoding-pragma&#160;|&#160;flynt&#160;|&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="898.4" textLength="12.2" 
clip-path="url [...]
-</text><text class="breeze-static-checks-r5" x="0" y="922.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-37)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="922.8" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-37)">generate-airflow-diagrams&#160;|&#160;generate-pypi-readme&#160;|&#160;identity&#160;|&#160;insert-license&#160;|&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="922.8" textLength="12.2" 
clip-path="url(#bre [...]
-</text><text class="breeze-static-checks-r5" x="0" y="947.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-38)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="947.2" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-38)">kubeconform&#160;|&#160;lint-chart-schema&#160;|&#160;lint-css&#160;|&#160;lint-dockerfile&#160;|&#160;lint-helm-chart&#160;|&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="947.2" textLength="12.2" 
clip-path="url(#bre [...]
-</text><text class="breeze-static-checks-r5" x="0" y="971.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-39)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="971.6" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-39)">lint-json-schema&#160;|&#160;lint-markdown&#160;|&#160;lint-openapi&#160;|&#160;mixed-line-ending&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y= [...]
-</text><text class="breeze-static-checks-r5" x="0" y="996" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-40)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="996" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-40)">mypy-airflow&#160;|&#160;mypy-dev&#160;|&#160;mypy-docs&#160;|&#160;mypy-providers&#160;|&#160;pretty-format-json&#160;|&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="996" textLength="12.2"  [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1020.4" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-41)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1020.4" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-41)">pylint&#160;|&#160;python-no-log-warn&#160;|&#160;replace-bad-characters&#160;|&#160;rst-backticks&#160;|&#160;ruff&#160;|&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="1020.4" textLength="12.2" c [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1044.8" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-42)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1044.8" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-42)">ruff-format&#160;|&#160;shellcheck&#160;|&#160;trailing-whitespace&#160;|&#160;ts-compile-format-lint-www&#160;|&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="1044.8" textLength="12.2" 
clip-path=" [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1069.2" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-43)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1069.2" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-43)">update-black-version&#160;|&#160;update-breeze-cmd-output&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;
 [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1093.6" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-44)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1093.6" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-44)">update-breeze-readme-config-hash&#160;|&#160;update-build-dependencies&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks- [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1118" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-45)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1118" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-45)">update-chart-dependencies&#160;|&#160;update-common-sql-api-stubs&#160;|&#160;update-er-diagram&#160;|&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="1118" textLength="12.2" 
clip-path="url(#breeze-stat [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1142.4" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-46)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1142.4" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-46)">update-extras&#160;|&#160;update-in-the-wild-to-be-sorted&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;
 [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1166.8" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-47)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1166.8" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-47)">update-inlined-dockerfile-scripts&#160;|&#160;update-installed-providers-to-be-sorted&#160;|&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="1166.8" textLength="12.2" 
clip-path="url(#breeze-static-c [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1191.2" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-48)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1191.2" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-48)">update-installers&#160;|&#160;update-local-yml-file&#160;|&#160;update-migration-references&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="1191.2" textLength="12.2" c [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1215.6" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-49)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1215.6" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-49)">update-providers-dependencies&#160;|&#160;update-reproducible-source-date-epoch&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="1215.6" textLength="12.2" c [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1240" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-50)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1240" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-50)">update-spelling-wordlist-to-be-sorted&#160;|&#160;update-supported-versions&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="1240" textL [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1264.4" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-51)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1264.4" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-51)">update-vendored-in-k8s-json-schema&#160;|&#160;update-version&#160;|&#160;validate-operators-init&#160;|&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="1264.4" textLength="12.2" 
clip-path="url(#breeze-static-c [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1288.8" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-52)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1288.8" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-52)">yamllint)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&
 [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1313.2" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-53)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1313.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-53)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1313.2" textLength="61" 
clip-path="url(#breeze-static-checks-line-53)">-show</text><text 
class="breeze-static-checks-r4" x="97.6" y="1313.2" textLength="195.2" 
clip-path="url(# [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1337.6" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-54)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1337.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-54)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1337.6" textLength="134.2" 
clip-path="url(#breeze-static-checks-line-54)">-initialize</text><text 
class="breeze-static-checks-r4" x="170.8" y="1337.6" textLength="146.4" clip-p 
[...]
-</text><text class="breeze-static-checks-r5" x="0" y="1362" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-55)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1362" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-55)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1362" textLength="48.8" 
clip-path="url(#breeze-static-checks-line-55)">-max</text><text 
class="breeze-static-checks-r4" x="85.4" y="1362" textLength="292.8" 
clip-path="url(#breeze- [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1386.4" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-56)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1386.4" textLength="854" 
clip-path="url(#breeze-static-checks-line-56)">(INTEGER&#160;RANGE)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#16
 [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1410.8" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-57)">│</text><text 
class="breeze-static-checks-r5" x="451.4" y="1410.8" textLength="854" 
clip-path="url(#breeze-static-checks-line-57)">[default:&#160;3;&#160;1&lt;=x&lt;=10]&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#16
 [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1435.2" 
textLength="1464" 
clip-path="url(#breeze-static-checks-line-58)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-static-checks-r1" x="1464" y="1435.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-58)">
-</text><text class="breeze-static-checks-r5" x="0" y="1459.6" 
textLength="24.4" clip-path="url(#breeze-static-checks-line-59)">╭─</text><text 
class="breeze-static-checks-r5" x="24.4" y="1459.6" textLength="463.6" 
clip-path="url(#breeze-static-checks-line-59)">&#160;Selecting&#160;files&#160;to&#160;run&#160;the&#160;checks&#160;on&#160;</text><text
 class="breeze-static-checks-r5" x="488" y="1459.6" textLength="951.6" 
clip-path="url(#breeze-static-checks-line-59)">──────────────────────── [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1484" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-60)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1484" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-60)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1484" textLength="61" 
clip-path="url(#breeze-static-checks-line-60)">-file</text><text 
class="breeze-static-checks-r6" x="256.2" y="1484" textLength="24.4" 
clip-path="url(#breeze-s [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1508.4" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-61)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1508.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-61)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1508.4" textLength="48.8" 
clip-path="url(#breeze-static-checks-line-61)">-all</text><text 
class="breeze-static-checks-r4" x="85.4" y="1508.4" textLength="73.2" 
clip-path="url(# [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1532.8" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-62)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1532.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-62)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1532.8" textLength="85.4" 
clip-path="url(#breeze-static-checks-line-62)">-commit</text><text 
class="breeze-static-checks-r4" x="122" y="1532.8" textLength="48.8" 
clip-path="url [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1557.2" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-63)">│</text><text 
class="breeze-static-checks-r1" x="305" y="1557.2" textLength="183" 
clip-path="url(#breeze-static-checks-line-63)">exclusive&#160;with&#160;</text><text
 class="breeze-static-checks-r4" x="488" y="1557.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-63)">-</text><text 
class="breeze-static-checks-r4" x="500.2" y="1557.2" textLength="61" [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1581.6" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-64)">│</text><text 
class="breeze-static-checks-r7" x="305" y="1581.6" textLength="1134.6" 
clip-path="url(#breeze-static-checks-line-64)">(TEXT)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160
 [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1606" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-65)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1606" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-65)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1606" textLength="61" 
clip-path="url(#breeze-static-checks-line-65)">-last</text><text 
class="breeze-static-checks-r4" x="97.6" y="1606" textLength="85.4" 
clip-path="url(#breeze-st [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1630.4" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-66)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1630.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-66)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1630.4" textLength="61" 
clip-path="url(#breeze-static-checks-line-66)">-only</text><text 
class="breeze-static-checks-r4" x="97.6" y="1630.4" textLength="134.2" 
clip-path="url(# [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1654.8" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-67)">│</text><text 
class="breeze-static-checks-r1" x="305" y="1654.8" textLength="1134.6" 
clip-path="url(#breeze-static-checks-line-67)">branch&#160;and&#160;HEAD&#160;of&#160;your&#160;branch.&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#1
 [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1679.2" 
textLength="1464" 
clip-path="url(#breeze-static-checks-line-68)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-static-checks-r1" x="1464" y="1679.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-68)">
-</text><text class="breeze-static-checks-r5" x="0" y="1703.6" 
textLength="24.4" clip-path="url(#breeze-static-checks-line-69)">╭─</text><text 
class="breeze-static-checks-r5" x="24.4" y="1703.6" textLength="463.6" 
clip-path="url(#breeze-static-checks-line-69)">&#160;Building&#160;image&#160;before&#160;running&#160;checks&#160;</text><text
 class="breeze-static-checks-r5" x="488" y="1703.6" textLength="951.6" 
clip-path="url(#breeze-static-checks-line-69)">──────────────────────────────────
 [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1728" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-70)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1728" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-70)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1728" textLength="61" 
clip-path="url(#breeze-static-checks-line-70)">-skip</text><text 
class="breeze-static-checks-r4" x="97.6" y="1728" textLength="244" 
clip-path="url(#breeze-sta [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1752.4" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-71)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1752.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-71)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1752.4" textLength="73.2" 
clip-path="url(#breeze-static-checks-line-71)">-force</text><text 
class="breeze-static-checks-r4" x="109.8" y="1752.4" textLength="73.2" 
clip-path="ur [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1776.8" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-72)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1776.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-72)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1776.8" textLength="73.2" 
clip-path="url(#breeze-static-checks-line-72)">-image</text><text 
class="breeze-static-checks-r4" x="109.8" y="1776.8" textLength="48.8" 
clip-path="ur [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1801.2" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-73)">│</text><text 
class="breeze-static-checks-r7" x="414.8" y="1801.2" textLength="963.8" 
clip-path="url(#breeze-static-checks-line-73)">(TEXT)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#16
 [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1825.6" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-74)">│</text><text 
class="breeze-static-checks-r5" x="414.8" y="1825.6" textLength="963.8" 
clip-path="url(#breeze-static-checks-line-74)">[default:&#160;latest]&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;
 [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1850" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-75)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1850" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-75)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1850" textLength="85.4" 
clip-path="url(#breeze-static-checks-line-75)">-github</text><text 
class="breeze-static-checks-r4" x="122" y="1850" textLength="134.2" 
clip-path="url(#breez [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1874.4" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-76)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1874.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-76)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1874.4" textLength="97.6" 
clip-path="url(#breeze-static-checks-line-76)">-builder</text><text 
class="breeze-static-checks-r1" x="414.8" y="1874.4" textLength="756.4" 
clip-path= [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1898.8" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-77)">│</text><text 
class="breeze-static-checks-r5" x="414.8" y="1898.8" textLength="756.4" 
clip-path="url(#breeze-static-checks-line-77)">[default:&#160;autodetect]&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#
 [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1923.2" 
textLength="1464" 
clip-path="url(#breeze-static-checks-line-78)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-static-checks-r1" x="1464" y="1923.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-78)">
-</text><text class="breeze-static-checks-r5" x="0" y="1947.6" 
textLength="24.4" clip-path="url(#breeze-static-checks-line-79)">╭─</text><text 
class="breeze-static-checks-r5" x="24.4" y="1947.6" textLength="195.2" 
clip-path="url(#breeze-static-checks-line-79)">&#160;Common&#160;options&#160;</text><text
 class="breeze-static-checks-r5" x="219.6" y="1947.6" textLength="1220" 
clip-path="url(#breeze-static-checks-line-79)">──────────────────────────────────────────────────────────────────────
 [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1972" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-80)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1972" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-80)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1972" textLength="48.8" 
clip-path="url(#breeze-static-checks-line-80)">-dry</text><text 
class="breeze-static-checks-r4" x="85.4" y="1972" textLength="48.8" 
clip-path="url(#breeze-s [...]
-</text><text class="breeze-static-checks-r5" x="0" y="1996.4" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-81)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1996.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-81)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1996.4" textLength="97.6" 
clip-path="url(#breeze-static-checks-line-81)">-verbose</text><text 
class="breeze-static-checks-r6" x="158.6" y="1996.4" textLength="24.4" 
clip-path=" [...]
-</text><text class="breeze-static-checks-r5" x="0" y="2020.8" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-82)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="2020.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-82)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="2020.8" textLength="61" 
clip-path="url(#breeze-static-checks-line-82)">-help</text><text 
class="breeze-static-checks-r6" x="158.6" y="2020.8" textLength="24.4" 
clip-path="url(# [...]
-</text><text class="breeze-static-checks-r5" x="0" y="2045.2" 
textLength="1464" 
clip-path="url(#breeze-static-checks-line-83)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-static-checks-r1" x="1464" y="2045.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-83)">
+</text><text class="breeze-static-checks-r5" x="0" y="800.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-32)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="800.8" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-32)">check-system-tests-tocs&#160;|&#160;check-template-context-variable-in-sync&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="800.8" te [...]
+</text><text class="breeze-static-checks-r5" x="0" y="825.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-33)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="825.2" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-33)">check-tests-in-the-right-folders&#160;|&#160;check-tests-unittest-testcase&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="825. [...]
+</text><text class="breeze-static-checks-r5" x="0" y="849.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-34)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="849.6" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-34)">check-urlparse-usage-in-code&#160;|&#160;check-usage-of-re2-over-re&#160;|&#160;check-xml&#160;|&#160;codespell</text><text
 class="breeze-static-checks-r5" x="1451.8" y="849.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-li [...]
+</text><text class="breeze-static-checks-r5" x="0" y="874" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-35)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="874" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-35)">|&#160;compile-www-assets&#160;|&#160;compile-www-assets-dev&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#1
 [...]
+</text><text class="breeze-static-checks-r5" x="0" y="898.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-36)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="898.4" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-36)">create-missing-init-py-files-tests&#160;|&#160;debug-statements&#160;|&#160;detect-private-key&#160;|&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="898.4" textLength="12.2" 
clip-path="url(#bre [...]
+</text><text class="breeze-static-checks-r5" x="0" y="922.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-37)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="922.8" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-37)">doctoc&#160;|&#160;end-of-file-fixer&#160;|&#160;fix-encoding-pragma&#160;|&#160;flynt&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</t
 [...]
+</text><text class="breeze-static-checks-r5" x="0" y="947.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-38)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="947.2" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-38)">generate-airflow-diagrams&#160;|&#160;generate-pypi-readme&#160;|&#160;identity&#160;|&#160;insert-license&#160;|&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="947.2" textLength="12.2" 
clip-path="url(#bre [...]
+</text><text class="breeze-static-checks-r5" x="0" y="971.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-39)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="971.6" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-39)">kubeconform&#160;|&#160;lint-chart-schema&#160;|&#160;lint-css&#160;|&#160;lint-dockerfile&#160;|&#160;lint-helm-chart&#160;|&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="971.6" textLength="12.2" 
clip-path="url(#bre [...]
+</text><text class="breeze-static-checks-r5" x="0" y="996" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-40)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="996" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-40)">lint-json-schema&#160;|&#160;lint-markdown&#160;|&#160;lint-openapi&#160;|&#160;mixed-line-ending&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="996 [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1020.4" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-41)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1020.4" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-41)">mypy-airflow&#160;|&#160;mypy-dev&#160;|&#160;mypy-docs&#160;|&#160;mypy-providers&#160;|&#160;pretty-format-json&#160;|&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="1020.4" textLengt [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1044.8" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-42)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1044.8" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-42)">pylint&#160;|&#160;python-no-log-warn&#160;|&#160;replace-bad-characters&#160;|&#160;rst-backticks&#160;|&#160;ruff&#160;|&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="1044.8" textLength="12.2" c [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1069.2" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-43)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1069.2" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-43)">ruff-format&#160;|&#160;shellcheck&#160;|&#160;trailing-whitespace&#160;|&#160;ts-compile-format-lint-www&#160;|&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="1069.2" textLength="12.2" 
clip-path=" [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1093.6" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-44)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1093.6" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-44)">update-black-version&#160;|&#160;update-breeze-cmd-output&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;
 [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1118" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-45)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1118" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-45)">update-breeze-readme-config-hash&#160;|&#160;update-build-dependencies&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5"  [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1142.4" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-46)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1142.4" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-46)">update-chart-dependencies&#160;|&#160;update-common-sql-api-stubs&#160;|&#160;update-er-diagram&#160;|&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="1142.4" textLength="12.2" 
clip-path="url(#breez [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1166.8" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-47)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1166.8" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-47)">update-extras&#160;|&#160;update-in-the-wild-to-be-sorted&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;
 [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1191.2" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-48)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1191.2" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-48)">update-inlined-dockerfile-scripts&#160;|&#160;update-installed-providers-to-be-sorted&#160;|&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="1191.2" textLength="12.2" 
clip-path="url(#breeze-static-c [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1215.6" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-49)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1215.6" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-49)">update-installers&#160;|&#160;update-local-yml-file&#160;|&#160;update-migration-references&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="1215.6" textLength="12.2" c [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1240" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-50)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1240" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-50)">update-providers-dependencies&#160;|&#160;update-reproducible-source-date-epoch&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="1240" textLength="12.2" clip-pa 
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="1264.4" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-51)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1264.4" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-51)">update-spelling-wordlist-to-be-sorted&#160;|&#160;update-supported-versions&#160;|&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="1264.4" [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1288.8" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-52)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1288.8" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-52)">update-vendored-in-k8s-json-schema&#160;|&#160;update-version&#160;|&#160;validate-operators-init&#160;|&#160;&#160;</text><text
 class="breeze-static-checks-r5" x="1451.8" y="1288.8" textLength="12.2" 
clip-path="url(#breeze-static-c [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1313.2" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-53)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1313.2" textLength="988.2" 
clip-path="url(#breeze-static-checks-line-53)">yamllint)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&
 [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1337.6" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-54)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1337.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-54)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1337.6" textLength="61" 
clip-path="url(#breeze-static-checks-line-54)">-show</text><text 
class="breeze-static-checks-r4" x="97.6" y="1337.6" textLength="195.2" 
clip-path="url(# [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1362" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-55)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1362" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-55)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1362" textLength="134.2" 
clip-path="url(#breeze-static-checks-line-55)">-initialize</text><text 
class="breeze-static-checks-r4" x="170.8" y="1362" textLength="146.4" 
clip-path="url [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1386.4" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-56)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1386.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-56)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1386.4" textLength="48.8" 
clip-path="url(#breeze-static-checks-line-56)">-max</text><text 
class="breeze-static-checks-r4" x="85.4" y="1386.4" textLength="292.8" 
clip-path="url( [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1410.8" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-57)">│</text><text 
class="breeze-static-checks-r7" x="451.4" y="1410.8" textLength="854" 
clip-path="url(#breeze-static-checks-line-57)">(INTEGER&#160;RANGE)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#16
 [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1435.2" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-58)">│</text><text 
class="breeze-static-checks-r5" x="451.4" y="1435.2" textLength="854" 
clip-path="url(#breeze-static-checks-line-58)">[default:&#160;3;&#160;1&lt;=x&lt;=10]&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#16
 [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1459.6" 
textLength="1464" 
clip-path="url(#breeze-static-checks-line-59)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-static-checks-r1" x="1464" y="1459.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-59)">
+</text><text class="breeze-static-checks-r5" x="0" y="1484" textLength="24.4" 
clip-path="url(#breeze-static-checks-line-60)">╭─</text><text 
class="breeze-static-checks-r5" x="24.4" y="1484" textLength="463.6" 
clip-path="url(#breeze-static-checks-line-60)">&#160;Selecting&#160;files&#160;to&#160;run&#160;the&#160;checks&#160;on&#160;</text><text
 class="breeze-static-checks-r5" x="488" y="1484" textLength="951.6" 
clip-path="url(#breeze-static-checks-line-60)">────────────────────────────── 
[...]
+</text><text class="breeze-static-checks-r5" x="0" y="1508.4" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-61)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1508.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-61)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1508.4" textLength="61" 
clip-path="url(#breeze-static-checks-line-61)">-file</text><text 
class="breeze-static-checks-r6" x="256.2" y="1508.4" textLength="24.4" 
clip-path="url(# [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1532.8" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-62)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1532.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-62)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1532.8" textLength="48.8" 
clip-path="url(#breeze-static-checks-line-62)">-all</text><text 
class="breeze-static-checks-r4" x="85.4" y="1532.8" textLength="73.2" 
clip-path="url(# [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1557.2" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-63)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1557.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-63)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1557.2" textLength="85.4" 
clip-path="url(#breeze-static-checks-line-63)">-commit</text><text 
class="breeze-static-checks-r4" x="122" y="1557.2" textLength="48.8" 
clip-path="url [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1581.6" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-64)">│</text><text 
class="breeze-static-checks-r1" x="305" y="1581.6" textLength="183" 
clip-path="url(#breeze-static-checks-line-64)">exclusive&#160;with&#160;</text><text
 class="breeze-static-checks-r4" x="488" y="1581.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-64)">-</text><text 
class="breeze-static-checks-r4" x="500.2" y="1581.6" textLength="61" [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1606" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-65)">│</text><text 
class="breeze-static-checks-r7" x="305" y="1606" textLength="1134.6" 
clip-path="url(#breeze-static-checks-line-65)">(TEXT)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#1
 [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1630.4" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-66)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1630.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-66)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1630.4" textLength="61" 
clip-path="url(#breeze-static-checks-line-66)">-last</text><text 
class="breeze-static-checks-r4" x="97.6" y="1630.4" textLength="85.4" 
clip-path="url(#b [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1654.8" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-67)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1654.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-67)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1654.8" textLength="61" 
clip-path="url(#breeze-static-checks-line-67)">-only</text><text 
class="breeze-static-checks-r4" x="97.6" y="1654.8" textLength="134.2" 
clip-path="url(# [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1679.2" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-68)">│</text><text 
class="breeze-static-checks-r1" x="305" y="1679.2" textLength="1134.6" 
clip-path="url(#breeze-static-checks-line-68)">branch&#160;and&#160;HEAD&#160;of&#160;your&#160;branch.&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#1
 [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1703.6" 
textLength="1464" 
clip-path="url(#breeze-static-checks-line-69)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-static-checks-r1" x="1464" y="1703.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-69)">
+</text><text class="breeze-static-checks-r5" x="0" y="1728" textLength="24.4" 
clip-path="url(#breeze-static-checks-line-70)">╭─</text><text 
class="breeze-static-checks-r5" x="24.4" y="1728" textLength="463.6" 
clip-path="url(#breeze-static-checks-line-70)">&#160;Building&#160;image&#160;before&#160;running&#160;checks&#160;</text><text
 class="breeze-static-checks-r5" x="488" y="1728" textLength="951.6" 
clip-path="url(#breeze-static-checks-line-70)">────────────────────────────────────────
 [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1752.4" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-71)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1752.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-71)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1752.4" textLength="61" 
clip-path="url(#breeze-static-checks-line-71)">-skip</text><text 
class="breeze-static-checks-r4" x="97.6" y="1752.4" textLength="244" 
clip-path="url(#br [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1776.8" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-72)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1776.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-72)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1776.8" textLength="73.2" 
clip-path="url(#breeze-static-checks-line-72)">-force</text><text 
class="breeze-static-checks-r4" x="109.8" y="1776.8" textLength="73.2" 
clip-path="ur [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1801.2" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-73)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1801.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-73)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1801.2" textLength="73.2" 
clip-path="url(#breeze-static-checks-line-73)">-image</text><text 
class="breeze-static-checks-r4" x="109.8" y="1801.2" textLength="48.8" 
clip-path="ur [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1825.6" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-74)">│</text><text 
class="breeze-static-checks-r7" x="414.8" y="1825.6" textLength="963.8" 
clip-path="url(#breeze-static-checks-line-74)">(TEXT)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#16
 [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1850" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-75)">│</text><text 
class="breeze-static-checks-r5" x="414.8" y="1850" textLength="963.8" 
clip-path="url(#breeze-static-checks-line-75)">[default:&#160;latest]&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#16
 [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1874.4" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-76)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1874.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-76)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1874.4" textLength="85.4" 
clip-path="url(#breeze-static-checks-line-76)">-github</text><text 
class="breeze-static-checks-r4" x="122" y="1874.4" textLength="134.2" 
clip-path="ur [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1898.8" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-77)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1898.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-77)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1898.8" textLength="97.6" 
clip-path="url(#breeze-static-checks-line-77)">-builder</text><text 
class="breeze-static-checks-r1" x="414.8" y="1898.8" textLength="756.4" 
clip-path= [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1923.2" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-78)">│</text><text 
class="breeze-static-checks-r5" x="414.8" y="1923.2" textLength="756.4" 
clip-path="url(#breeze-static-checks-line-78)">[default:&#160;autodetect]&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#
 [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1947.6" 
textLength="1464" 
clip-path="url(#breeze-static-checks-line-79)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-static-checks-r1" x="1464" y="1947.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-79)">
+</text><text class="breeze-static-checks-r5" x="0" y="1972" textLength="24.4" 
clip-path="url(#breeze-static-checks-line-80)">╭─</text><text 
class="breeze-static-checks-r5" x="24.4" y="1972" textLength="195.2" 
clip-path="url(#breeze-static-checks-line-80)">&#160;Common&#160;options&#160;</text><text
 class="breeze-static-checks-r5" x="219.6" y="1972" textLength="1220" 
clip-path="url(#breeze-static-checks-line-80)">────────────────────────────────────────────────────────────────────────────
 [...]
+</text><text class="breeze-static-checks-r5" x="0" y="1996.4" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-81)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="1996.4" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-81)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="1996.4" textLength="48.8" 
clip-path="url(#breeze-static-checks-line-81)">-dry</text><text 
class="breeze-static-checks-r4" x="85.4" y="1996.4" textLength="48.8" 
clip-path="url(# [...]
+</text><text class="breeze-static-checks-r5" x="0" y="2020.8" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-82)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="2020.8" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-82)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="2020.8" textLength="97.6" 
clip-path="url(#breeze-static-checks-line-82)">-verbose</text><text 
class="breeze-static-checks-r6" x="158.6" y="2020.8" textLength="24.4" 
clip-path=" [...]
+</text><text class="breeze-static-checks-r5" x="0" y="2045.2" 
textLength="12.2" clip-path="url(#breeze-static-checks-line-83)">│</text><text 
class="breeze-static-checks-r4" x="24.4" y="2045.2" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-83)">-</text><text 
class="breeze-static-checks-r4" x="36.6" y="2045.2" textLength="61" 
clip-path="url(#breeze-static-checks-line-83)">-help</text><text 
class="breeze-static-checks-r6" x="158.6" y="2045.2" textLength="24.4" 
clip-path="url(# [...]
+</text><text class="breeze-static-checks-r5" x="0" y="2069.6" 
textLength="1464" 
clip-path="url(#breeze-static-checks-line-84)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-static-checks-r1" x="1464" y="2069.6" textLength="12.2" 
clip-path="url(#breeze-static-checks-line-84)">
 </text>
     </g>
     </g>
diff --git a/dev/breeze/doc/images/output_static-checks.txt 
b/dev/breeze/doc/images/output_static-checks.txt
index 66ca569ffb..10228461e0 100644
--- a/dev/breeze/doc/images/output_static-checks.txt
+++ b/dev/breeze/doc/images/output_static-checks.txt
@@ -1 +1 @@
-e8fa3d7a6215d2565dc536cbc50e0465
+4dc5653769bd03c4d07f6d998cdcb679
diff --git a/dev/breeze/src/airflow_breeze/pre_commit_ids.py 
b/dev/breeze/src/airflow_breeze/pre_commit_ids.py
index 516fc85c51..867f16e0a9 100644
--- a/dev/breeze/src/airflow_breeze/pre_commit_ids.py
+++ b/dev/breeze/src/airflow_breeze/pre_commit_ids.py
@@ -76,6 +76,7 @@ PRE_COMMIT_LIST = [
     "check-start-date-not-used-in-defaults",
     "check-system-tests-present",
     "check-system-tests-tocs",
+    "check-template-context-variable-in-sync",
     "check-tests-in-the-right-folders",
     "check-tests-unittest-testcase",
     "check-urlparse-usage-in-code",
diff --git a/docs/apache-airflow/authoring-and-scheduling/datasets.rst 
b/docs/apache-airflow/authoring-and-scheduling/datasets.rst
index 1102420dd4..5324a11bbc 100644
--- a/docs/apache-airflow/authoring-and-scheduling/datasets.rst
+++ b/docs/apache-airflow/authoring-and-scheduling/datasets.rst
@@ -99,8 +99,8 @@ The identifier does not have to be absolute; it can be a 
scheme-less, relative U
 
 Non-absolute identifiers are considered plain strings that do not carry any 
semantic meanings to Airflow.
 
-Extra information
------------------
+Extra information on Dataset
+----------------------------
 
 If needed, an extra dictionary can be included in a Dataset:
 
@@ -111,7 +111,7 @@ If needed, an extra dictionary can be included in a Dataset:
         extra={"team": "trainees"},
     )
 
-This extra information does not affect a dataset's identity. This means a DAG 
will be triggered by a dataset with an identical URI, even if the extra dict is 
different:
+This can be used to supply custom description to the dataset, such as who has 
ownership to the target file, or what the file is for. The extra information 
does not affect a dataset's identity. This means a DAG will be triggered by a 
dataset with an identical URI, even if the extra dict is different:
 
 .. code-block:: python
 
@@ -224,6 +224,29 @@ If one dataset is updated multiple times before all 
consumed datasets have been
 
     }
 
+Attaching extra information to an emitting Dataset Event
+--------------------------------------------------------
+
+.. versionadded:: 2.10.0
+
+A task with a dataset outlet can optionally attach extra information before it 
emits a dataset event. This is different
+from `Extra information on Dataset`_. Extra information on a dataset 
statically describes the entity pointed to by the dataset URI; extra 
information on the *dataset event* instead should be used to annotate the 
triggering data change, such as how many rows in the database are changed by 
the update, or the date range covered by it.
+
+The easiest way to attach extra information to the dataset event is by 
accessing ``dataset_events`` in a task's execution context:
+
+.. code-block:: python
+
+    example_s3_dataset = Dataset("s3://dataset/example.csv")
+
+
+    @task(outlets=[example_s3_dataset])
+    def write_to_s3(*, dataset_events):
+        df = ...  # Get a Pandas DataFrame to write.
+        # Write df to dataset...
+        dataset_events[example_s3_dataset].extras = {"row_count": len(df)}
+
+This can also be done in classic operators by either subclassing the operator 
and overriding ``execute``, or by supplying a pre- or post-execution function.
+
 Fetching information from a Triggering Dataset Event
 ----------------------------------------------------
 
@@ -234,7 +257,7 @@ Example:
 
 .. code-block:: python
 
-    example_snowflake_dataset = Dataset("snowflake://my_db.my_schema.my_table")
+    example_snowflake_dataset = Dataset("snowflake://my_db/my_schema/my_table")
 
     with DAG(dag_id="load_snowflake_data", schedule="@hourly", ...):
         SQLExecuteQueryOperator(
diff --git a/docs/apache-airflow/templates-ref.rst 
b/docs/apache-airflow/templates-ref.rst
index dd05fcc831..4d3014268b 100644
--- a/docs/apache-airflow/templates-ref.rst
+++ b/docs/apache-airflow/templates-ref.rst
@@ -74,6 +74,8 @@ Variable                                    Type              
    Description
 ``{{ var.value }}``                                               Airflow 
variables. See `Airflow Variables in Templates`_ below.
 ``{{ var.json }}``                                                Airflow 
variables. See `Airflow Variables in Templates`_ below.
 ``{{ conn }}``                                                    Airflow 
connections. See `Airflow Connections in Templates`_ below.
+``{{ dataset_events }}``                    dict[str, ...]        | Accessors 
to attach information to dataset events that will be emitted by the current 
task.
+                                                                  | See 
:doc:`Datasets <authoring-and-scheduling/datasets>`. Added in version 2.10.
 ``{{ task_instance_key_str }}``             str                   | A unique, 
human-readable key to the task instance. The format is
                                                                   | 
``{dag_id}__{task_id}__{ds_nodash}``.
 ``{{ conf }}``                              AirflowConfigParser   | The full 
configuration object representing the content of your
diff --git a/scripts/ci/pre_commit/pre_commit_template_context_key_sync.py 
b/scripts/ci/pre_commit/pre_commit_template_context_key_sync.py
old mode 100644
new mode 100755
diff --git a/tests/models/test_taskinstance.py 
b/tests/models/test_taskinstance.py
index 120856dbbf..e618731142 100644
--- a/tests/models/test_taskinstance.py
+++ b/tests/models/test_taskinstance.py
@@ -35,6 +35,7 @@ from uuid import uuid4
 import pendulum
 import pytest
 import time_machine
+from sqlalchemy import select
 
 from airflow import settings
 from airflow.decorators import task, task_group
@@ -2281,7 +2282,7 @@ class TestTaskInstance:
                 task_instance.run()
                 assert task_instance.current_state() == 
TaskInstanceState.SUCCESS
 
-    def test_outlet_datasets_skipped(self, create_task_instance):
+    def test_outlet_datasets_skipped(self):
         """
         Verify that when we have an outlet dataset on a task, and the task
         is skipped, a DatasetDagRunQueue is not logged, and a DatasetEvent is
@@ -2311,7 +2312,69 @@ class TestTaskInstance:
         # check that no dataset events were generated
         assert session.query(DatasetEvent).count() == 0
 
-    def test_changing_of_dataset_when_ddrq_is_already_populated(self, 
dag_maker, session):
+    def test_outlet_dataset_extra(self, dag_maker, session):
+        from airflow.datasets import Dataset
+
+        with dag_maker(schedule=None, session=session) as dag:
+
+            @task(outlets=Dataset("test_outlet_dataset_extra_1"))
+            def write1(*, dataset_events):
+                dataset_events["test_outlet_dataset_extra_1"].extra = {"foo": 
"bar"}
+
+            write1()
+
+            def _write2_post_execute(context, _):
+                context["dataset_events"]["test_outlet_dataset_extra_2"].extra 
= {"x": 1}
+
+            BashOperator(
+                task_id="write2",
+                bash_command=":",
+                outlets=Dataset("test_outlet_dataset_extra_2"),
+                post_execute=_write2_post_execute,
+            )
+
+        dr: DagRun = dag_maker.create_dagrun()
+        for ti in dr.get_task_instances(session=session):
+            ti.refresh_from_task(dag.get_task(ti.task_id))
+            ti.run(session=session)
+
+        events = dict(iter(session.execute(select(DatasetEvent.source_task_id, 
DatasetEvent))))
+        assert set(events) == {"write1", "write2"}
+
+        assert events["write1"].source_dag_id == dr.dag_id
+        assert events["write1"].source_run_id == dr.run_id
+        assert events["write1"].source_task_id == "write1"
+        assert events["write1"].dataset.uri == "test_outlet_dataset_extra_1"
+        assert events["write1"].extra == {"foo": "bar"}
+
+        assert events["write2"].source_dag_id == dr.dag_id
+        assert events["write2"].source_run_id == dr.run_id
+        assert events["write2"].source_task_id == "write2"
+        assert events["write2"].dataset.uri == "test_outlet_dataset_extra_2"
+        assert events["write2"].extra == {"x": 1}
+
+    def test_outlet_dataset_extra_ignore_different(self, dag_maker, session):
+        from airflow.datasets import Dataset
+
+        with dag_maker(schedule=None, session=session):
+
+            @task(outlets=Dataset("test_outlet_dataset_extra"))
+            def write(*, dataset_events):
+                dataset_events["test_outlet_dataset_extra"].extra = {"one": 1}
+                dataset_events["different_uri"].extra = {"foo": "bar"}  # Will 
be silently dropped.
+
+            write()
+
+        dr: DagRun = dag_maker.create_dagrun()
+        dr.get_task_instance("write").run(session=session)
+
+        event = session.scalars(select(DatasetEvent)).one()
+        assert event.source_dag_id == dr.dag_id
+        assert event.source_run_id == dr.run_id
+        assert event.source_task_id == "write"
+        assert event.extra == {"one": 1}
+
+    def test_changing_of_dataset_when_ddrq_is_already_populated(self, 
dag_maker):
         """
         Test that when a task that produces dataset has ran, that changing the 
consumer
         dag dataset will not cause primary key blank-out
diff --git a/tests/operators/test_python.py b/tests/operators/test_python.py
index 578302a836..b8876f97ec 100644
--- a/tests/operators/test_python.py
+++ b/tests/operators/test_python.py
@@ -834,6 +834,7 @@ class BaseTestPythonVirtualenvOperator(BasePythonTest):
             "ti",
             "var",  # Accessor for Variable; var->json and var->value.
             "conn",  # Accessor for Connection.
+            "dataset_events",  # Accessor for DatasetEvent.
         ]
 
         ti = create_task_instance(dag_id=self.dag_id, task_id=self.task_id, 
schedule=None)

Reply via email to