diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index c31f3d6d7b153..265f52fd1c2ba 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -924,6 +924,13 @@ repos:
files: ^chart
require_serial: true
additional_dependencies: ['rich>=12.4.4','requests>=2.31.0']
+ - id: validate-chart-annotations
+ name: Validate chart annotations
+ entry: ./scripts/ci/pre_commit/validate_chart_annotations.py
+ language: python
+ pass_filenames: false
+ files: ^chart/Chart\.yaml$
+ additional_dependencies: ['pyyaml>=6.0.2', 'rich>=12.4.4']
- id: kubeconform
name: Kubeconform check on our helm chart
entry: ./scripts/ci/pre_commit/check_kubeconform.py
diff --git a/chart/Chart.yaml b/chart/Chart.yaml
index f53fc21407eee..5f247d5650e9d 100644
--- a/chart/Chart.yaml
+++ b/chart/Chart.yaml
@@ -136,7 +136,7 @@ annotations:
- description: 'Fix execution_api_server_url when base_url has a subpath'
kind: changed
links:
- - name: '#51454
+ - name: '#51454'
url: https://github.com/apache/airflow/pull/51454
- description: 'Docs: Bump minimum helm version in docs'
kind: changed
diff --git a/contributing-docs/08_static_code_checks.rst b/contributing-docs/08_static_code_checks.rst
index db0c4e3129d7b..70fd44db68d8f 100644
--- a/contributing-docs/08_static_code_checks.rst
+++ b/contributing-docs/08_static_code_checks.rst
@@ -412,6 +412,8 @@ require Breeze Docker image to be built locally.
+-----------------------------------------------------------+--------------------------------------------------------+---------+
| update-version | Update versions in docs | |
+-----------------------------------------------------------+--------------------------------------------------------+---------+
+| validate-chart-annotations | Validate chart annotations | |
++-----------------------------------------------------------+--------------------------------------------------------+---------+
| validate-operators-init | No templated field logic checks in operator __init__ | |
+-----------------------------------------------------------+--------------------------------------------------------+---------+
| yamllint | Check YAML files with yamllint | |
diff --git a/dev/breeze/doc/images/output_static-checks.svg b/dev/breeze/doc/images/output_static-checks.svg
index 9918dedfb8bfb..0e6fb97574d95 100644
--- a/dev/breeze/doc/images/output_static-checks.svg
+++ b/dev/breeze/doc/images/output_static-checks.svg
@@ -384,8 +384,8 @@
│update-providers-build-files | update-providers-dependencies | │
│update-pyproject-toml | update-reproducible-source-date-epoch | │
│update-spelling-wordlist-to-be-sorted | update-supported-versions | │
-│update-vendored-in-k8s-json-schema | update-version | validate-operators-init | │
-│yamllint | zizmor) │
+│update-vendored-in-k8s-json-schema | update-version | validate-chart-annotations │
+│| validate-operators-init | yamllint | zizmor) │
│--show-diff-on-failure-sShow diff for files modified by the checks.│
│--initialize-environmentInitialize environment before running checks.│
│--max-initialization-attemptsMaximum number of attempts to initialize environment before giving up.│
diff --git a/dev/breeze/doc/images/output_static-checks.txt b/dev/breeze/doc/images/output_static-checks.txt
index e1d3187c5864b..e8dbbc57b6271 100644
--- a/dev/breeze/doc/images/output_static-checks.txt
+++ b/dev/breeze/doc/images/output_static-checks.txt
@@ -1 +1 @@
-d0dc18a59b8997b9c06a3bd15879c8c7
+4d21a8da51102b0c61707aac83f31b3a
diff --git a/dev/breeze/src/airflow_breeze/pre_commit_ids.py b/dev/breeze/src/airflow_breeze/pre_commit_ids.py
index c5ad5b2040a4e..9f1a79c15a4e2 100644
--- a/dev/breeze/src/airflow_breeze/pre_commit_ids.py
+++ b/dev/breeze/src/airflow_breeze/pre_commit_ids.py
@@ -158,6 +158,7 @@
"update-supported-versions",
"update-vendored-in-k8s-json-schema",
"update-version",
+ "validate-chart-annotations",
"validate-operators-init",
"yamllint",
"zizmor",
diff --git a/scripts/ci/pre_commit/validate_chart_annotations.py b/scripts/ci/pre_commit/validate_chart_annotations.py
new file mode 100755
index 0000000000000..77f001e13fbd7
--- /dev/null
+++ b/scripts/ci/pre_commit/validate_chart_annotations.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+# 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.
+from __future__ import annotations
+
+import sys
+from pathlib import Path
+
+import yaml
+
+sys.path.insert(0, str(Path(__file__).parent.resolve()))
+from common_precommit_utils import AIRFLOW_ROOT_PATH, console
+
+CHART_YAML_FILE = AIRFLOW_ROOT_PATH / "chart" / "Chart.yaml"
+
+# List of artifacthub.io annotations that should contain valid YAML strings
+ARTIFACTHUB_ANNOTATIONS_TO_CHECK = [
+ "artifacthub.io/links",
+ "artifacthub.io/screenshots",
+ "artifacthub.io/changes",
+]
+
+
+def validate_chart_annotations():
+ """Validate that chart annotations are valid - e.g. strings that hold yaml are valid yaml"""
+ errors = []
+
+ try:
+ chart_content = yaml.safe_load(CHART_YAML_FILE.read_text())
+ except yaml.YAMLError as e:
+ console.print(f"[red]Error parsing Chart.yaml: {e}")
+ return False
+
+ annotations = chart_content.get("annotations", {})
+
+ for annotation_key in ARTIFACTHUB_ANNOTATIONS_TO_CHECK:
+ if annotation_key in annotations:
+ annotation_value = annotations[annotation_key]
+ try:
+ # Try to parse the string value as YAML
+ yaml.safe_load(annotation_value)
+ console.print(f"[green]✓[/] {annotation_key} contains valid YAML")
+ except yaml.YAMLError as e:
+ error_msg = f"Invalid YAML in annotation '{annotation_key}': {e}"
+ errors.append(error_msg)
+ console.print(f"[red]✗ {error_msg}[/]")
+
+ if errors:
+ console.print("\n[red]Chart.yaml validation failed![/]")
+ console.print("[red]The following artifacthub.io annotations contain invalid YAML:[/]")
+ for error in errors:
+ console.print(f"[red] - {error}[/]")
+ return False
+
+ console.print("\n[green]All artifacthub.io annotations contain valid YAML![/]")
+ return True
+
+
+if __name__ == "__main__":
+ if not validate_chart_annotations():
+ sys.exit(1)