blob: d516aaeee4ffabe4af194106c66061199bacbe61 [file]
# 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 json
import re
from typing import Any
from unittest.mock import Mock, patch
import pytest
from rich.console import Console
from airflow_breeze.global_constants import (
ALLOWED_KUBERNETES_VERSIONS,
ALLOWED_PYTHON_MAJOR_MINOR_VERSIONS,
CI_AMD_PLATFORM,
CI_ARM_PLATFORM,
CURRENT_PYTHON_MAJOR_MINOR_VERSIONS,
DEFAULT_KUBERNETES_VERSION,
DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
JAVA_SDK_VERSION,
NUMBER_OF_CORE_SLICES,
NUMBER_OF_LOW_DEP_SLICES,
PROVIDERS_COMPATIBILITY_TESTS_MATRIX,
GithubEvents,
)
from airflow_breeze.utils.functools_cache import clearable_cache
from airflow_breeze.utils.packages import get_available_distributions
from airflow_breeze.utils.path_utils import AIRFLOW_ROOT_PATH
from airflow_breeze.utils.selective_checks import (
ALL_CI_SELECTIVE_TEST_TYPES,
SelectiveChecks,
_get_test_list_as_json,
_split_list,
)
ANSI_COLORS_MATCHER = re.compile(r"(?:\x1B[@-_]|[\x80-\x9F])[0-?]*[ -/]*[@-~]")
ALL_DOCS_SELECTED_FOR_BUILD = ""
ALL_PROVIDERS_AFFECTED = ""
ALL_KUBERNETES_VERSIONS_AS_STRING = " ".join(ALLOWED_KUBERNETES_VERSIONS)
ALL_KUBERNETES_VERSIONS_AS_LIST = "[" + ", ".join([f"'{v}'" for v in ALLOWED_KUBERNETES_VERSIONS]) + "]"
ALL_PYTHON_VERSIONS_AS_STRING = " ".join(ALLOWED_PYTHON_MAJOR_MINOR_VERSIONS)
ALL_PYTHON_VERSIONS_AS_LIST = "[" + ", ".join([f"'{v}'" for v in ALLOWED_PYTHON_MAJOR_MINOR_VERSIONS]) + "]"
CURRENT_PYTHON_VERSIONS_AS_LIST = (
"[" + ", ".join([f"'{v}'" for v in CURRENT_PYTHON_MAJOR_MINOR_VERSIONS]) + "]"
)
DEFAULT_HELM_K8S_VERSION = ALLOWED_KUBERNETES_VERSIONS[0].lstrip("v")
LAST_HELM_K8S_VERSION = ALLOWED_KUBERNETES_VERSIONS[-1].lstrip("v")
DEFAULT_HELM_K8S_VERSIONS_JSON = json.dumps([DEFAULT_HELM_K8S_VERSION])
ALL_HELM_K8S_VERSIONS_JSON = json.dumps(
[DEFAULT_HELM_K8S_VERSION]
if DEFAULT_HELM_K8S_VERSION == LAST_HELM_K8S_VERSION
else [DEFAULT_HELM_K8S_VERSION, LAST_HELM_K8S_VERSION]
)
PYTHON_K8S_COMBO_LENGTH = max(len(ALLOWED_PYTHON_MAJOR_MINOR_VERSIONS), len(ALLOWED_KUBERNETES_VERSIONS))
PYTHON_VERSIONS_MAX = (ALLOWED_PYTHON_MAJOR_MINOR_VERSIONS * 2)[:PYTHON_K8S_COMBO_LENGTH]
KUBERNETES_VERSIONS_MAX = (ALLOWED_KUBERNETES_VERSIONS * 2)[:PYTHON_K8S_COMBO_LENGTH]
ZIP_PYTHON_AND_KUBERNETES_VERSIONS_AS_STRING = " ".join(
[f"{t[0]}-{t[1]}" for t in zip(PYTHON_VERSIONS_MAX, KUBERNETES_VERSIONS_MAX)]
)
ZIP_PYTHON_AND_KUBERNETES_VERSIONS_AS_LIST = (
"[" + ", ".join([f"'{t[0]}-{t[1]}'" for t in zip(PYTHON_VERSIONS_MAX, KUBERNETES_VERSIONS_MAX)]) + "]"
)
ALL_CI_SELECTIVE_TEST_TYPES_AS_JSON = json.dumps(
_get_test_list_as_json(_split_list(sorted(ALL_CI_SELECTIVE_TEST_TYPES.split()), NUMBER_OF_CORE_SLICES))
)
ALL_PROVIDERS_SELECTIVE_TEST_TYPES_AS_JSON = json.dumps(
[
{
"description": "-amazon,celer...standard",
"test_types": "Providers[-amazon,celery,google,standard] "
"Providers[amazon] Providers[celery] Providers[google] Providers[standard]",
}
]
)
LIST_OF_ALL_PROVIDER_TESTS = [
f"Providers[{provider}]" for provider in get_available_distributions(include_not_ready=True)
]
LIST_OF_ALL_PROVIDER_TESTS_AS_JSON = json.dumps(
_get_test_list_as_json(_split_list(sorted(LIST_OF_ALL_PROVIDER_TESTS), 5))
)
ALL_SKIPPED_COMMITS_ON_NO_CI_IMAGE = (
"check-provider-yaml-valid,check-ts-sdk-supervisor-schema,flynt,identity,ktlint,lint-helm-chart,"
"mypy-airflow-core,mypy-airflow-ctl,mypy-airflow-ctl-tests,mypy-airflow-e2e-tests,"
"mypy-dev,mypy-devel-common,mypy-docker-tests,mypy-helm-tests,mypy-kubernetes-tests,"
"mypy-scripts,"
"mypy-shared-configuration,mypy-shared-dagnode,mypy-shared-listeners,mypy-shared-logging,"
"mypy-shared-module_loading,mypy-shared-observability,mypy-shared-plugins_manager,"
"mypy-shared-providers_discovery,mypy-shared-secrets_backend,mypy-shared-secrets_masker,"
"mypy-shared-serialization,mypy-shared-state,mypy-shared-template_rendering,mypy-shared-timezones,mypy-task-sdk,mypy-task-sdk-integration-tests,"
"ts-compile-lint-simple-auth-manager-ui,ts-compile-lint-ui,update-uv-lock"
)
ALL_SKIPPED_COMMITS_BY_DEFAULT_ON_ALL_TESTS_NEEDED = "identity,update-uv-lock"
ALL_SKIPPED_COMMITS_IF_ONLY_UI_OPENAPI_CHANGED = (
"check-provider-yaml-valid,check-ts-sdk-supervisor-schema,flynt,identity,ktlint,"
"lint-helm-chart,mypy-airflow-core,mypy-airflow-ctl,mypy-airflow-ctl-tests,"
"mypy-airflow-e2e-tests,mypy-dev,mypy-devel-common,mypy-docker-tests,mypy-helm-tests,"
"mypy-kubernetes-tests,mypy-scripts,mypy-shared-configuration,mypy-shared-dagnode,"
"mypy-shared-listeners,mypy-shared-logging,mypy-shared-module_loading,"
"mypy-shared-observability,mypy-shared-plugins_manager,mypy-shared-providers_discovery,"
"mypy-shared-secrets_backend,mypy-shared-secrets_masker,mypy-shared-serialization,"
"mypy-shared-state,mypy-shared-template_rendering,mypy-shared-timezones,mypy-task-sdk,"
"mypy-task-sdk-integration-tests,update-uv-lock"
)
ALL_SKIPPED_COMMITS_IF_NO_UI = (
"check-ts-sdk-supervisor-schema,identity,ktlint,mypy-airflow-core,mypy-airflow-ctl,mypy-airflow-ctl-tests,mypy-airflow-e2e-tests,"
"mypy-dev,mypy-devel-common,mypy-docker-tests,mypy-helm-tests,mypy-kubernetes-tests,"
"mypy-scripts,"
"mypy-shared-configuration,mypy-shared-dagnode,mypy-shared-listeners,mypy-shared-logging,"
"mypy-shared-module_loading,mypy-shared-observability,mypy-shared-plugins_manager,"
"mypy-shared-providers_discovery,mypy-shared-secrets_backend,mypy-shared-secrets_masker,"
"mypy-shared-serialization,mypy-shared-state,mypy-shared-template_rendering,mypy-shared-timezones,mypy-task-sdk,mypy-task-sdk-integration-tests,"
"ts-compile-lint-simple-auth-manager-ui,ts-compile-lint-ui,update-uv-lock"
)
ALL_SKIPPED_COMMITS_IF_NO_HELM_TESTS = (
"check-ts-sdk-supervisor-schema,identity,ktlint,lint-helm-chart,"
"mypy-airflow-core,mypy-airflow-ctl,mypy-airflow-ctl-tests,mypy-airflow-e2e-tests,"
"mypy-dev,mypy-devel-common,mypy-docker-tests,mypy-helm-tests,mypy-kubernetes-tests,"
"mypy-scripts,"
"mypy-shared-configuration,mypy-shared-dagnode,mypy-shared-listeners,mypy-shared-logging,"
"mypy-shared-module_loading,mypy-shared-observability,mypy-shared-plugins_manager,"
"mypy-shared-providers_discovery,mypy-shared-secrets_backend,mypy-shared-secrets_masker,"
"mypy-shared-serialization,mypy-shared-state,mypy-shared-template_rendering,mypy-shared-timezones,mypy-task-sdk,mypy-task-sdk-integration-tests,update-uv-lock"
)
ALL_SKIPPED_COMMITS_IF_NO_UI_AND_HELM_TESTS = (
"check-ts-sdk-supervisor-schema,identity,ktlint,lint-helm-chart,"
"mypy-airflow-core,mypy-airflow-ctl,mypy-airflow-ctl-tests,mypy-airflow-e2e-tests,"
"mypy-dev,mypy-devel-common,mypy-docker-tests,mypy-helm-tests,mypy-kubernetes-tests,"
"mypy-scripts,"
"mypy-shared-configuration,mypy-shared-dagnode,mypy-shared-listeners,mypy-shared-logging,"
"mypy-shared-module_loading,mypy-shared-observability,mypy-shared-plugins_manager,"
"mypy-shared-providers_discovery,mypy-shared-secrets_backend,mypy-shared-secrets_masker,"
"mypy-shared-serialization,mypy-shared-state,mypy-shared-template_rendering,mypy-shared-timezones,mypy-task-sdk,mypy-task-sdk-integration-tests,"
"ts-compile-lint-simple-auth-manager-ui,ts-compile-lint-ui,update-uv-lock"
)
# API source/test change with NO OpenAPI spec change: the full matrix is no longer
# forced. airflow-core Python changed (so mypy-airflow-core + flynt run); no
# provider.yaml, helm, or UI files changed, so those checks stay skipped.
ALL_SKIPPED_COMMITS_IF_ONLY_API_SOURCE_CHANGED = (
"check-provider-yaml-valid,check-ts-sdk-supervisor-schema,identity,ktlint,lint-helm-chart,"
"mypy-airflow-ctl,mypy-airflow-ctl-tests,mypy-airflow-e2e-tests,"
"mypy-dev,mypy-devel-common,mypy-docker-tests,mypy-helm-tests,mypy-kubernetes-tests,"
"mypy-scripts,"
"mypy-shared-configuration,mypy-shared-dagnode,mypy-shared-listeners,mypy-shared-logging,"
"mypy-shared-module_loading,mypy-shared-observability,mypy-shared-plugins_manager,"
"mypy-shared-providers_discovery,mypy-shared-secrets_backend,mypy-shared-secrets_masker,"
"mypy-shared-serialization,mypy-shared-state,mypy-shared-template_rendering,mypy-shared-timezones,"
"mypy-task-sdk,mypy-task-sdk-integration-tests,"
"ts-compile-lint-simple-auth-manager-ui,ts-compile-lint-ui,update-uv-lock"
)
ALL_SKIPPED_COMMITS_IF_NO_PROVIDERS_AND_UI = (
"check-provider-yaml-valid,check-ts-sdk-supervisor-schema,identity,ktlint,"
"mypy-airflow-core,mypy-airflow-ctl,mypy-airflow-ctl-tests,mypy-airflow-e2e-tests,"
"mypy-dev,mypy-devel-common,mypy-docker-tests,mypy-helm-tests,mypy-kubernetes-tests,"
"mypy-scripts,"
"mypy-shared-configuration,mypy-shared-dagnode,mypy-shared-listeners,mypy-shared-logging,"
"mypy-shared-module_loading,mypy-shared-observability,mypy-shared-plugins_manager,"
"mypy-shared-providers_discovery,mypy-shared-secrets_backend,mypy-shared-secrets_masker,"
"mypy-shared-serialization,mypy-shared-state,mypy-shared-template_rendering,mypy-shared-timezones,mypy-task-sdk,mypy-task-sdk-integration-tests,"
"ts-compile-lint-simple-auth-manager-ui,ts-compile-lint-ui,update-uv-lock"
)
ALL_SKIPPED_COMMITS_IF_NO_PROVIDERS = (
"check-provider-yaml-valid,check-ts-sdk-supervisor-schema,identity,ktlint,lint-helm-chart,"
"mypy-airflow-core,mypy-airflow-ctl,mypy-airflow-ctl-tests,mypy-airflow-e2e-tests,"
"mypy-dev,mypy-devel-common,mypy-docker-tests,mypy-helm-tests,mypy-kubernetes-tests,"
"mypy-scripts,"
"mypy-shared-configuration,mypy-shared-dagnode,mypy-shared-listeners,mypy-shared-logging,"
"mypy-shared-module_loading,mypy-shared-observability,mypy-shared-plugins_manager,"
"mypy-shared-providers_discovery,mypy-shared-secrets_backend,mypy-shared-secrets_masker,"
"mypy-shared-serialization,mypy-shared-state,mypy-shared-template_rendering,mypy-shared-timezones,mypy-task-sdk,mypy-task-sdk-integration-tests,"
"ts-compile-lint-simple-auth-manager-ui,ts-compile-lint-ui,update-uv-lock"
)
ALL_SKIPPED_COMMITS_IF_NO_PROVIDERS_UI_AND_HELM_TESTS = (
"check-provider-yaml-valid,check-ts-sdk-supervisor-schema,identity,ktlint,lint-helm-chart,"
"mypy-airflow-core,mypy-airflow-ctl,mypy-airflow-ctl-tests,mypy-airflow-e2e-tests,"
"mypy-dev,mypy-devel-common,mypy-docker-tests,mypy-helm-tests,mypy-kubernetes-tests,"
"mypy-scripts,"
"mypy-shared-configuration,mypy-shared-dagnode,mypy-shared-listeners,mypy-shared-logging,"
"mypy-shared-module_loading,mypy-shared-observability,mypy-shared-plugins_manager,"
"mypy-shared-providers_discovery,mypy-shared-secrets_backend,mypy-shared-secrets_masker,"
"mypy-shared-serialization,mypy-shared-state,mypy-shared-template_rendering,mypy-shared-timezones,mypy-task-sdk,mypy-task-sdk-integration-tests,"
"ts-compile-lint-simple-auth-manager-ui,ts-compile-lint-ui,update-uv-lock"
)
ALL_SKIPPED_COMMITS_IF_NO_CODE_PROVIDERS_AND_HELM_TESTS = (
"check-provider-yaml-valid,check-ts-sdk-supervisor-schema,flynt,identity,ktlint,lint-helm-chart,"
"mypy-airflow-core,mypy-airflow-ctl,mypy-airflow-ctl-tests,mypy-airflow-e2e-tests,"
"mypy-dev,mypy-devel-common,mypy-docker-tests,mypy-helm-tests,mypy-kubernetes-tests,"
"mypy-scripts,"
"mypy-shared-configuration,mypy-shared-dagnode,mypy-shared-listeners,mypy-shared-logging,"
"mypy-shared-module_loading,mypy-shared-observability,mypy-shared-plugins_manager,"
"mypy-shared-providers_discovery,mypy-shared-secrets_backend,mypy-shared-secrets_masker,"
"mypy-shared-serialization,mypy-shared-state,mypy-shared-template_rendering,mypy-shared-timezones,mypy-task-sdk,mypy-task-sdk-integration-tests,update-uv-lock"
)
ALL_SKIPPED_COMMITS_IF_NOT_IMPORTANT_FILES_CHANGED = (
"check-provider-yaml-valid,check-ts-sdk-supervisor-schema,flynt,identity,ktlint,lint-helm-chart,"
"mypy-airflow-core,mypy-airflow-ctl,mypy-airflow-ctl-tests,mypy-airflow-e2e-tests,"
"mypy-dev,mypy-devel-common,mypy-docker-tests,mypy-helm-tests,mypy-kubernetes-tests,"
"mypy-scripts,"
"mypy-shared-configuration,mypy-shared-dagnode,mypy-shared-listeners,mypy-shared-logging,"
"mypy-shared-module_loading,mypy-shared-observability,mypy-shared-plugins_manager,"
"mypy-shared-providers_discovery,mypy-shared-secrets_backend,mypy-shared-secrets_masker,"
"mypy-shared-serialization,mypy-shared-state,mypy-shared-template_rendering,mypy-shared-timezones,mypy-task-sdk,mypy-task-sdk-integration-tests,"
"ts-compile-lint-simple-auth-manager-ui,ts-compile-lint-ui,update-uv-lock"
)
All_SKIPPED_COMMITS_IF_NON_MAIN_BRANCH = (
"check-airflow-provider-compatibility,check-airflow-providers-bug-report-template,"
"check-extra-packages-references,check-provider-yaml-valid,"
"compile-fab-assets,generate-openapi-spec-fab,identity,"
"lint-helm-chart,update-uv-lock,validate-operators-init"
)
# commit that is neutral - allows to keep pyproject.toml-changing PRS neutral for unit tests
NEUTRAL_COMMIT = "938f0c1f3cc4cbe867123ee8aa9f290f9f18100a"
def escape_ansi_colors(line):
return ANSI_COLORS_MATCHER.sub("", line)
@clearable_cache
def get_rich_console() -> Console:
return Console(color_system="truecolor", force_terminal=True)
def print_in_color(s: Any = ""):
get_rich_console().print(s)
def get_outputs_from_stderr(stderr: str) -> dict[str, str]:
escaped_stderr = escape_ansi_colors(stderr)
return dict(line.split("=", 1) for line in escaped_stderr.splitlines() if "=" in line)
def assert_outputs_are_printed(expected_outputs: dict[str, str], stderr: str):
received_output_as_dict = get_outputs_from_stderr(stderr)
for expected_key, expected_value in expected_outputs.items():
if expected_value is None:
if expected_key in received_output_as_dict:
print_in_color(f"\n[red]ERROR: The '{expected_key}' should not be present in:[/]")
print_in_color(received_output_as_dict)
print_in_color("\n")
assert expected_key is not None
else:
received_value = received_output_as_dict.get(expected_key)
if received_value != expected_value:
if received_value is not None:
print_in_color(f"\n[red]ERROR: The key '{expected_key}' has unexpected value:")
print(
received_value,
)
print_in_color("Expected value:\n")
print(expected_value)
print_in_color("\nOutput received:")
print_in_color(received_output_as_dict)
print_in_color()
assert received_value == expected_value, f"Correct value for {expected_key!r}"
else:
print_in_color(
f"\n[red]ERROR: The key '{expected_key}' missing but it is expected. Expected value:"
)
print_in_color(expected_value)
print_in_color("\nOutput received:")
print(received_output_as_dict)
print_in_color()
print(received_output_as_dict)
print_in_color()
assert received_value is not None
@pytest.mark.parametrize(
("files", "expected_outputs"),
[
(
pytest.param(
("INTHEWILD.md",),
{
"selected-providers-list-as-string": None,
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "false",
"run-helm-tests": "false",
"run-unit-tests": "false",
"run-amazon-tests": "false",
"docs-build": "false",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_ON_NO_CI_IMAGE,
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": None,
"providers-test-types-list-as-strings-in-json": None,
"individual-providers-test-types-list-as-strings-in-json": None,
"run-mypy-providers": "false",
},
id="No tests on simple change",
)
),
(
pytest.param(
("pyproject.toml",),
{
"ci-image-build": "true",
},
id="CI image build and when pyproject.toml change",
)
),
(
pytest.param(
("airflow-core/src/airflow/api/file.py",),
{
"full-tests-needed": "false",
"selected-providers-list-as-string": "common.compat fab",
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "false",
"run-helm-tests": "false",
"run-unit-tests": "true",
"run-amazon-tests": "false",
"run-api-tests": "true",
"docs-build": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_IF_ONLY_API_SOURCE_CHANGED,
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": json.dumps(
[{"description": "API...Always", "test_types": "API Always"}]
),
"providers-test-types-list-as-strings-in-json": json.dumps(
[{"description": "common.compat,fab", "test_types": "Providers[common.compat,fab]"}]
),
"individual-providers-test-types-list-as-strings-in-json": json.dumps(
[
{
"description": "common.compat...fab",
"test_types": "Providers[common.compat] Providers[fab]",
}
]
),
"run-mypy-providers": "false",
},
id="API source change (no spec) runs API + fab only, not the full matrix",
)
),
(
pytest.param(
("airflow-core/src/airflow/api_fastapi/file.py",),
{
"full-tests-needed": "false",
"selected-providers-list-as-string": "common.compat fab",
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "false",
"run-helm-tests": "false",
"run-unit-tests": "true",
"run-amazon-tests": "false",
"run-api-tests": "true",
"docs-build": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_IF_ONLY_API_SOURCE_CHANGED,
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": json.dumps(
[{"description": "API...Always", "test_types": "API Always"}]
),
"providers-test-types-list-as-strings-in-json": json.dumps(
[{"description": "common.compat,fab", "test_types": "Providers[common.compat,fab]"}]
),
"individual-providers-test-types-list-as-strings-in-json": json.dumps(
[
{
"description": "common.compat...fab",
"test_types": "Providers[common.compat] Providers[fab]",
}
]
),
"run-mypy-providers": "false",
},
id="fastapi source change (no spec) runs API + fab only, not the full matrix",
)
),
(
pytest.param(
("airflow-core/tests/unit/api/file.py",),
{
"full-tests-needed": "false",
"selected-providers-list-as-string": "common.compat fab",
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "false",
"run-helm-tests": "false",
"run-unit-tests": "true",
"run-amazon-tests": "false",
"run-api-tests": "true",
"docs-build": "false",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_IF_ONLY_API_SOURCE_CHANGED,
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": json.dumps(
[{"description": "API...Always", "test_types": "API Always"}]
),
"providers-test-types-list-as-strings-in-json": json.dumps(
[{"description": "common.compat,fab", "test_types": "Providers[common.compat,fab]"}]
),
"individual-providers-test-types-list-as-strings-in-json": json.dumps(
[
{
"description": "common.compat...fab",
"test_types": "Providers[common.compat] Providers[fab]",
}
]
),
"run-mypy-providers": "false",
},
id="API test change (no spec) runs API + fab only, not the full matrix",
)
),
(
pytest.param(
("airflow-core/src/airflow/serialization/python.py",),
{
"selected-providers-list-as-string": None,
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "false",
"run-helm-tests": "false",
"run-unit-tests": "true",
"run-amazon-tests": "false",
"docs-build": "true",
"skip-prek-hooks": (
"check-provider-yaml-valid,check-ts-sdk-supervisor-schema,identity,ktlint,lint-helm-chart,"
"mypy-airflow-ctl,mypy-airflow-ctl-tests,mypy-airflow-e2e-tests,"
"mypy-dev,mypy-devel-common,mypy-docker-tests,mypy-helm-tests,mypy-kubernetes-tests,"
"mypy-scripts,"
"mypy-shared-configuration,mypy-shared-dagnode,mypy-shared-listeners,mypy-shared-logging,"
"mypy-shared-module_loading,mypy-shared-observability,mypy-shared-plugins_manager,"
"mypy-shared-providers_discovery,mypy-shared-secrets_backend,mypy-shared-secrets_masker,"
"mypy-shared-serialization,mypy-shared-state,mypy-shared-template_rendering,mypy-shared-timezones,mypy-task-sdk,mypy-task-sdk-integration-tests,"
"ts-compile-lint-simple-auth-manager-ui,ts-compile-lint-ui,update-uv-lock"
),
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": json.dumps(
_get_test_list_as_json(
_split_list(sorted(["Always", "Core", "Serialization"]), NUMBER_OF_CORE_SLICES)
)
),
"providers-test-types-list-as-strings-in-json": None,
"individual-providers-test-types-list-as-strings-in-json": None,
"run-mypy-providers": "false",
"skip-providers-tests": "true",
},
id="Only Serialization tests",
)
),
(
pytest.param(
(
"airflow-core/src/airflow/api/file.py",
"providers/postgres/tests/unit/postgres/file.py",
),
{
"full-tests-needed": "false",
"selected-providers-list-as-string": "amazon common.compat common.sql fab google "
"microsoft.azure openlineage pgvector postgres",
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "false",
"run-helm-tests": "false",
"run-unit-tests": "true",
"run-amazon-tests": "true",
"run-api-tests": "true",
"docs-build": "true",
"skip-prek-hooks": (
"check-ts-sdk-supervisor-schema,identity,ktlint,lint-helm-chart,"
"mypy-airflow-ctl,mypy-airflow-ctl-tests,mypy-airflow-e2e-tests,"
"mypy-dev,mypy-devel-common,mypy-docker-tests,mypy-helm-tests,mypy-kubernetes-tests,"
"mypy-scripts,"
"mypy-shared-configuration,mypy-shared-dagnode,mypy-shared-listeners,mypy-shared-logging,"
"mypy-shared-module_loading,mypy-shared-observability,mypy-shared-plugins_manager,"
"mypy-shared-providers_discovery,mypy-shared-secrets_backend,mypy-shared-secrets_masker,"
"mypy-shared-serialization,mypy-shared-state,mypy-shared-template_rendering,"
"mypy-shared-timezones,mypy-task-sdk,mypy-task-sdk-integration-tests,"
"ts-compile-lint-simple-auth-manager-ui,ts-compile-lint-ui,update-uv-lock"
),
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": json.dumps(
[{"description": "API...Always", "test_types": "API Always"}]
),
"providers-test-types-list-as-strings-in-json": json.dumps(
[
{
"description": "amazon...google",
"test_types": "Providers[amazon] "
"Providers[common.compat,common.sql,fab,microsoft.azure,openlineage,pgvector,postgres] "
"Providers[google]",
}
]
),
"run-mypy-providers": "true",
},
id="API source + provider change runs API + affected providers, not the full matrix",
)
),
(
pytest.param(
("providers/apache/beam/tests/unit/apache/beam/file.py",),
{
"selected-providers-list-as-string": "common.compat google",
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "false",
"run-helm-tests": "false",
"run-unit-tests": "true",
"run-amazon-tests": "false",
"docs-build": "false",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_IF_NO_UI_AND_HELM_TESTS,
"run-kubernetes-tests": "false",
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": json.dumps(
[{"description": "Always", "test_types": "Always"}]
),
"providers-test-types-list-as-strings-in-json": json.dumps(
[
{
"description": "common.compat...google",
"test_types": "Providers[common.compat] Providers[google]",
}
]
),
"individual-providers-test-types-list-as-strings-in-json": json.dumps(
[
{
"description": "common.compat...google",
"test_types": "Providers[common.compat] Providers[google]",
}
]
),
"run-mypy-providers": "true",
},
id="Selected Providers and docs should run",
)
),
(
pytest.param(
("providers/apache/beam/tests/unit/apache/beam/file.py",),
{
"selected-providers-list-as-string": "common.compat google",
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "false",
"run-helm-tests": "false",
"run-unit-tests": "true",
"run-amazon-tests": "false",
"docs-build": "false",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_IF_NO_UI_AND_HELM_TESTS,
"run-kubernetes-tests": "false",
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": json.dumps(
[{"description": "Always", "test_types": "Always"}]
),
"providers-test-types-list-as-strings-in-json": json.dumps(
[
{
"description": "common.compat...google",
"test_types": "Providers[common.compat] Providers[google]",
}
]
),
"individual-providers-test-types-list-as-strings-in-json": json.dumps(
[
{
"description": "common.compat...google",
"test_types": "Providers[common.compat] Providers[google]",
}
]
),
"run-mypy-providers": "true",
"skip-providers-tests": "false",
},
id="Selected Providers should run when system tests are modified",
)
),
(
pytest.param(
(
"providers/apache/beam/tests/system/apache/beam/file.py",
"providers/apache/beam/tests/unit/apache/beam/file.py",
),
{
"selected-providers-list-as-string": "common.compat google",
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "false",
"run-helm-tests": "false",
"run-unit-tests": "true",
"run-amazon-tests": "false",
"docs-build": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_IF_NO_UI_AND_HELM_TESTS,
"run-kubernetes-tests": "false",
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": json.dumps(
[{"description": "Always", "test_types": "Always"}]
),
"providers-test-types-list-as-strings-in-json": json.dumps(
[
{
"description": "common.compat...google",
"test_types": "Providers[common.compat] Providers[google]",
}
]
),
"individual-providers-test-types-list-as-strings-in-json": json.dumps(
[
{
"description": "common.compat...google",
"test_types": "Providers[common.compat] Providers[google]",
}
]
),
"run-mypy-providers": "true",
"skip-providers-tests": "false",
},
id="Selected Providers and docs should run when both system tests and tests are modified",
)
),
(
pytest.param(
(
"providers/apache/beam/tests/system/apache/beam/file.py",
"providers/apache/beam/tests/unit/apache/beam/file.py",
),
{
"selected-providers-list-as-string": "common.compat google",
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "false",
"run-helm-tests": "false",
"run-unit-tests": "true",
"run-amazon-tests": "false",
"docs-build": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_IF_NO_UI_AND_HELM_TESTS,
"run-kubernetes-tests": "false",
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": json.dumps(
[{"description": "Always", "test_types": "Always"}]
),
"providers-test-types-list-as-strings-in-json": json.dumps(
[
{
"description": "common.compat...google",
"test_types": "Providers[common.compat] Providers[google]",
}
]
),
"individual-providers-test-types-list-as-strings-in-json": json.dumps(
[
{
"description": "common.compat...google",
"test_types": "Providers[common.compat] Providers[google]",
}
]
),
"run-mypy-providers": "true",
"skip-providers-tests": "false",
},
id="Selected Providers and docs should run when both system tests and tests are modified for more than one provider",
)
),
(
pytest.param(
("docs/file.rst",),
{
"selected-providers-list-as-string": None,
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "false",
"run-helm-tests": "false",
"run-unit-tests": "false",
"run-amazon-tests": "false",
"docs-build": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_ON_NO_CI_IMAGE,
"run-kubernetes-tests": "false",
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": None,
"providers-test-types-list-as-strings-in-json": None,
"run-mypy-providers": "false",
},
id="Only docs builds should run - no tests needed",
)
),
(
pytest.param(
("task-sdk/src/airflow/sdk/random.py",),
{
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "true",
"run-api-tests": "false",
"run-helm-tests": "false",
"run-kubernetes-tests": "false",
"run-unit-tests": "true",
"run-task-sdk-tests": "true",
"run-task-sdk-integration-tests": "true",
"docs-build": "true",
"full-tests-needed": "false",
"skip-prek-hooks": (
"check-provider-yaml-valid,check-ts-sdk-supervisor-schema,identity,ktlint,lint-helm-chart,"
"mypy-airflow-core,mypy-airflow-ctl,mypy-airflow-ctl-tests,mypy-airflow-e2e-tests,"
"mypy-dev,mypy-devel-common,mypy-docker-tests,mypy-helm-tests,mypy-kubernetes-tests,"
"mypy-scripts,"
"mypy-shared-configuration,mypy-shared-dagnode,mypy-shared-listeners,mypy-shared-logging,"
"mypy-shared-module_loading,mypy-shared-observability,mypy-shared-plugins_manager,"
"mypy-shared-providers_discovery,mypy-shared-secrets_backend,mypy-shared-secrets_masker,"
"mypy-shared-serialization,mypy-shared-state,mypy-shared-template_rendering,mypy-shared-timezones,mypy-task-sdk-integration-tests,"
"ts-compile-lint-simple-auth-manager-ui,ts-compile-lint-ui,update-uv-lock"
),
"skip-providers-tests": "false",
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": ALL_CI_SELECTIVE_TEST_TYPES_AS_JSON,
"providers-test-types-list-as-strings-in-json": ALL_PROVIDERS_SELECTIVE_TEST_TYPES_AS_JSON,
"run-mypy-providers": "true",
},
id="Task SDK source file changed - Task SDK, Core and provider tests should run",
)
),
(
pytest.param(
("task-sdk-integration-tests/tests/airflow/sdk/random.py",),
{
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "true",
"run-api-tests": "false",
"run-helm-tests": "false",
"run-kubernetes-tests": "false",
"run-unit-tests": "false",
"run-task-sdk-tests": "false",
"run-task-sdk-integration-tests": "true",
"docs-build": "false",
"full-tests-needed": "false",
"skip-prek-hooks": (
"check-provider-yaml-valid,check-ts-sdk-supervisor-schema,identity,ktlint,lint-helm-chart,"
"mypy-airflow-core,mypy-airflow-ctl,mypy-airflow-ctl-tests,mypy-airflow-e2e-tests,"
"mypy-dev,mypy-devel-common,mypy-docker-tests,mypy-helm-tests,mypy-kubernetes-tests,"
"mypy-scripts,"
"mypy-shared-configuration,mypy-shared-dagnode,mypy-shared-listeners,mypy-shared-logging,"
"mypy-shared-module_loading,mypy-shared-observability,mypy-shared-plugins_manager,"
"mypy-shared-providers_discovery,mypy-shared-secrets_backend,mypy-shared-secrets_masker,"
"mypy-shared-serialization,mypy-shared-state,mypy-shared-template_rendering,mypy-shared-timezones,mypy-task-sdk,"
"ts-compile-lint-simple-auth-manager-ui,ts-compile-lint-ui,update-uv-lock"
),
"skip-providers-tests": "true",
"upgrade-to-newer-dependencies": "false",
"run-mypy-providers": "false",
},
id="Task SDK integration tests files changed - "
"Task SDK integration tests and prod image build should run but no other tests",
)
),
(
pytest.param(
("ts-sdk/src/coordinator/runtime.ts",),
{
"prod-image-build": "true",
"run-unit-tests": "false",
"run-task-sdk-tests": "false",
"run-task-sdk-integration-tests": "false",
"run-ts-sdk-e2e-tests": "true",
"run-go-sdk-e2e-tests": "false",
"full-tests-needed": "false",
},
id="TypeScript SDK files changed - TS SDK e2e tests and prod image build should run",
)
),
(
pytest.param(
("ts-sdk/README.md",),
{
"prod-image-build": "false",
"run-ts-sdk-e2e-tests": "false",
"full-tests-needed": "false",
},
id="TypeScript SDK README-only change - TS SDK e2e tests should be skipped",
)
),
(
pytest.param(
("airflow-ctl/src/airflowctl/random.py",),
{
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "true",
"run-api-tests": "false",
"run-helm-tests": "false",
"run-kubernetes-tests": "false",
"run-unit-tests": "true",
"run-airflow-ctl-tests": "true",
"run-airflow-ctl-integration-tests": "true",
"docs-build": "true",
"full-tests-needed": "false",
"skip-prek-hooks": (
"check-provider-yaml-valid,check-ts-sdk-supervisor-schema,identity,ktlint,lint-helm-chart,"
"mypy-airflow-core,mypy-airflow-ctl-tests,mypy-airflow-e2e-tests,"
"mypy-dev,mypy-devel-common,mypy-docker-tests,mypy-helm-tests,mypy-kubernetes-tests,"
"mypy-scripts,"
"mypy-shared-configuration,mypy-shared-dagnode,mypy-shared-listeners,mypy-shared-logging,"
"mypy-shared-module_loading,mypy-shared-observability,mypy-shared-plugins_manager,"
"mypy-shared-providers_discovery,mypy-shared-secrets_backend,mypy-shared-secrets_masker,"
"mypy-shared-serialization,mypy-shared-state,mypy-shared-template_rendering,mypy-shared-timezones,mypy-task-sdk,mypy-task-sdk-integration-tests,"
"ts-compile-lint-simple-auth-manager-ui,ts-compile-lint-ui,update-uv-lock"
),
"skip-providers-tests": "true",
"upgrade-to-newer-dependencies": "false",
"run-mypy-providers": "false",
},
id="Airflow CTL source file changed - Airflow CTL tests should run",
)
),
(
pytest.param(
("airflow-ctl-tests/tests/random.py",),
{
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "true",
"run-api-tests": "false",
"run-helm-tests": "false",
"run-kubernetes-tests": "false",
"run-unit-tests": "false",
"run-airflow-ctl-tests": "false",
"run-airflow-ctl-integration-tests": "true",
"docs-build": "false",
"full-tests-needed": "false",
"skip-prek-hooks": (
"check-provider-yaml-valid,check-ts-sdk-supervisor-schema,identity,ktlint,lint-helm-chart,"
"mypy-airflow-core,mypy-airflow-ctl,mypy-airflow-e2e-tests,"
"mypy-dev,mypy-devel-common,mypy-docker-tests,mypy-helm-tests,mypy-kubernetes-tests,"
"mypy-scripts,"
"mypy-shared-configuration,mypy-shared-dagnode,mypy-shared-listeners,mypy-shared-logging,"
"mypy-shared-module_loading,mypy-shared-observability,mypy-shared-plugins_manager,"
"mypy-shared-providers_discovery,mypy-shared-secrets_backend,mypy-shared-secrets_masker,"
"mypy-shared-serialization,mypy-shared-state,mypy-shared-template_rendering,mypy-shared-timezones,mypy-task-sdk,mypy-task-sdk-integration-tests,"
"ts-compile-lint-simple-auth-manager-ui,ts-compile-lint-ui,update-uv-lock"
),
"skip-providers-tests": "true",
"upgrade-to-newer-dependencies": "false",
"run-mypy-providers": "false",
},
id="Airflow CTL integration tests files changed - "
"Airflow CTL integration tests and prod image build should run but no other tests",
)
),
(
pytest.param(
(
"chart/aaaa.txt",
"providers/postgres/tests/unit/postgres/file.py",
),
{
"selected-providers-list-as-string": "amazon common.compat common.sql google "
"microsoft.azure openlineage pgvector postgres",
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "true",
"run-helm-tests": "true",
"run-unit-tests": "true",
"run-amazon-tests": "true",
"docs-build": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_IF_NO_UI,
"run-kubernetes-tests": "true",
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": json.dumps(
[{"description": "Always", "test_types": "Always"}]
),
"providers-test-types-list-as-strings-in-json": json.dumps(
[
{
"description": "amazon...google",
"test_types": "Providers[amazon] "
"Providers[common.compat,common.sql,microsoft.azure,openlineage,pgvector,postgres] "
"Providers[google]",
}
]
),
"run-mypy-providers": "true",
},
id="Helm tests, providers (both upstream and downstream),"
"kubernetes tests and docs should run",
)
),
(
pytest.param(
(
"INTHEWILD.md",
"chart/aaaa.txt",
"providers/http/tests/file.py",
),
{
"selected-providers-list-as-string": "amazon apache.livy atlassian.jira common.compat dbt.cloud dingding discord google http informatica pagerduty",
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "true",
"run-helm-tests": "true",
"run-unit-tests": "true",
"run-amazon-tests": "true",
"docs-build": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_IF_NO_UI,
"run-kubernetes-tests": "true",
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": json.dumps(
[{"description": "Always", "test_types": "Always"}]
),
"providers-test-types-list-as-strings-in-json": json.dumps(
[
{
"description": "amazon...google",
"test_types": "Providers[amazon] Providers[apache.livy,atlassian.jira,common.compat,dbt.cloud,dingding,discord,http,informatica,pagerduty] Providers[google]",
}
]
),
"individual-providers-test-types-list-as-strings-in-json": json.dumps(
[
{
"description": "amazon...atlassian.jir",
"test_types": "Providers[amazon] Providers[apache.livy] Providers[atlassian.jira]",
},
{
"description": "common.compat...dbt.cloud",
"test_types": "Providers[common.compat] Providers[dbt.cloud]",
},
{
"description": "dingding...discord",
"test_types": "Providers[dingding] Providers[discord]",
},
{
"description": "google...http",
"test_types": "Providers[google] Providers[http]",
},
{
"description": "informatica...pagerduty",
"test_types": "Providers[informatica] Providers[pagerduty]",
},
]
),
"run-mypy-providers": "true",
},
id="Helm tests, http and all relevant providers, kubernetes tests and "
"docs should run even if unimportant files were added",
)
),
(
pytest.param(
(
"INTHEWILD.md",
"chart/aaaa.txt",
"providers/airbyte/tests/file.py",
),
{
"selected-providers-list-as-string": "airbyte common.compat",
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "true",
"run-helm-tests": "true",
"run-unit-tests": "true",
"run-amazon-tests": "false",
"docs-build": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_IF_NO_UI,
"run-kubernetes-tests": "true",
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": json.dumps(
[{"description": "Always", "test_types": "Always"}]
),
"providers-test-types-list-as-strings-in-json": json.dumps(
[
{
"description": "airbyte,common.compat",
"test_types": "Providers[airbyte,common.compat]",
}
]
),
},
id="Helm tests, airbyte providers, kubernetes tests and "
"docs should run even if unimportant files were added",
)
),
(
pytest.param(
(
"INTHEWILD.md",
"chart/aaaa.txt",
"foo/other.py",
),
{
"selected-providers-list-as-string": None,
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "true",
"run-helm-tests": "true",
"run-unit-tests": "false",
"docs-build": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_IF_NO_PROVIDERS_AND_UI,
"run-amazon-tests": "false",
"run-kubernetes-tests": "true",
"upgrade-to-newer-dependencies": "false",
"providers-test-types-list-as-strings-in-json": None,
"run-mypy-providers": "false",
},
id="Docs should run even if unimportant files were added and prod image "
"should be build for chart changes",
)
),
(
pytest.param(
("pyproject.toml",),
{
"selected-providers-list-as-string": ALL_PROVIDERS_AFFECTED,
"all-python-versions": ALL_PYTHON_VERSIONS_AS_LIST,
"all-python-versions-list-as-string": ALL_PYTHON_VERSIONS_AS_STRING,
"python-versions": ALL_PYTHON_VERSIONS_AS_LIST,
"python-versions-list-as-string": ALL_PYTHON_VERSIONS_AS_STRING,
"ci-image-build": "true",
"prod-image-build": "true",
"run-helm-tests": "true",
"run-unit-tests": "true",
"run-amazon-tests": "true",
"docs-build": "true",
"full-tests-needed": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_BY_DEFAULT_ON_ALL_TESTS_NEEDED,
"upgrade-to-newer-dependencies": "true",
"core-test-types-list-as-strings-in-json": ALL_CI_SELECTIVE_TEST_TYPES_AS_JSON,
"providers-test-types-list-as-strings-in-json": ALL_PROVIDERS_SELECTIVE_TEST_TYPES_AS_JSON,
"run-mypy-providers": "true",
},
id="Everything should run and upgrading to newer requirements as dependencies change",
)
),
pytest.param(
("providers/amazon/src/airflow/providers/amazon/provider.yaml",),
{
"selected-providers-list-as-string": "amazon apache.hive cncf.kubernetes "
"common.compat common.messaging common.sql databricks exasol ftp google http imap microsoft.azure "
"mongo mysql openlineage postgres salesforce ssh teradata",
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "false",
"run-helm-tests": "false",
"run-unit-tests": "true",
"docs-build": "false",
# no python files changed so flynt should not run
"skip-prek-hooks": ALL_SKIPPED_COMMITS_IF_NO_UI_AND_HELM_TESTS.replace(
"check-ts-sdk-supervisor-schema,", "check-ts-sdk-supervisor-schema,flynt,", 1
),
"run-kubernetes-tests": "false",
"upgrade-to-newer-dependencies": "false",
"run-amazon-tests": "true",
"core-test-types-list-as-strings-in-json": json.dumps(
[{"description": "Always", "test_types": "Always"}]
),
"providers-test-types-list-as-strings-in-json": json.dumps(
[
{
"description": "amazon...google",
"test_types": "Providers[amazon] Providers[apache.hive,cncf.kubernetes,"
"common.compat,common.messaging,common.sql,databricks,exasol,ftp,http,imap,"
"microsoft.azure,mongo,mysql,openlineage,postgres,salesforce,ssh,teradata] "
"Providers[google]",
}
]
),
"run-mypy-providers": "true",
},
id="Providers tests run including amazon tests if only amazon provider.yaml files changed",
),
pytest.param(
("providers/airbyte/tests/airbyte/__init__.py",),
{
"selected-providers-list-as-string": "airbyte common.compat",
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "false",
"run-helm-tests": "false",
"run-unit-tests": "true",
"run-amazon-tests": "false",
"docs-build": "false",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_IF_NO_UI_AND_HELM_TESTS,
"run-kubernetes-tests": "false",
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": json.dumps(
[{"description": "Always", "test_types": "Always"}]
),
"providers-test-types-list-as-strings-in-json": json.dumps(
[
{
"description": "airbyte,common.compat",
"test_types": "Providers[airbyte,common.compat]",
}
]
),
"run-mypy-providers": "true",
},
id="Providers tests run without amazon tests if no amazon file changed",
),
pytest.param(
("providers/amazon/src/airflow/providers/amazon/file.py",),
{
"selected-providers-list-as-string": "amazon apache.hive cncf.kubernetes "
"common.compat common.messaging common.sql databricks exasol ftp google http imap microsoft.azure "
"mongo mysql openlineage postgres salesforce ssh teradata",
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "false",
"run-helm-tests": "false",
"run-unit-tests": "true",
"run-amazon-tests": "true",
"docs-build": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_IF_NO_UI_AND_HELM_TESTS,
"run-kubernetes-tests": "false",
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": json.dumps(
[{"description": "Always", "test_types": "Always"}]
),
"providers-test-types-list-as-strings-in-json": json.dumps(
[
{
"description": "amazon...google",
"test_types": "Providers[amazon] Providers[apache.hive,cncf.kubernetes,"
"common.compat,common.messaging,common.sql,databricks,exasol,ftp,http,imap,"
"microsoft.azure,mongo,mysql,openlineage,postgres,salesforce,ssh,teradata] "
"Providers[google]",
}
]
),
"run-mypy-providers": "true",
},
id="Providers tests run including amazon tests if amazon provider files changed",
),
pytest.param(
(
"airflow-core/tests/unit/always/test_project_structure.py",
"providers/common/io/tests/operators/__init__.py",
"providers/common/io/tests/operators/test_file_transfer.py",
),
{
"selected-providers-list-as-string": "common.compat common.io openlineage",
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
# common providers feed OpenLineage e2e tests, which need the PROD image.
"prod-image-build": "true",
"run-openlineage-e2e-tests": "true",
# ordinary OL PR (no canary, no "full tests needed" label): compat matrix stays off.
"run-openlineage-e2e-compat-tests": "false",
"run-helm-tests": "false",
"run-unit-tests": "true",
"run-amazon-tests": "false",
"docs-build": "false",
"run-kubernetes-tests": "false",
"skip-prek-hooks": (
"check-ts-sdk-supervisor-schema,identity,ktlint,lint-helm-chart,"
"mypy-airflow-ctl,mypy-airflow-ctl-tests,mypy-airflow-e2e-tests,"
"mypy-dev,mypy-devel-common,mypy-docker-tests,mypy-helm-tests,mypy-kubernetes-tests,"
"mypy-scripts,"
"mypy-shared-configuration,mypy-shared-dagnode,mypy-shared-listeners,mypy-shared-logging,"
"mypy-shared-module_loading,mypy-shared-observability,mypy-shared-plugins_manager,"
"mypy-shared-providers_discovery,mypy-shared-secrets_backend,mypy-shared-secrets_masker,"
"mypy-shared-serialization,mypy-shared-state,mypy-shared-template_rendering,mypy-shared-timezones,mypy-task-sdk,mypy-task-sdk-integration-tests,"
"ts-compile-lint-simple-auth-manager-ui,ts-compile-lint-ui,update-uv-lock"
),
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": json.dumps(
[{"description": "Always", "test_types": "Always"}]
),
"providers-test-types-list-as-strings-in-json": json.dumps(
[
{
"description": "common.compat,common.io,openl",
"test_types": "Providers[common.compat,common.io,openlineage]",
}
]
),
"run-mypy-providers": "true",
},
id="Only Always and common providers tests should run when only common.io and tests/always changed",
),
pytest.param(
("providers/standard/src/airflow/providers/standard/operators/bash.py",),
{
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "true",
"run-helm-tests": "true",
"run-unit-tests": "true",
"run-amazon-tests": "true",
"docs-build": "true",
"run-kubernetes-tests": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_BY_DEFAULT_ON_ALL_TESTS_NEEDED,
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": ALL_CI_SELECTIVE_TEST_TYPES_AS_JSON,
"providers-test-types-list-as-strings-in-json": ALL_PROVIDERS_SELECTIVE_TEST_TYPES_AS_JSON,
"run-mypy-providers": "true",
},
id="All tests to run when standard operator changed",
),
(
pytest.param(
("airflow-core/tests/unit/utils/test_cli_util.py",),
{
"selected-providers-list-as-string": ALL_PROVIDERS_AFFECTED,
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "true",
"run-helm-tests": "true",
"run-unit-tests": "true",
"run-amazon-tests": "true",
"docs-build": "true",
"full-tests-needed": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_BY_DEFAULT_ON_ALL_TESTS_NEEDED,
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": ALL_CI_SELECTIVE_TEST_TYPES_AS_JSON,
"providers-test-types-list-as-strings-in-json": ALL_PROVIDERS_SELECTIVE_TEST_TYPES_AS_JSON,
"run-mypy-providers": "true",
},
id="All tests should be run when tests/utils/ change",
)
),
(
pytest.param(
("devel-common/src/tests_common/test_utils/__init__.py",),
{
"selected-providers-list-as-string": ALL_PROVIDERS_AFFECTED,
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "true",
"run-helm-tests": "true",
"run-unit-tests": "true",
"run-amazon-tests": "true",
"docs-build": "true",
"full-tests-needed": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_BY_DEFAULT_ON_ALL_TESTS_NEEDED,
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": ALL_CI_SELECTIVE_TEST_TYPES_AS_JSON,
"providers-test-types-list-as-strings-in-json": ALL_PROVIDERS_SELECTIVE_TEST_TYPES_AS_JSON,
"testable-core-integrations": "['kerberos', 'otel', 'redis']",
"testable-providers-integrations": "['celery', 'cassandra', 'drill', 'elasticsearch', 'tinkerpop', 'kafka', "
"'mongo', 'pinot', 'qdrant', 'redis', 'trino', 'ydb']",
"run-mypy-providers": "true",
},
id="All tests should be run when devel-common/ change",
)
),
(
pytest.param(
("airflow-core/src/airflow/ui/src/index.tsx",),
{
"selected-providers-list-as-string": None,
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "true",
"docs-build": "false",
"full-tests-needed": "false",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_IF_NO_CODE_PROVIDERS_AND_HELM_TESTS,
"upgrade-to-newer-dependencies": "false",
"run-mypy-providers": "false",
"run-helm-tests": "false",
"run-ui-tests": "true",
"run-ui-e2e-tests": "true",
"run-unit-tests": "false",
"run-go-sdk-tests": "false",
"run-airflow-ctl-tests": "false",
"run-amazon-tests": "false",
},
id="Run only ui tests for PR with new UI only changes.",
)
),
pytest.param(
("RELEASE_NOTES.rst",),
{
"selected-providers-list-as-string": None,
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"run-helm-tests": "false",
"run-unit-tests": "false",
"run-amazon-tests": "false",
"docs-build": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_ON_NO_CI_IMAGE,
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": None,
"providers-test-types-list-as-strings-in-json": None,
"individual-providers-test-types-list-as-strings-in-json": None,
"run-mypy-providers": "false",
},
id="Run docs-build for RELEASE_NOTES.rst",
),
pytest.param(
("chart/RELEASE_NOTES.rst",),
{
"selected-providers-list-as-string": None,
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"run-helm-tests": "true",
"run-unit-tests": "false",
"run-amazon-tests": "false",
"docs-build": "true",
"skip-prek-hooks": (
"check-provider-yaml-valid,check-ts-sdk-supervisor-schema,flynt,identity,ktlint,"
"mypy-airflow-core,mypy-airflow-ctl,mypy-airflow-ctl-tests,mypy-airflow-e2e-tests,"
"mypy-dev,mypy-devel-common,mypy-docker-tests,mypy-helm-tests,mypy-kubernetes-tests,"
"mypy-scripts,"
"mypy-shared-configuration,mypy-shared-dagnode,mypy-shared-listeners,mypy-shared-logging,"
"mypy-shared-module_loading,mypy-shared-observability,mypy-shared-plugins_manager,"
"mypy-shared-providers_discovery,mypy-shared-secrets_backend,mypy-shared-secrets_masker,"
"mypy-shared-serialization,mypy-shared-state,mypy-shared-template_rendering,mypy-shared-timezones,mypy-task-sdk,mypy-task-sdk-integration-tests,"
"ts-compile-lint-simple-auth-manager-ui,ts-compile-lint-ui,update-uv-lock"
),
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": None,
"providers-test-types-list-as-strings-in-json": None,
"individual-providers-test-types-list-as-strings-in-json": None,
"run-mypy-providers": "false",
},
id="Run docs-build for chart/RELEASE_NOTES.rst",
),
pytest.param(
(".github/SECURITY.md",),
{
"selected-providers-list-as-string": None,
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"run-helm-tests": "false",
"run-unit-tests": "false",
"run-amazon-tests": "false",
"docs-build": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_ON_NO_CI_IMAGE,
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": None,
"providers-test-types-list-as-strings-in-json": None,
"individual-providers-test-types-list-as-strings-in-json": None,
"run-mypy-providers": "false",
},
id="Run docs-build for SECURITY.md",
),
pytest.param(
("go-sdk/sdk/variable.go",),
{
"run-go-sdk-tests": "true",
"run-java-sdk-e2e-tests": "false",
},
id="Run go tests for go-sdk and skip java e2e tests for non-java change",
),
pytest.param(
("java-sdk/sdk/build.gradle.kts",),
{
"run-java-sdk-tests": "true",
"run-java-sdk-e2e-tests": "true",
"prod-image-build": "true",
},
id="Run java unit and e2e tests for java-sdk source change",
),
pytest.param(
("java-sdk/README.md",),
{
"run-java-sdk-tests": "false",
"run-java-sdk-e2e-tests": "false",
"prod-image-build": "false",
},
id="Skip java unit and e2e tests for java-sdk README-only change",
),
pytest.param(
("airflow-e2e-tests/docker/java.yml",),
{
"run-java-sdk-tests": "false",
"run-java-sdk-e2e-tests": "true",
"prod-image-build": "true",
},
id="Run java e2e tests when java compose override changes",
),
pytest.param(
("task-sdk/src/airflow/sdk/coordinators/java/coordinator.py",),
{
"run-java-sdk-e2e-tests": "true",
"prod-image-build": "true",
},
id="Run java e2e tests when JavaCoordinator changes",
),
pytest.param(
("go-sdk/sdk/variable.go",),
{
"run-go-sdk-tests": "true",
"run-go-sdk-e2e-tests": "true",
"prod-image-build": "true",
},
id="Run go unit and e2e tests for go-sdk source change",
),
pytest.param(
("go-sdk/go.mod",),
{
"run-go-sdk-tests": "true",
"run-go-sdk-e2e-tests": "true",
"prod-image-build": "true",
},
id="Run go unit and e2e tests for go-sdk dependency change",
),
pytest.param(
("go-sdk/README.md",),
{
"run-go-sdk-tests": "false",
"run-go-sdk-e2e-tests": "false",
"prod-image-build": "false",
},
id="Skip go unit and e2e tests for go-sdk README-only change",
),
pytest.param(
("go-sdk/adr/0001-bundle-packing-options.md",),
{
"run-go-sdk-tests": "false",
"run-go-sdk-e2e-tests": "false",
"prod-image-build": "false",
},
id="Skip go unit and e2e tests for go-sdk ADR-only change",
),
pytest.param(
("airflow-e2e-tests/docker/go.yml",),
{
"run-go-sdk-tests": "false",
"run-go-sdk-e2e-tests": "true",
"prod-image-build": "true",
},
id="Run go e2e tests when go compose override changes",
),
pytest.param(
("task-sdk/src/airflow/sdk/coordinators/executable/coordinator.py",),
{
"run-go-sdk-e2e-tests": "true",
"prod-image-build": "true",
},
id="Run go e2e tests when ExecutableCoordinator changes",
),
pytest.param(
("providers/openlineage/src/airflow/providers/openlineage/plugins/adapter.py",),
{
"run-openlineage-e2e-tests": "true",
"prod-image-build": "true",
},
id="Run OpenLineage e2e tests for openlineage provider change",
),
pytest.param(
("providers/common/compat/src/airflow/providers/common/compat/sdk.py",),
{
"run-openlineage-e2e-tests": "true",
"prod-image-build": "true",
},
id="Run OpenLineage e2e tests for common provider change",
),
pytest.param(
("airflow-e2e-tests/tests/airflow_e2e_tests/openlineage_tests/harness.py",),
{
"run-openlineage-e2e-tests": "true",
"run-openlineage-e2e-compat-tests": "false",
"prod-image-build": "true",
},
id="Run OpenLineage e2e tests (not the costly compat matrix) when the OL e2e suite changes",
),
pytest.param(
("providers/ftp/src/airflow/providers/ftp/hooks/ftp.py",),
{
"run-openlineage-e2e-tests": "false",
"run-openlineage-e2e-compat-tests": "false",
"prod-image-build": "false",
},
id="Do not run OpenLineage e2e tests for unrelated provider change",
),
pytest.param(
("airflow-e2e-tests/tests/airflow_e2e_tests/conftest.py",),
{
"run-openlineage-e2e-tests": "false",
"run-openlineage-e2e-compat-tests": "true",
"full-tests-needed": "false",
"prod-image-build": "true",
},
id="Run OpenLineage e2e compat tests when the shared e2e harness (conftest) changes",
),
pytest.param(
("airflow-e2e-tests/docker/openlineage-compat.Dockerfile",),
{
"run-openlineage-e2e-tests": "false",
"run-openlineage-e2e-compat-tests": "true",
"full-tests-needed": "false",
"prod-image-build": "true",
},
id="Run OpenLineage e2e compat tests when the compat Dockerfile changes",
),
pytest.param(
(".github/workflows/openlineage-e2e-compat-tests.yml",),
{
# The compat workflow matches ENVIRONMENT_FILES, so it forces the full matrix.
# The compat therefore runs via full_tests_needed, not via OPENLINEAGE_E2E_COMPAT_FILES.
"run-openlineage-e2e-tests": "true",
"run-openlineage-e2e-compat-tests": "true",
"full-tests-needed": "true",
},
id="Compat workflow change forces the full matrix (compat runs via full_tests_needed)",
),
(
pytest.param(
("devel-common/pyproject.toml",),
{
"run-mypy-providers": "true",
},
id="All mypy checks should run when devel-common/pyproject.toml changes",
)
),
(
pytest.param(
("providers/amazon/src/airflow/providers/amazon/aws/log/s3_task_handler.py",),
{
"run-remote-logging-s3-e2e-tests": "true",
"run-remote-logging-elasticsearch-e2e-tests": "false",
"ci-image-build": "true",
"prod-image-build": "true",
},
id="S3 remote logging changes enable only S3 e2e",
)
),
(
pytest.param(
("providers/elasticsearch/src/airflow/providers/elasticsearch/log/es_task_handler.py",),
{
"run-remote-logging-s3-e2e-tests": "false",
"run-remote-logging-elasticsearch-e2e-tests": "true",
"run-remote-logging-opensearch-e2e-tests": "false",
"ci-image-build": "true",
"prod-image-build": "true",
},
id="Elasticsearch remote logging changes enable only Elasticsearch e2e",
)
),
(
pytest.param(
("providers/elasticsearch/src/airflow/providers/elasticsearch/log/es_json_formatter.py",),
{
"run-remote-logging-s3-e2e-tests": "false",
"run-remote-logging-elasticsearch-e2e-tests": "true",
"run-remote-logging-opensearch-e2e-tests": "false",
"ci-image-build": "true",
"prod-image-build": "true",
},
id="Elasticsearch helper changes enable Elasticsearch e2e",
)
),
(
pytest.param(
("providers/opensearch/src/airflow/providers/opensearch/log/os_task_handler.py",),
{
"run-remote-logging-s3-e2e-tests": "false",
"run-remote-logging-elasticsearch-e2e-tests": "false",
"run-remote-logging-opensearch-e2e-tests": "true",
"ci-image-build": "true",
"prod-image-build": "true",
},
id="OpenSearch remote logging changes enable only OpenSearch e2e",
)
),
(
pytest.param(
("providers/opensearch/src/airflow/providers/opensearch/log/os_json_formatter.py",),
{
"run-remote-logging-s3-e2e-tests": "false",
"run-remote-logging-elasticsearch-e2e-tests": "false",
"run-remote-logging-opensearch-e2e-tests": "true",
"ci-image-build": "true",
"prod-image-build": "true",
},
id="OpenSearch helper changes enable OpenSearch e2e",
)
),
(
pytest.param(
("airflow-core/src/airflow/config_templates/airflow_local_settings.py",),
{
"run-remote-logging-s3-e2e-tests": "true",
"run-remote-logging-elasticsearch-e2e-tests": "true",
"run-remote-logging-opensearch-e2e-tests": "true",
"ci-image-build": "true",
"prod-image-build": "true",
},
id="Shared remote logging changes enable both remote logging e2e jobs",
)
),
(
pytest.param(
("shared/logging/src/airflow_shared/logging/remote.py",),
{
"run-remote-logging-s3-e2e-tests": "true",
"run-remote-logging-elasticsearch-e2e-tests": "true",
"run-remote-logging-opensearch-e2e-tests": "true",
"ci-image-build": "true",
"prod-image-build": "true",
},
id="Shared logging library changes enable both remote logging e2e jobs",
)
),
(
pytest.param(
("shared/timezones/src/airflow_shared/timezones/timezone.py",),
{
"ci-image-build": "true",
"run-unit-tests": "true",
},
id="Shared library python changes trigger unit tests",
)
),
(
pytest.param(
("shared/logging/src/airflow_shared/logging/remote.py",),
{
"skip-prek-hooks": (
"check-provider-yaml-valid,check-ts-sdk-supervisor-schema,identity,ktlint,lint-helm-chart,"
"mypy-airflow-core,mypy-airflow-ctl,mypy-airflow-ctl-tests,"
"mypy-airflow-e2e-tests,mypy-dev,mypy-devel-common,mypy-docker-tests,"
"mypy-helm-tests,mypy-kubernetes-tests,mypy-scripts,"
"mypy-shared-configuration,mypy-shared-dagnode,mypy-shared-listeners,"
"mypy-shared-module_loading,mypy-shared-observability,"
"mypy-shared-plugins_manager,mypy-shared-providers_discovery,"
"mypy-shared-secrets_backend,mypy-shared-secrets_masker,"
"mypy-shared-serialization,mypy-shared-state,mypy-shared-template_rendering,"
"mypy-shared-timezones,mypy-task-sdk,mypy-task-sdk-integration-tests,"
"ts-compile-lint-simple-auth-manager-ui,ts-compile-lint-ui,update-uv-lock"
),
},
id=("Shared logging change keeps only mypy-shared-logging among the mypy-shared-* hooks"),
)
),
],
)
def test_expected_output_pull_request_main(
files: tuple[str, ...],
expected_outputs: dict[str, str],
):
stderr = SelectiveChecks(
files=files,
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.PULL_REQUEST,
pr_labels=tuple(),
default_branch="main",
)
assert_outputs_are_printed(expected_outputs, str(stderr))
@pytest.mark.parametrize(
("files", "ktlint_skipped"),
[
pytest.param(
("java-sdk/sdk/build.gradle.kts",),
False,
id="ktlint runs when java-sdk files change",
),
pytest.param(
("SECURITY.md",),
True,
id="ktlint skipped when no java-sdk files change",
),
pytest.param(
("java-sdk/README.md",),
True,
id="ktlint skipped when only java-sdk docs change",
),
],
)
def test_ktlint_hook_only_runs_for_java_sdk_changes(files: tuple[str, ...], ktlint_skipped: bool):
# ktlint downloads the Gradle distribution, so it must be skipped unless java-sdk changed.
stderr = SelectiveChecks(
files=files,
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.PULL_REQUEST,
pr_labels=tuple(),
default_branch="main",
)
skipped_hooks = get_outputs_from_stderr(str(stderr))["skip-prek-hooks"].split(",")
assert ("ktlint" in skipped_hooks) is ktlint_skipped
@pytest.mark.parametrize(
("files", "hook_skipped"),
[
pytest.param(
("ts-sdk/src/generated/supervisor.ts",),
False,
id="runs when ts-sdk files change",
),
pytest.param(
("task-sdk/src/airflow/sdk/execution_time/schema/schema.json",),
True,
id="skipped when only the supervisor schema changes",
),
pytest.param(
("SECURITY.md",),
True,
id="skipped when no ts-sdk files change",
),
pytest.param(
("ts-sdk/README.md",),
True,
id="skipped when only ts-sdk docs change",
),
pytest.param(
("ts-sdk/example/README.md",),
True,
id="skipped when only nested ts-sdk docs change",
),
],
)
def test_check_ts_sdk_supervisor_schema_hook_only_runs_for_relevant_changes(
files: tuple[str, ...], hook_skipped: bool
):
# This hook regenerates and diffs ts-sdk/src/generated/supervisor.ts. Only ts-sdk changes
# trigger it; regenerating after a wire-schema bump is the ts-sdk follow-up PR's job.
stderr = SelectiveChecks(
files=files,
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.PULL_REQUEST,
pr_labels=tuple(),
default_branch="main",
)
skipped_hooks = get_outputs_from_stderr(str(stderr))["skip-prek-hooks"].split(",")
assert ("check-ts-sdk-supervisor-schema" in skipped_hooks) is hook_skipped
def test_java_sdk_version_is_emitted_as_output():
# The lang-SDK k8s job reads this to pick the JDK for the native Java build via actions/setup-java.
stderr = SelectiveChecks(
files=("README.md",),
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.PULL_REQUEST,
pr_labels=tuple(),
default_branch="main",
)
assert get_outputs_from_stderr(str(stderr))["java-sdk-version"] == JAVA_SDK_VERSION
@pytest.mark.skipif(
not (AIRFLOW_ROOT_PATH / ".git").exists(),
reason="This test should not run if .git folder is missing (for example by default in breeze container)",
)
@pytest.mark.parametrize(
("files", "commit_ref", "expected_outputs"),
[
(
pytest.param(
("pyproject.toml",),
"c381fdaff42bbda480eee70fb15c5b26a2a3a77d",
{
"full-tests-needed": "true",
"all-versions": "true",
},
id="Full tests needed / all versions when build-system changes in pyproject.toml",
)
),
],
)
def test_full_test_needed_when_pyproject_toml_changes(
files: tuple[str, ...], commit_ref: str, expected_outputs: dict[str, str]
):
stderr = SelectiveChecks(
files=files,
github_event=GithubEvents.PULL_REQUEST,
commit_ref=commit_ref,
default_branch="main",
)
assert_outputs_are_printed(expected_outputs, str(stderr))
@pytest.mark.parametrize(
("files", "github_event", "expected_outputs"),
[
pytest.param(
("README.md",),
GithubEvents.PULL_REQUEST,
{
"run-unit-tests": "false",
"ci-image-build": "false",
"docs-build": "false",
},
id="Only .md file changed in PR - no tests needed",
),
pytest.param(
("requirements.txt", "NOTICE.txt"),
GithubEvents.PULL_REQUEST,
{
"run-unit-tests": "false",
"ci-image-build": "false",
"docs-build": "false",
},
id="Only .txt files changed in PR - no tests needed",
),
pytest.param(
("README.md", "airflow-core/src/airflow/api.py"),
GithubEvents.PULL_REQUEST,
{
"run-unit-tests": "true",
"ci-image-build": "true",
},
id="Mixed .md and source file changed - tests needed",
),
],
)
def test_text_non_doc_files_do_not_trigger_tests(
files: tuple[str, ...], github_event: str, expected_outputs: dict[str, str]
):
stderr = SelectiveChecks(
files=files,
commit_ref=NEUTRAL_COMMIT,
github_event=github_event,
pr_labels=(),
default_branch="main",
)
assert_outputs_are_printed(expected_outputs, str(stderr))
def test_list_splitting():
stderr = SelectiveChecks(
pr_labels=("full tests needed",),
default_branch="main",
)
output_dict = get_outputs_from_stderr(str(stderr))
individual_providers_test_types_list_as_string = json.loads(
output_dict["individual-providers-test-types-list-as-strings-in-json"]
)
all_providers_in_sub_lists = [
list_of_types["test_types"].split(" ")
for list_of_types in individual_providers_test_types_list_as_string
]
assert len(all_providers_in_sub_lists) == NUMBER_OF_LOW_DEP_SLICES
assert sum([len(list_of_types) for list_of_types in all_providers_in_sub_lists]) == len(
LIST_OF_ALL_PROVIDER_TESTS
)
def test_excluded_providers():
stderr = SelectiveChecks(
files=(),
github_event=GithubEvents.PULL_REQUEST,
default_branch="main",
)
assert_outputs_are_printed(
{
"excluded-providers-as-string": json.dumps(
{
"3.14": [
"apache.cassandra", # Enable when the next release after 3.29.3 is available
],
}
),
},
str(stderr),
)
@pytest.mark.parametrize(
("files", "expected_outputs"),
[
(
pytest.param(
("scripts/ci/prek/file.sh",),
{
# prek hooks are static checks, not tests: they must not force the full
# test matrix, but they still build the CI image so mypy-scripts and the
# image-based static checks run.
"full-tests-needed": "false",
"ci-image-build": "true",
},
id="prek scripts build the CI image but do not force full tests",
)
),
(
pytest.param(
("scripts/docker-compose/test.yml",),
{
"full-tests-needed": "true",
},
id="Full tests needed when docker-compose changes",
)
),
(
pytest.param(
("scripts/ci/kubernetes/some_file.txt",),
{
"full-tests-needed": "true",
},
id="Full tests needed when ci/kubernetes changes",
)
),
(
pytest.param(
("scripts/in_container/script.sh",),
{
"full-tests-needed": "true",
},
id="Full tests needed when in_container script changes",
)
),
],
)
def test_full_test_needed_when_scripts_changes(files: tuple[str, ...], expected_outputs: dict[str, str]):
stderr = SelectiveChecks(
files=files,
github_event=GithubEvents.PULL_REQUEST,
commit_ref=NEUTRAL_COMMIT,
default_branch="main",
)
assert_outputs_are_printed(expected_outputs, str(stderr))
@pytest.mark.parametrize(
"files",
[
pytest.param(
("scripts/ci/prek/check_provider_yaml_files.py",),
id="provider yaml check script changed",
),
pytest.param(
("providers/.pre-commit-config.yaml",),
id="providers prek config changed",
),
pytest.param(
(
"scripts/ci/prek/check_provider_yaml_files.py",
"providers/.pre-commit-config.yaml",
),
id="provider yaml check script and providers prek config changed together",
),
],
)
def test_provider_yaml_check_not_skipped_when_check_scripts_change(files: tuple[str, ...]):
stderr = SelectiveChecks(
files=files,
github_event=GithubEvents.PULL_REQUEST,
commit_ref=NEUTRAL_COMMIT,
default_branch="main",
)
skip_prek_hooks = str(stderr).split("skip-prek-hooks=")[1].split("\n")[0]
assert "check-provider-yaml-valid" not in skip_prek_hooks.split(",")
@pytest.mark.parametrize(
"files",
[
pytest.param(
("airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml",),
id="private UI spec changed",
),
pytest.param(
(
"airflow-core/src/airflow/api_fastapi/auth/managers/simple/openapi/v2-simple-auth-manager-generated.yaml",
),
id="simple auth manager spec changed",
),
],
)
def test_ui_compile_hooks_not_skipped_when_ui_openapi_spec_changes(files: tuple[str, ...]):
stderr = SelectiveChecks(
files=files,
github_event=GithubEvents.PULL_REQUEST,
commit_ref=NEUTRAL_COMMIT,
default_branch="main",
)
skip_prek_hooks = str(stderr).split("skip-prek-hooks=")[1].split("\n")[0]
assert "ts-compile-lint-ui" not in skip_prek_hooks.split(",")
assert "ts-compile-lint-simple-auth-manager-ui" not in skip_prek_hooks.split(",")
@pytest.mark.parametrize(
("files", "expected_outputs"),
[
pytest.param(
(".github/workflows/ci-amd.yml",),
{"full-tests-needed": "true"},
id="Test workflow (ci-amd) forces full tests",
),
pytest.param(
(".github/workflows/run-unit-tests.yml",),
{"full-tests-needed": "true"},
id="Test workflow (run-unit-tests) forces full tests",
),
pytest.param(
(".github/workflows/codeql-analysis.yml",),
{"full-tests-needed": "false"},
id="Non-test workflow (codeql) does not force full tests",
),
pytest.param(
(".github/workflows/publish-docs-to-s3.yml",),
{"full-tests-needed": "false"},
id="Non-test workflow (publish-docs-to-s3) does not force full tests",
),
pytest.param(
(".github/workflows/ci-notification.yml",),
{"full-tests-needed": "false"},
id="Non-test workflow (ci-notification) does not force full tests",
),
],
)
def test_non_test_workflows_do_not_force_full_tests(files: tuple[str, ...], expected_outputs: dict[str, str]):
stderr = SelectiveChecks(
files=files,
github_event=GithubEvents.PULL_REQUEST,
commit_ref=NEUTRAL_COMMIT,
default_branch="main",
)
assert_outputs_are_printed(expected_outputs, str(stderr))
@pytest.mark.parametrize(
("files", "pr_labels", "default_branch", "expected_outputs"),
[
(
pytest.param(
("providers/git/src/airflow/providers/git/test_file.py",),
(),
"main",
{
"selected-providers-list-as-string": ALL_PROVIDERS_AFFECTED,
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"all-versions": "false",
"mysql-versions": "['8.0']",
"postgres-versions": "['14']",
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"kubernetes-versions": f"['{DEFAULT_KUBERNETES_VERSION}']",
"kubernetes-versions-list-as-string": DEFAULT_KUBERNETES_VERSION,
"kubernetes-combos-list-as-string": f"{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}-{DEFAULT_KUBERNETES_VERSION}",
"ci-image-build": "true",
"prod-image-build": "true",
"run-unit-tests": "true",
"skip-providers-tests": "false",
"docs-build": "true",
"docs-list-as-string": ALL_DOCS_SELECTED_FOR_BUILD,
"full-tests-needed": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_BY_DEFAULT_ON_ALL_TESTS_NEEDED,
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": ALL_CI_SELECTIVE_TEST_TYPES_AS_JSON,
"providers-test-types-list-as-strings-in-json": ALL_PROVIDERS_SELECTIVE_TEST_TYPES_AS_JSON,
"run-mypy-providers": "true",
},
id="Everything should run including all providers when git provider is changed"
"(special case for now)",
)
),
(
pytest.param(
("INTHEWILD.md",),
("full tests needed", "all versions"),
"main",
{
"selected-providers-list-as-string": ALL_PROVIDERS_AFFECTED,
"all-versions": "true",
"all-python-versions": ALL_PYTHON_VERSIONS_AS_LIST,
"all-python-versions-list-as-string": ALL_PYTHON_VERSIONS_AS_STRING,
"mysql-versions": "['8.0', '8.4']",
"postgres-versions": "['14', '15', '16', '17', '18']",
"python-versions": ALL_PYTHON_VERSIONS_AS_LIST,
"python-versions-list-as-string": ALL_PYTHON_VERSIONS_AS_STRING,
"kubernetes-versions": ALL_KUBERNETES_VERSIONS_AS_LIST,
"kubernetes-versions-list-as-string": ALL_KUBERNETES_VERSIONS_AS_STRING,
"kubernetes-combos-list-as-string": ZIP_PYTHON_AND_KUBERNETES_VERSIONS_AS_STRING,
"ci-image-build": "true",
"prod-image-build": "true",
"run-unit-tests": "true",
"skip-providers-tests": "false",
"docs-build": "true",
"docs-list-as-string": ALL_DOCS_SELECTED_FOR_BUILD,
"full-tests-needed": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_BY_DEFAULT_ON_ALL_TESTS_NEEDED,
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": ALL_CI_SELECTIVE_TEST_TYPES_AS_JSON,
"providers-test-types-list-as-strings-in-json": ALL_PROVIDERS_SELECTIVE_TEST_TYPES_AS_JSON,
"run-mypy-providers": "true",
},
id="Everything should run including all providers when full tests are needed, "
"and all versions are required.",
)
),
(
pytest.param(
("INTHEWILD.md",),
("full tests needed", "default versions only"),
"main",
{
"selected-providers-list-as-string": ALL_PROVIDERS_AFFECTED,
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"all-versions": "false",
"mysql-versions": "['8.0']",
"postgres-versions": "['14']",
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"kubernetes-versions": f"['{DEFAULT_KUBERNETES_VERSION}']",
"kubernetes-versions-list-as-string": DEFAULT_KUBERNETES_VERSION,
"kubernetes-combos-list-as-string": f"{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}-{DEFAULT_KUBERNETES_VERSION}",
"ci-image-build": "true",
"prod-image-build": "true",
"run-unit-tests": "true",
"skip-providers-tests": "false",
"docs-build": "true",
"docs-list-as-string": ALL_DOCS_SELECTED_FOR_BUILD,
"full-tests-needed": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_BY_DEFAULT_ON_ALL_TESTS_NEEDED,
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": ALL_CI_SELECTIVE_TEST_TYPES_AS_JSON,
"providers-test-types-list-as-strings-in-json": ALL_PROVIDERS_SELECTIVE_TEST_TYPES_AS_JSON,
"run-mypy-providers": "true",
},
id="Everything should run including all providers when full tests are needed "
"but with single python and kubernetes if `default versions only` label is set",
)
),
(
pytest.param(
("INTHEWILD.md",),
("full tests needed",),
"main",
{
"selected-providers-list-as-string": ALL_PROVIDERS_AFFECTED,
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"all-versions": "false",
"mysql-versions": "['8.0']",
"postgres-versions": "['14']",
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"kubernetes-versions": f"['{DEFAULT_KUBERNETES_VERSION}']",
"kubernetes-versions-list-as-string": DEFAULT_KUBERNETES_VERSION,
"kubernetes-combos-list-as-string": f"{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}-{DEFAULT_KUBERNETES_VERSION}",
"ci-image-build": "true",
"prod-image-build": "true",
"run-unit-tests": "true",
"skip-providers-tests": "false",
"docs-build": "true",
"docs-list-as-string": ALL_DOCS_SELECTED_FOR_BUILD,
"full-tests-needed": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_BY_DEFAULT_ON_ALL_TESTS_NEEDED,
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": ALL_CI_SELECTIVE_TEST_TYPES_AS_JSON,
"providers-test-types-list-as-strings-in-json": ALL_PROVIDERS_SELECTIVE_TEST_TYPES_AS_JSON,
"run-mypy-providers": "true",
"run-ui-e2e-tests": "true",
"run-openlineage-e2e-compat-tests": "true",
},
id="Everything should run including all providers when full tests are needed "
"but with single python and kubernetes if no version label is set",
)
),
(
pytest.param(
("INTHEWILD.md",),
("full tests needed", "latest versions only"),
"main",
{
"selected-providers-list-as-string": ALL_PROVIDERS_AFFECTED,
"all-python-versions": f"['{ALLOWED_PYTHON_MAJOR_MINOR_VERSIONS[-1]}']",
"all-python-versions-list-as-string": f"{ALLOWED_PYTHON_MAJOR_MINOR_VERSIONS[-1]}",
"all-versions": "false",
"default-python-version": f"{ALLOWED_PYTHON_MAJOR_MINOR_VERSIONS[-1]}",
"mysql-versions": "['8.4']",
"postgres-versions": "['18']",
"python-versions": f"['{ALLOWED_PYTHON_MAJOR_MINOR_VERSIONS[-1]}']",
"python-versions-list-as-string": f"{ALLOWED_PYTHON_MAJOR_MINOR_VERSIONS[-1]}",
"kubernetes-versions": f"['{ALLOWED_KUBERNETES_VERSIONS[-1]}']",
"kubernetes-versions-list-as-string": f"{ALLOWED_KUBERNETES_VERSIONS[-1]}",
"kubernetes-combos-list-as-string": f"{ALLOWED_PYTHON_MAJOR_MINOR_VERSIONS[-1]}-{ALLOWED_KUBERNETES_VERSIONS[-1]}",
"ci-image-build": "true",
"prod-image-build": "true",
"run-unit-tests": "true",
"skip-providers-tests": "false",
"docs-build": "true",
"docs-list-as-string": ALL_DOCS_SELECTED_FOR_BUILD,
"full-tests-needed": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_BY_DEFAULT_ON_ALL_TESTS_NEEDED,
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": ALL_CI_SELECTIVE_TEST_TYPES_AS_JSON,
"providers-test-types-list-as-strings-in-json": ALL_PROVIDERS_SELECTIVE_TEST_TYPES_AS_JSON,
"run-mypy-providers": "true",
},
id="Everything should run including all providers when full tests are needed "
"but with single python and kubernetes if `latest versions only` label is set",
)
),
(
pytest.param(
("INTHEWILD.md",),
(
"another label",
"full tests needed",
),
"main",
{
"selected-providers-list-as-string": ALL_PROVIDERS_AFFECTED,
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"all-versions": "false",
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"kubernetes-versions": f"['{DEFAULT_KUBERNETES_VERSION}']",
"kubernetes-versions-list-as-string": DEFAULT_KUBERNETES_VERSION,
"kubernetes-combos-list-as-string": f"{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}-{DEFAULT_KUBERNETES_VERSION}",
"ci-image-build": "true",
"prod-image-build": "true",
"run-unit-tests": "true",
"skip-providers-tests": "false",
"docs-build": "true",
"docs-list-as-string": ALL_DOCS_SELECTED_FOR_BUILD,
"full-tests-needed": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_BY_DEFAULT_ON_ALL_TESTS_NEEDED,
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": ALL_CI_SELECTIVE_TEST_TYPES_AS_JSON,
"providers-test-types-list-as-strings-in-json": ALL_PROVIDERS_SELECTIVE_TEST_TYPES_AS_JSON,
"run-mypy-providers": "true",
},
id="Everything should run including full providers when full "
"tests are needed even with different label set as well",
)
),
(
pytest.param(
(),
("full tests needed",),
"main",
{
"selected-providers-list-as-string": ALL_PROVIDERS_AFFECTED,
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"all-versions": "false",
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"kubernetes-versions": f"['{DEFAULT_KUBERNETES_VERSION}']",
"kubernetes-versions-list-as-string": DEFAULT_KUBERNETES_VERSION,
"kubernetes-combos-list-as-string": f"{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}-{DEFAULT_KUBERNETES_VERSION}",
"ci-image-build": "true",
"prod-image-build": "true",
"run-unit-tests": "true",
"skip-providers-tests": "false",
"docs-build": "true",
"docs-list-as-string": ALL_DOCS_SELECTED_FOR_BUILD,
"full-tests-needed": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_BY_DEFAULT_ON_ALL_TESTS_NEEDED,
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": ALL_CI_SELECTIVE_TEST_TYPES_AS_JSON,
"providers-test-types-list-as-strings-in-json": ALL_PROVIDERS_SELECTIVE_TEST_TYPES_AS_JSON,
"individual-providers-test-types-list-as-strings-in-json": LIST_OF_ALL_PROVIDER_TESTS_AS_JSON,
"run-mypy-providers": "true",
},
id="Everything should run including full providers when "
"full tests are needed even if no files are changed",
)
),
(
pytest.param(
("INTHEWILD.md", "providers/asana/tests/asana.py"),
("full tests needed",),
"v2-7-stable",
{
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"all-versions": "false",
"ci-image-build": "true",
"prod-image-build": "true",
"run-unit-tests": "true",
"skip-providers-tests": "true",
"docs-build": "true",
"docs-list-as-string": "apache-airflow docker-stack",
"full-tests-needed": "true",
"skip-prek-hooks": All_SKIPPED_COMMITS_IF_NON_MAIN_BRANCH,
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": ALL_CI_SELECTIVE_TEST_TYPES_AS_JSON,
"run-mypy-providers": "false",
},
id="Everything should run except Providers and lint prek "
"when full tests are needed for non-main branch",
)
),
],
)
def test_expected_output_full_tests_needed(
files: tuple[str, ...],
pr_labels: tuple[str, ...],
default_branch: str,
expected_outputs: dict[str, str],
):
stderr = SelectiveChecks(
files=files,
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.PULL_REQUEST,
pr_labels=pr_labels,
default_branch=default_branch,
)
assert_outputs_are_printed(expected_outputs, str(stderr))
@pytest.mark.parametrize(
("files", "expected_outputs"),
[
pytest.param(
("INTHEWILD.md",),
{
"selected-providers-list-as-string": None,
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "false",
"run-helm-tests": "false",
"run-unit-tests": "false",
"skip-providers-tests": "true",
"docs-build": "false",
"docs-list-as-string": None,
"full-tests-needed": "false",
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": None,
"run-mypy-providers": "false",
},
id="Nothing should run if only non-important files changed",
),
pytest.param(
(
"chart/aaaa.txt",
"providers/google/tests/unit/google/file.py",
),
{
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"run-helm-tests": "false",
"ci-image-build": "true",
"prod-image-build": "true",
"run-unit-tests": "true",
"skip-providers-tests": "true",
"docs-build": "true",
"docs-list-as-string": "apache-airflow docker-stack",
"full-tests-needed": "false",
"run-kubernetes-tests": "true",
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": json.dumps(
[{"description": "Always", "test_types": "Always"}]
),
"run-mypy-providers": "false",
},
id="No Helm tests, No providers no lint charts, should run if "
"only chart/providers changed in non-main but PROD image should be built",
),
pytest.param(
(
"airflow-core/src/airflow/cli/test.py",
"chart/aaaa.txt",
"providers/google/tests/unit/google/file.py",
),
{
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "true",
"run-helm-tests": "false",
"run-unit-tests": "true",
"skip-providers-tests": "true",
"docs-build": "true",
"docs-list-as-string": "apache-airflow docker-stack",
"full-tests-needed": "false",
"run-kubernetes-tests": "true",
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": json.dumps(
[{"description": "Always...CLI", "test_types": "Always CLI"}]
),
"run-mypy-providers": "false",
},
id="Only CLI tests and Kubernetes tests should run if cli/chart files changed in non-main branch",
),
pytest.param(
(
"airflow-core/src/airflow/file.py",
"providers/google/tests/unit/google/file.py",
),
{
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "false",
"run-helm-tests": "false",
"run-unit-tests": "true",
"skip-providers-tests": "true",
"docs-build": "true",
"docs-list-as-string": "apache-airflow docker-stack",
"full-tests-needed": "false",
"run-kubernetes-tests": "false",
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": ALL_CI_SELECTIVE_TEST_TYPES_AS_JSON,
"run-mypy-providers": "false",
},
id="All tests except Providers and helm lint prek "
"should run if core file changed in non-main branch",
),
],
)
def test_expected_output_pull_request_v2_7(
files: tuple[str, ...],
expected_outputs: dict[str, str],
):
stderr = SelectiveChecks(
files=files,
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.PULL_REQUEST,
pr_labels=(),
default_branch="v2-7-stable",
)
assert_outputs_are_printed(expected_outputs, str(stderr))
@pytest.mark.parametrize(
("files", "pr_labels", "default_branch", "expected_outputs"),
[
pytest.param(
("INTHEWILD.md",),
(),
"main",
{
"selected-providers-list-as-string": None,
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "false",
"prod-image-build": "false",
"run-helm-tests": "false",
"run-unit-tests": "false",
"skip-providers-tests": "true",
"docs-build": "false",
"docs-list-as-string": None,
"upgrade-to-newer-dependencies": "false",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_IF_NOT_IMPORTANT_FILES_CHANGED,
"core-test-types-list-as-strings-in-json": None,
"run-mypy-providers": "false",
},
id="No tests run on push if only text non-doc files changed",
),
pytest.param(
("INTHEWILD.md",),
(),
"v2-3-stable",
{
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "false",
"prod-image-build": "false",
"run-helm-tests": "false",
"run-unit-tests": "false",
"skip-providers-tests": "true",
"docs-build": "false",
"docs-list-as-string": None,
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": None,
"run-mypy-providers": "false",
},
id="No tests run on push if only text non-doc files changed in non-main branch",
),
pytest.param(
("airflow-core/src/airflow/api.py",),
(),
"main",
{
"selected-providers-list-as-string": ALL_PROVIDERS_AFFECTED,
"all-python-versions": ALL_PYTHON_VERSIONS_AS_LIST,
"all-python-versions-list-as-string": ALL_PYTHON_VERSIONS_AS_STRING,
"ci-image-build": "true",
"prod-image-build": "true",
"run-helm-tests": "true",
"run-unit-tests": "true",
"docs-build": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_BY_DEFAULT_ON_ALL_TESTS_NEEDED,
"docs-list-as-string": ALL_DOCS_SELECTED_FOR_BUILD,
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": ALL_CI_SELECTIVE_TEST_TYPES_AS_JSON,
"run-mypy-providers": "true",
"run-ui-e2e-tests": "false",
},
id="All tests run on push if core file changed",
),
],
)
def test_expected_output_push(
files: tuple[str, ...],
pr_labels: tuple[str, ...],
default_branch: str,
expected_outputs: dict[str, str],
):
stderr = SelectiveChecks(
files=files,
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.PUSH,
pr_labels=pr_labels,
default_branch=default_branch,
)
assert_outputs_are_printed(expected_outputs, str(stderr))
@pytest.mark.parametrize(
("files", "expected_outputs"),
[
pytest.param(
("INTHEWILD.md",),
{
"selected-providers-list-as-string": None,
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "false",
"run-helm-tests": "false",
"run-unit-tests": "false",
"skip-providers-tests": "true",
"docs-build": "false",
"docs-list-as-string": None,
"upgrade-to-newer-dependencies": "false",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_IF_NOT_IMPORTANT_FILES_CHANGED,
"core-test-types-list-as-strings-in-json": None,
"run-mypy-providers": "false",
},
id="Nothing should run if only non-important files changed",
),
pytest.param(
("airflow-core/tests/system/any_file.py",),
{
"selected-providers-list-as-string": None,
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "false",
"run-helm-tests": "false",
"run-unit-tests": "true",
"skip-providers-tests": "true",
"docs-build": "true",
"docs-list-as-string": ALL_DOCS_SELECTED_FOR_BUILD,
"skip-prek-hooks": (
"check-provider-yaml-valid,check-ts-sdk-supervisor-schema,identity,ktlint,lint-helm-chart,"
"mypy-airflow-ctl,mypy-airflow-ctl-tests,mypy-airflow-e2e-tests,"
"mypy-dev,mypy-devel-common,mypy-docker-tests,mypy-helm-tests,mypy-kubernetes-tests,"
"mypy-scripts,"
"mypy-shared-configuration,mypy-shared-dagnode,mypy-shared-listeners,mypy-shared-logging,"
"mypy-shared-module_loading,mypy-shared-observability,mypy-shared-plugins_manager,"
"mypy-shared-providers_discovery,mypy-shared-secrets_backend,mypy-shared-secrets_masker,"
"mypy-shared-serialization,mypy-shared-state,mypy-shared-template_rendering,mypy-shared-timezones,mypy-task-sdk,mypy-task-sdk-integration-tests,"
"ts-compile-lint-simple-auth-manager-ui,ts-compile-lint-ui,update-uv-lock"
),
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": json.dumps(
[{"description": "Always", "test_types": "Always"}]
),
"run-mypy-providers": "false",
},
id="Only Always and docs build should run if only system tests changed",
),
pytest.param(
(
"airflow-core/src/airflow/cli/test.py",
"chart/aaaa.txt",
"providers/google/tests/unit/google/file.py",
),
{
"selected-providers-list-as-string": "amazon apache.cassandra apache.kafka "
"cncf.kubernetes common.compat common.messaging common.sql databricks "
"facebook google hashicorp http microsoft.azure microsoft.mssql mongo mysql "
"openlineage oracle postgres presto salesforce samba sftp ssh standard trino",
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "true",
"run-helm-tests": "true",
"run-unit-tests": "true",
"skip-providers-tests": "false",
"docs-build": "true",
"docs-list-as-string": "apache-airflow helm-chart amazon apache.cassandra "
"apache.kafka cncf.kubernetes common.compat common.messaging common.sql databricks facebook google hashicorp http microsoft.azure "
"microsoft.mssql mongo mysql openlineage oracle postgres "
"presto salesforce samba sftp ssh standard trino",
"skip-prek-hooks": (
"check-ts-sdk-supervisor-schema,identity,ktlint,mypy-airflow-ctl,mypy-airflow-ctl-tests,mypy-airflow-e2e-tests,"
"mypy-dev,mypy-devel-common,mypy-docker-tests,mypy-helm-tests,mypy-kubernetes-tests,"
"mypy-scripts,"
"mypy-shared-configuration,mypy-shared-dagnode,mypy-shared-listeners,mypy-shared-logging,"
"mypy-shared-module_loading,mypy-shared-observability,mypy-shared-plugins_manager,"
"mypy-shared-providers_discovery,mypy-shared-secrets_backend,mypy-shared-secrets_masker,"
"mypy-shared-serialization,mypy-shared-state,mypy-shared-template_rendering,mypy-shared-timezones,mypy-task-sdk,mypy-task-sdk-integration-tests,"
"ts-compile-lint-simple-auth-manager-ui,ts-compile-lint-ui,update-uv-lock"
),
"run-kubernetes-tests": "true",
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": json.dumps(
[{"description": "Always...CLI", "test_types": "Always CLI"}]
),
"providers-test-types-list-as-strings-in-json": json.dumps(
[
{
"description": "amazon...standard",
"test_types": "Providers[amazon] Providers[apache.cassandra,"
"apache.kafka,cncf.kubernetes,common.compat,common.messaging,common.sql,databricks,facebook,"
"hashicorp,http,microsoft.azure,microsoft.mssql,mongo,mysql,"
"openlineage,oracle,postgres,presto,salesforce,samba,sftp,ssh,trino] "
"Providers[google] "
"Providers[standard]",
}
]
),
"run-mypy-providers": "true",
},
id="CLI tests and Google-related provider tests should run if cli/chart files changed but "
"prod image should be build too and k8s tests too",
),
pytest.param(
("airflow-core/src/airflow/models/test.py",),
{
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "false",
"run-helm-tests": "false",
"run-unit-tests": "true",
"skip-providers-tests": "true",
"docs-build": "true",
"docs-list-as-string": "apache-airflow",
"skip-prek-hooks": (
"check-provider-yaml-valid,check-ts-sdk-supervisor-schema,identity,ktlint,lint-helm-chart,"
"mypy-airflow-ctl,mypy-airflow-ctl-tests,mypy-airflow-e2e-tests,"
"mypy-dev,mypy-devel-common,mypy-docker-tests,mypy-helm-tests,mypy-kubernetes-tests,"
"mypy-scripts,"
"mypy-shared-configuration,mypy-shared-dagnode,mypy-shared-listeners,mypy-shared-logging,"
"mypy-shared-module_loading,mypy-shared-observability,mypy-shared-plugins_manager,"
"mypy-shared-providers_discovery,mypy-shared-secrets_backend,mypy-shared-secrets_masker,"
"mypy-shared-serialization,mypy-shared-state,mypy-shared-template_rendering,mypy-shared-timezones,mypy-task-sdk,mypy-task-sdk-integration-tests,"
"ts-compile-lint-simple-auth-manager-ui,ts-compile-lint-ui,update-uv-lock"
),
"run-kubernetes-tests": "false",
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": ALL_CI_SELECTIVE_TEST_TYPES_AS_JSON,
"run-mypy-providers": "false",
},
id="Tests for all airflow core types except providers should run if model file changed",
),
pytest.param(
("airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml",),
{
# The OpenAPI spec IS the API contract — changing it ripples to the UI
# codegen and generated clients, so it still forces the full matrix.
"full-tests-needed": "true",
"selected-providers-list-as-string": "",
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"run-helm-tests": "true",
"run-unit-tests": "true",
"skip-providers-tests": "false",
"docs-build": "true",
"docs-list-as-string": "",
"upgrade-to-newer-dependencies": "false",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_BY_DEFAULT_ON_ALL_TESTS_NEEDED,
"core-test-types-list-as-strings-in-json": ALL_CI_SELECTIVE_TEST_TYPES_AS_JSON,
"run-mypy-providers": "true",
},
id="OpenAPI spec change still forces the full matrix",
),
pytest.param(
("airflow-core/src/airflow/api_fastapi/core_api/openapi/_private_ui.yaml",),
{
# Rationale on the UI_OPENAPI_FILES group in selective_checks.py. One param per
# spec directory so each pattern of the group is pinned individually - with both
# files in one param, dropping either pattern would still pass via the other file.
"full-tests-needed": "false",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_IF_ONLY_UI_OPENAPI_CHANGED,
},
id="Private UI OpenAPI spec change runs the UI compile hooks without the full matrix",
),
pytest.param(
(
"airflow-core/src/airflow/api_fastapi/auth/managers/simple/openapi/v2-simple-auth-manager-generated.yaml",
),
{
"full-tests-needed": "false",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_IF_ONLY_UI_OPENAPI_CHANGED,
},
id="Simple auth manager OpenAPI spec change runs the UI compile hooks",
),
pytest.param(
(
"airflow-core/src/airflow/assets/",
"airflow-core/src/airflow/models/assets/",
"task-sdk/src/airflow/sdk/definitions/asset/",
"airflow-core/src/airflow/datasets/",
),
{
"selected-providers-list-as-string": "amazon common.compat common.io common.sql "
"databricks dbt.cloud ftp google jdbc microsoft.azure microsoft.mssql mysql "
"openlineage oracle postgres sftp snowflake standard trino",
"all-python-versions": f"['{DEFAULT_PYTHON_MAJOR_MINOR_VERSION}']",
"all-python-versions-list-as-string": DEFAULT_PYTHON_MAJOR_MINOR_VERSION,
"ci-image-build": "true",
"prod-image-build": "false",
"run-helm-tests": "false",
"run-unit-tests": "true",
"skip-providers-tests": "false",
"docs-build": "false",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_ON_NO_CI_IMAGE,
"run-kubernetes-tests": "false",
"upgrade-to-newer-dependencies": "false",
"core-test-types-list-as-strings-in-json": ALL_CI_SELECTIVE_TEST_TYPES_AS_JSON,
"providers-test-types-list-as-strings-in-json": json.dumps(
[
{
"description": "amazon...standard",
"test_types": "Providers[amazon] Providers[common.compat,common.io,common.sql,"
"databricks,dbt.cloud,ftp,jdbc,microsoft.azure,microsoft.mssql,mysql,openlineage,oracle,"
"postgres,sftp,snowflake,trino] Providers[google] Providers[standard]",
}
]
),
"run-mypy-providers": "false",
},
id="Trigger openlineage and related providers tests when Assets files changed",
),
],
)
def test_expected_output_pull_request_target(
files: tuple[str, ...],
expected_outputs: dict[str, str],
):
stderr = SelectiveChecks(
files=files,
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.PULL_REQUEST_TARGET,
pr_labels=(),
default_branch="main",
)
assert_outputs_are_printed(expected_outputs, str(stderr))
@pytest.mark.parametrize(
"github_event",
[
GithubEvents.PUSH,
GithubEvents.PULL_REQUEST,
GithubEvents.PULL_REQUEST_TARGET,
GithubEvents.PULL_REQUEST_WORKFLOW,
GithubEvents.SCHEDULE,
],
)
def test_no_commit_provided_trigger_full_build_for_any_event_type(github_event):
stderr = SelectiveChecks(
files=(),
commit_ref="",
github_event=github_event,
pr_labels=(),
default_branch="main",
)
assert_outputs_are_printed(
{
"all-python-versions": ALL_PYTHON_VERSIONS_AS_LIST,
"all-python-versions-list-as-string": ALL_PYTHON_VERSIONS_AS_STRING,
"ci-image-build": "true",
"prod-image-build": "true",
"run-helm-tests": "true",
"run-unit-tests": "true",
"docs-build": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_BY_DEFAULT_ON_ALL_TESTS_NEEDED,
"upgrade-to-newer-dependencies": ("true" if github_event == GithubEvents.SCHEDULE else "false"),
"core-test-types-list-as-strings-in-json": ALL_CI_SELECTIVE_TEST_TYPES_AS_JSON,
"run-mypy-providers": "true",
},
str(stderr),
)
# The image cache is pushed for `python-versions`, so a narrowed list leaves the remaining
# versions with no cache and they build from scratch on every run. `refresh-image-registry-cache.yml`
# forces the label below for exactly that reason; this pins the behaviour it relies on.
def test_all_python_versions_with_all_versions_label():
"""Set on the event that would otherwise narrow: a text-only push."""
stderr = SelectiveChecks(
files=("INTHEWILD.md",),
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.PUSH,
pr_labels=("all versions",),
default_branch="main",
)
assert_outputs_are_printed({"python-versions": CURRENT_PYTHON_VERSIONS_AS_LIST}, str(stderr))
@pytest.mark.parametrize(
"github_event",
[
GithubEvents.PUSH,
GithubEvents.SCHEDULE,
],
)
def test_files_provided_trigger_full_build_for_any_event_type(github_event):
stderr = SelectiveChecks(
files=(
"airflow-core/src/airflow/ui/src/pages/Run/Details.tsx",
"airflow-core/src/airflow/ui/src/router.tsx",
),
commit_ref="",
github_event=github_event,
pr_labels=(),
default_branch="main",
)
assert_outputs_are_printed(
{
"all-python-versions": ALL_PYTHON_VERSIONS_AS_LIST,
"all-python-versions-list-as-string": ALL_PYTHON_VERSIONS_AS_STRING,
"ci-image-build": "true",
"prod-image-build": "true",
"run-helm-tests": "true",
"run-unit-tests": "true",
"docs-build": "true",
"skip-prek-hooks": ALL_SKIPPED_COMMITS_BY_DEFAULT_ON_ALL_TESTS_NEEDED,
"upgrade-to-newer-dependencies": ("true" if github_event == GithubEvents.SCHEDULE else "false"),
"core-test-types-list-as-strings-in-json": ALL_CI_SELECTIVE_TEST_TYPES_AS_JSON,
"run-mypy-providers": "true",
},
str(stderr),
)
@pytest.mark.parametrize(
("files", "expected_outputs", "pr_labels", "commit_ref"),
[
pytest.param(
("airflow-core/src/airflow/models/dag.py",),
{
"upgrade-to-newer-dependencies": "false",
},
(),
None,
id="Regular source changed",
),
pytest.param(
("providers/microsoft/azure/src/airflow/providers/microsoft/azure/provider.yaml",),
{
"upgrade-to-newer-dependencies": "false",
},
(),
None,
id="Provider.yaml changed",
),
pytest.param(
("airflow-core/src/airflow/models/dag.py",),
{
"upgrade-to-newer-dependencies": "true",
},
("upgrade to newer dependencies",),
None,
id="Regular source changed",
),
],
)
def test_upgrade_to_newer_dependencies(
files: tuple[str, ...],
expected_outputs: dict[str, str],
pr_labels: tuple[str, ...],
commit_ref: str | None,
):
stderr = SelectiveChecks(
files=files,
commit_ref=commit_ref,
github_event=GithubEvents.PULL_REQUEST,
default_branch="main",
pr_labels=pr_labels,
)
assert_outputs_are_printed(expected_outputs, str(stderr))
@pytest.mark.parametrize(
("files", "expected_outputs"),
[
pytest.param(
("providers/google/docs/some_file.rst",),
{
"docs-list-as-string": "amazon apache.cassandra apache.kafka "
"cncf.kubernetes common.compat common.messaging common.sql databricks facebook google hashicorp http "
"microsoft.azure microsoft.mssql mongo mysql openlineage oracle "
"postgres presto salesforce samba sftp ssh standard trino",
},
id="Google provider docs changed",
),
pytest.param(
("providers/common/sql/src/airflow/providers/common/sql/common_sql_python.py",),
{
"docs-list-as-string": "amazon apache.drill apache.druid apache.hive apache.iceberg "
"apache.impala apache.pinot clickhousedb common.ai common.compat common.sql databricks elasticsearch "
"exasol google informatica jdbc microsoft.mssql mysql odbc openlineage "
"oracle pgvector postgres presto slack snowflake sqlite teradata trino vertica ydb",
},
id="Common SQL provider package python files changed",
),
pytest.param(
("providers/airbyte/docs/some_file.rst",),
{
"docs-list-as-string": "airbyte common.compat",
},
id="Airbyte provider docs changed",
),
pytest.param(
("providers/airbyte/docs/some_file.rst", "airflow-core/docs/docs.rst"),
{
"docs-list-as-string": "apache-airflow airbyte common.compat",
},
id="Airbyte provider and airflow core docs changed",
),
pytest.param(
(
"providers/airbyte/docs/some_file.rst",
"airflow-core/docs/docs.rst",
"providers-summary-docs/docs.rst",
),
{
"docs-list-as-string": "apache-airflow apache-airflow-providers airbyte common.compat",
},
id="Airbyte provider and airflow core and common provider docs changed",
),
pytest.param(
("airflow-core/docs/docs.rst",),
{
"docs-list-as-string": "apache-airflow",
},
id="Only Airflow docs changed",
),
pytest.param(
("providers/celery/src/airflow/providers/celery/file.py",),
{"docs-list-as-string": "celery cncf.kubernetes common.compat"},
id="Celery python files changed",
),
pytest.param(
("docs/conf.py",),
{
"docs-list-as-string": ALL_DOCS_SELECTED_FOR_BUILD,
},
id="Docs conf.py changed",
),
pytest.param(
("airflow-core/src/airflow/test.py",),
{
"docs-list-as-string": "apache-airflow",
},
id="Core files changed. Apache-Airflow docs should also be built",
),
pytest.param(
("docker-stack-docs/test.rst",),
{"docs-list-as-string": "docker-stack"},
id="Docker stack files changed. No provider docs to build",
),
pytest.param(
("airflow-core/src/airflow/test.py", "chart/airflow/values.yaml"),
{
"docs-list-as-string": "apache-airflow helm-chart",
},
id="Core files and helm chart files changed. Apache Airflow and helm chart docs to build",
),
pytest.param(
("chart/airflow/values.yaml",),
{
"docs-list-as-string": "helm-chart",
},
id="Helm chart files changed. No provider, airflow docs to build",
),
pytest.param(
("chart/docs/airflow/values.yaml",),
{
"docs-list-as-string": "helm-chart",
},
id="Docs helm chart files changed. No provider, airflow docs to build",
),
],
)
def test_docs_filter(files: tuple[str, ...], expected_outputs: dict[str, str]):
stderr = SelectiveChecks(
files=files,
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.PULL_REQUEST,
pr_labels=(),
default_branch="main",
)
assert_outputs_are_printed(expected_outputs, str(stderr))
@pytest.mark.parametrize(
("files", "expected_outputs"),
[
pytest.param(
("chart/tests/helm_tests/random_helm_test.py",),
{
"ci-image-build": "true",
"prod-image-build": "true",
"run-helm-tests": "true",
},
id="Only helm test files changed",
)
],
)
def test_helm_tests_trigger_ci_build(files: tuple[str, ...], expected_outputs: dict[str, str]):
stderr = SelectiveChecks(
files=files,
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.PULL_REQUEST,
pr_labels=(),
default_branch="main",
)
assert_outputs_are_printed(expected_outputs, str(stderr))
@pytest.mark.parametrize(
("files", "expected_outputs"),
[
pytest.param(
("providers/amazon/provider.yaml",),
{
"ci-image-build": "true",
"prod-image-build": "false",
"run-helm-tests": "false",
},
id="Amazon provider.yaml",
),
pytest.param(
("providers/amazon/pyproject.toml",),
{
"ci-image-build": "true",
"prod-image-build": "false",
"run-helm-tests": "false",
},
id="Amazon pyproject.toml",
),
pytest.param(
("providers/cncf/kubernetes/provider.yaml",),
{
"ci-image-build": "true",
"prod-image-build": "true",
"run-helm-tests": "false",
},
id="CNCF Kubernetes provider.yaml",
),
pytest.param(
("providers/cncf/kubernetes/pyproject.toml",),
{
"ci-image-build": "true",
"prod-image-build": "true",
"run-helm-tests": "false",
},
id="CNCF Kubernetes pyproject.toml",
),
],
)
def test_provider_yaml_or_pyproject_toml_changes_trigger_ci_build(
files: tuple[str, ...], expected_outputs: dict[str, str]
):
stderr = SelectiveChecks(
files=files,
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.PULL_REQUEST,
pr_labels=(),
default_branch="main",
)
assert_outputs_are_printed(expected_outputs, str(stderr))
@pytest.mark.parametrize(
("files", "has_migrations"),
[
pytest.param(
("airflow-core/src/airflow/test.py",),
False,
id="No migrations",
),
pytest.param(
("airflow-core/src/airflow/migrations/test_sql", "airflow-core/src/airflow/test.py"),
True,
id="With migrations",
),
],
)
def test_has_migrations(files: tuple[str, ...], has_migrations: bool):
stderr = str(
SelectiveChecks(
files=files,
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.PULL_REQUEST,
default_branch="main",
)
)
assert_outputs_are_printed({"has-migrations": str(has_migrations).lower()}, str(stderr))
@pytest.mark.parametrize(
("labels", "expected_outputs"),
[
pytest.param(
(),
{
"providers-compatibility-tests-matrix": json.dumps(
[
check
for check in PROVIDERS_COMPATIBILITY_TESTS_MATRIX
if check["python-version"] == DEFAULT_PYTHON_MAJOR_MINOR_VERSION
]
),
},
id="Regular tests",
),
pytest.param(
("all versions",),
{"providers-compatibility-tests-matrix": json.dumps(PROVIDERS_COMPATIBILITY_TESTS_MATRIX)},
id="full tests",
),
],
)
def test_provider_compatibility_checks(labels: tuple[str, ...], expected_outputs: dict[str, str]):
stderr = SelectiveChecks(
files=(),
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.PULL_REQUEST,
pr_labels=labels,
default_branch="main",
)
assert_outputs_are_printed(expected_outputs, str(stderr))
@pytest.mark.parametrize(
("files", "expected_outputs", "default_branch", "pr_labels"),
[
pytest.param(
("README.md",),
{
"run-mypy-providers": "false",
},
"main",
(),
id="No mypy checks on non-python files",
),
pytest.param(
("airflow-core/src/airflow/cli/file.py",),
{
"run-mypy-providers": "false",
},
"main",
(),
id="Airflow mypy checks on airflow regular files",
),
pytest.param(
("airflow-core/src/airflow/models/file.py",),
{
"run-mypy-providers": "false",
},
"main",
(),
id="Airflow mypy checks on airflow files with model changes.",
),
pytest.param(
("task-sdk/src/airflow/sdk/a_file.py",),
{
"run-mypy-providers": "true",
},
"main",
(),
id="Airflow mypy checks on Task SDK files (implies providers)",
),
pytest.param(
("dev/a_package/a_file.py",),
{
"run-mypy-providers": "true",
},
"main",
(),
id="All mypy checks on def files changed (full tests needed are implicit)",
),
pytest.param(
("readme.md",),
{
"run-mypy-providers": "true",
},
"main",
("full tests needed",),
id="All mypy checks on full tests needed",
),
],
)
def test_mypy_matches(
files: tuple[str, ...], expected_outputs: dict[str, str], default_branch: str, pr_labels: tuple[str, ...]
):
stderr = SelectiveChecks(
files=files,
commit_ref=NEUTRAL_COMMIT,
default_branch=default_branch,
github_event=GithubEvents.PULL_REQUEST,
pr_labels=pr_labels,
)
assert_outputs_are_printed(expected_outputs, str(stderr))
@pytest.mark.parametrize(
("integration", "platform", "expected_result"),
[
# Test integrations disabled for all CI environments
pytest.param(
"mssql",
CI_AMD_PLATFORM,
True,
id="mssql_disabled_on_amd",
),
pytest.param(
"localstack",
CI_ARM_PLATFORM,
True,
id="localstack_disabled_on_arm",
),
# Test integrations disabled only for ARM runners
pytest.param(
"kerberos",
CI_ARM_PLATFORM,
True,
id="kerberos_disabled_on_arm",
),
pytest.param(
"drill",
CI_ARM_PLATFORM,
True,
id="drill_disabled_on_arm",
),
pytest.param(
"tinkerpop",
CI_ARM_PLATFORM,
True,
id="tinkerpop_disabled_on_arm",
),
pytest.param(
"pinot",
CI_ARM_PLATFORM,
True,
id="pinot_disabled_on_arm",
),
pytest.param(
"trino",
CI_ARM_PLATFORM,
True,
id="trino_disabled_on_arm",
),
pytest.param(
"ydb",
CI_ARM_PLATFORM,
True,
id="ydb_disabled_on_arm",
),
# Test integrations that are NOT disabled on AMD runners
pytest.param(
"kerberos",
CI_AMD_PLATFORM,
False,
id="kerberos_enabled_on_amd",
),
pytest.param(
"drill",
CI_AMD_PLATFORM,
False,
id="drill_enabled_on_amd",
),
pytest.param(
"tinkerpop",
CI_AMD_PLATFORM,
False,
id="tinkerpop_enabled_on_amd",
),
# Test an integration that is not in any disabled list
pytest.param(
"postgres",
CI_AMD_PLATFORM,
False,
id="postgres_enabled_on_amd",
),
pytest.param(
"postgres",
CI_ARM_PLATFORM,
False,
id="postgres_enabled_on_arm",
),
pytest.param(
"redis",
CI_AMD_PLATFORM,
False,
id="redis_enabled_on_amd",
),
pytest.param(
"redis",
CI_ARM_PLATFORM,
False,
id="redis_enabled_on_arm",
),
],
)
def test_is_disabled_integration(integration: str, platform: str, expected_result: bool):
"""Test that _is_disabled_integration correctly identifies disabled integrations."""
selective_checks = SelectiveChecks(
files=(),
github_event=GithubEvents.PULL_REQUEST,
github_repository="apache/airflow",
github_context_dict={},
platform=platform,
)
assert selective_checks._is_disabled_integration(integration) == expected_result
def test_testable_core_integrations_excludes_disabled():
"""Test that testable_core_integrations excludes disabled integrations."""
with patch(
"airflow_breeze.utils.selective_checks.TESTABLE_CORE_INTEGRATIONS",
["postgres", "kerberos"],
):
# Test with AMD runner
selective_checks_amd = SelectiveChecks(
files=("airflow-core/tests/test_example.py",),
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.PULL_REQUEST,
platform=CI_AMD_PLATFORM,
)
with patch.object(
SelectiveChecks, "full_tests_needed", new_callable=lambda: property(lambda self: True)
):
result = selective_checks_amd.testable_core_integrations
assert "postgres" in result
assert "kerberos" in result
def test_testable_core_integrations_excludes_arm_disabled_on_arm():
"""Test that testable_core_integrations excludes ARM-disabled integrations on ARM runners."""
with patch(
"airflow_breeze.utils.selective_checks.TESTABLE_CORE_INTEGRATIONS", ["postgres", "kerberos", "drill"]
):
selective_checks_arm = SelectiveChecks(
files=("airflow-core/tests/test_example.py",),
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.SCHEDULE,
github_context_dict={"ref_name": "main"},
platform=CI_ARM_PLATFORM,
)
with patch.object(
SelectiveChecks, "full_tests_needed", new_callable=lambda: property(lambda self: True)
):
result = selective_checks_arm.testable_core_integrations
assert "postgres" in result
assert "kerberos" not in result
assert "drill" not in result
def test_testable_providers_integrations_excludes_disabled():
"""Test that testable_providers_integrations excludes disabled integrations."""
with patch(
"airflow_breeze.utils.selective_checks.TESTABLE_PROVIDERS_INTEGRATIONS",
["postgres", "mssql", "trino"],
):
# Test with AMD runner - should exclude mssql (disabled for all CI)
selective_checks_amd = SelectiveChecks(
files=("providers/amazon/tests/test_example.py",),
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.PULL_REQUEST,
platform=CI_AMD_PLATFORM,
)
with patch.object(
SelectiveChecks, "full_tests_needed", new_callable=lambda: property(lambda self: True)
):
result = selective_checks_amd.testable_providers_integrations
assert "postgres" in result
assert "trino" in result
assert "mssql" not in result
def test_testable_providers_integrations_excludes_arm_disabled_on_arm():
"""Test that testable_providers_integrations excludes ARM-disabled integrations on ARM runners."""
with patch(
"airflow_breeze.utils.selective_checks.TESTABLE_PROVIDERS_INTEGRATIONS", ["postgres", "trino", "ydb"]
):
selective_checks_arm = SelectiveChecks(
files=("providers/tests/test_example.py",),
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.SCHEDULE,
github_context_dict={"ref_name": "main"},
platform=CI_ARM_PLATFORM,
)
with patch.object(
SelectiveChecks, "full_tests_needed", new_callable=lambda: property(lambda self: True)
):
result = selective_checks_arm.testable_providers_integrations
assert "postgres" in result
assert "trino" not in result
assert "ydb" not in result
@pytest.mark.parametrize(
("changed_file", "expected_integration"),
[
pytest.param("airflow-core/src/airflow/security/kerberos.py", "kerberos", id="kerberos-source"),
pytest.param("airflow-core/src/airflow/observability/stats.py", "otel", id="otel-source"),
pytest.param("airflow-core/tests/integration/otel/test_otel.py", "otel", id="otel-integration-tests"),
pytest.param("task-sdk/src/airflow/sdk/execution_time/task_runner.py", "otel", id="otel-task-runner"),
pytest.param("airflow-core/src/airflow/executors/executor_loader.py", "redis", id="celery-source"),
],
)
def test_testable_core_integrations_gated_by_source(changed_file, expected_integration):
"""A core integration is only emitted when its corresponding core source group changed."""
selective_checks = SelectiveChecks(
files=(changed_file,),
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.PULL_REQUEST,
platform=CI_AMD_PLATFORM,
)
assert selective_checks.testable_core_integrations == [expected_integration]
def test_testable_core_integrations_empty_when_unrelated_source():
"""Unrelated core changes emit no core integrations (no full-tests / canary trigger)."""
selective_checks = SelectiveChecks(
files=("airflow-core/src/airflow/models/taskinstance.py",),
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.PULL_REQUEST,
platform=CI_AMD_PLATFORM,
)
assert selective_checks.testable_core_integrations == []
def test_testable_providers_integrations_gated_by_affected_provider():
"""A provider integration is only emitted when its owning provider is affected."""
selective_checks = SelectiveChecks(
files=("providers/apache/cassandra/src/airflow/providers/apache/cassandra/hooks/cassandra.py",),
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.PULL_REQUEST,
platform=CI_AMD_PLATFORM,
)
result = selective_checks.testable_providers_integrations
assert "cassandra" in result
# Unrelated integrations whose providers are not affected must be absent.
assert "mongo" not in result
assert "ydb" not in result
def test_individual_providers_excludes_platform_excluded_on_arm():
"""ibm.mq declares `excluded-platforms: [linux/arm64]`, so it must be absent from
the ARM individual-providers matrix (used by the Low-dep ARM canary job) and
present on AMD."""
arm_checks = SelectiveChecks(
files=("airflow-core/tests/test_example.py",),
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.SCHEDULE,
github_context_dict={"ref_name": "main"},
default_branch="main",
pr_labels=("full tests needed",),
platform=CI_ARM_PLATFORM,
)
arm_output = arm_checks.individual_providers_test_types_list_as_strings_in_json
assert arm_output is not None
assert "Providers[ibm.mq]" not in arm_output
amd_checks = SelectiveChecks(
files=("airflow-core/tests/test_example.py",),
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.SCHEDULE,
github_context_dict={"ref_name": "main"},
default_branch="main",
pr_labels=("full tests needed",),
platform=CI_AMD_PLATFORM,
)
amd_output = amd_checks.individual_providers_test_types_list_as_strings_in_json
assert amd_output is not None
assert "Providers[ibm.mq]" in amd_output
def test_run_kubernetes_tests_forced_by_label():
"""`area:kubernetes-tests` forces the Kubernetes tests job without pulling in
the full test matrix, unlike `full tests needed`."""
checks = SelectiveChecks(
files=("INTHEWILD.md",),
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.PULL_REQUEST,
default_branch="main",
pr_labels=("area:kubernetes-tests",),
)
assert checks.run_kubernetes_tests is True
assert checks.full_tests_needed is False
def test_run_kubernetes_tests_forced_by_label_with_no_changed_files():
"""The label still forces the Kubernetes tests job even when no files changed."""
checks = SelectiveChecks(
files=(),
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.PULL_REQUEST,
default_branch="main",
pr_labels=("area:kubernetes-tests",),
)
assert checks.run_kubernetes_tests is True
assert checks.full_tests_needed is False
@pytest.mark.parametrize("files", [("INTHEWILD.md",), ()], ids=["unrelated-file", "no-files"])
def test_prod_image_build_forced_by_e2e_tests_label(files):
checks = SelectiveChecks(
files=files,
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.PULL_REQUEST,
default_branch="main",
pr_labels=("area:e2e-tests",),
)
assert checks.prod_image_build is True
assert checks.full_tests_needed is False
def test_filter_platform_excluded_test_types_handles_all_shapes():
"""Direct unit check of the in-place filter for the three Providers[...] shapes."""
checks = SelectiveChecks(
files=(),
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.SCHEDULE,
github_context_dict={"ref_name": "main"},
default_branch="main",
)
with patch.object(
SelectiveChecks,
"_platform_excluded_providers",
new_callable=lambda: property(lambda self: {"ibm.mq"}),
):
# Bare match drops entry.
ts = {"Providers[ibm.mq]"}
checks._filter_platform_excluded_test_types(ts)
assert ts == set()
# Combined positive form drops just the excluded id.
ts = {"Providers[amazon,ibm.mq,google]"}
checks._filter_platform_excluded_test_types(ts)
assert ts == {"Providers[amazon,google]"}
# Negative form gets the excluded id appended.
ts = {"Providers[-amazon,celery,google,standard]"}
checks._filter_platform_excluded_test_types(ts)
assert ts == {"Providers[-amazon,celery,google,ibm.mq,standard]"}
# Non-Providers entries are untouched.
ts = {"Core", "Always"}
checks._filter_platform_excluded_test_types(ts)
assert ts == {"Core", "Always"}
@patch("airflow_breeze.utils.selective_checks.run_command")
def test_provider_dependency_bump_check_no_changes(mock_run_command):
"""Test that provider dependency bump check passes when no pyproject.toml files are changed."""
selective_checks = SelectiveChecks(
files=("some_other_file.py",),
commit_ref=NEUTRAL_COMMIT,
pr_labels=(),
github_event=GithubEvents.PULL_REQUEST,
default_branch="main",
)
result = selective_checks.provider_dependency_bump
assert result is False
@patch("airflow_breeze.utils.selective_checks.run_command")
def test_provider_dependency_bump_check_fails_on_provider_version_bump(mock_run_command):
"""Test that provider dependency bump check fails when provider version is bumped without label."""
old_toml = """
[project]
dependencies = [
"apache-airflow-providers-common-sql>=1.0.0",
]
"""
new_toml = """
[project]
dependencies = [
"apache-airflow-providers-common-sql>=1.1.0",
]
"""
def side_effect(*args, **kwargs):
result = Mock()
result.returncode = 0
if "^:" in args[0][2]:
result.stdout = old_toml
else:
result.stdout = new_toml
return result
mock_run_command.side_effect = side_effect
with pytest.raises(SystemExit):
SelectiveChecks(
files=("providers/amazon/pyproject.toml",),
commit_ref=NEUTRAL_COMMIT,
pr_labels=(),
github_event=GithubEvents.PULL_REQUEST,
default_branch="main",
).provider_dependency_bump
@patch("airflow_breeze.utils.selective_checks.run_command")
def test_provider_dependency_bump_check_works_on_provider_version_bump_when_pushed(mock_run_command):
"""Test that provider dependency bump check fails when provider version is bumped without label."""
old_toml = """
[project]
dependencies = [
"apache-airflow-providers-common-sql>=1.0.0",
]
"""
new_toml = """
[project]
dependencies = [
"apache-airflow-providers-common-sql>=1.1.0",
]
"""
def side_effect(*args, **kwargs):
result = Mock()
result.returncode = 0
if "^:" in args[0][2]:
result.stdout = old_toml
else:
result.stdout = new_toml
return result
mock_run_command.side_effect = side_effect
assert not SelectiveChecks(
files=("providers/amazon/pyproject.toml",),
commit_ref=NEUTRAL_COMMIT,
pr_labels=(),
github_event=GithubEvents.PUSH,
default_branch="main",
).provider_dependency_bump
@patch("airflow_breeze.utils.selective_checks.run_command")
def test_provider_dependency_bump_check_skipped_on_release_branch(mock_run_command):
"""Test that provider dependency bump check is a no-op on release branches (v3-X-test)."""
old_toml = """
[project]
dependencies = [
"apache-airflow-providers-common-sql>=1.0.0",
]
"""
new_toml = """
[project]
dependencies = [
"apache-airflow-providers-common-sql>=1.1.0",
]
"""
def side_effect(*args, **kwargs):
result = Mock()
result.returncode = 0
if "^:" in args[0][2]:
result.stdout = old_toml
else:
result.stdout = new_toml
return result
mock_run_command.side_effect = side_effect
assert not SelectiveChecks(
files=("providers/amazon/pyproject.toml",),
commit_ref=NEUTRAL_COMMIT,
pr_labels=(),
github_event=GithubEvents.PULL_REQUEST,
default_branch="v3-2-test",
).provider_dependency_bump
@patch("airflow_breeze.utils.selective_checks.run_command")
def test_provider_dependency_bump_check_passes_with_label(mock_run_command):
"""Test that provider dependency bump check passes when label is set."""
old_toml = """
[project]
dependencies = [
"apache-airflow-providers-common-sql>=1.0.0",
]
"""
new_toml = """
[project]
dependencies = [
"apache-airflow-providers-common-sql>=1.1.0",
]
"""
def side_effect(*args, **kwargs):
result = Mock()
result.returncode = 0
if "^:" in args[0][2]:
result.stdout = old_toml
else:
result.stdout = new_toml
return result
mock_run_command.side_effect = side_effect
selective_checks = SelectiveChecks(
files=("providers/amazon/pyproject.toml",),
commit_ref=NEUTRAL_COMMIT,
pr_labels=("allow provider dependency bump",),
github_event=GithubEvents.PULL_REQUEST,
default_branch="main",
)
result = selective_checks.provider_dependency_bump
assert result is True
@patch("airflow_breeze.utils.selective_checks.run_command")
def test_provider_dependency_bump_check_passes_on_non_provider_dependency_changes(mock_run_command):
"""Test that provider dependency bump check passes when non-provider dependencies change."""
old_toml = """
[project]
dependencies = [
"apache-airflow>=2.11.0",
"boto3>=1.37.0",
]
"""
new_toml = """
[project]
dependencies = [
"apache-airflow>=2.11.0",
"boto3>=1.38.0",
]
"""
def side_effect(*args, **kwargs):
result = Mock()
result.returncode = 0
if "^:" in args[0][2]:
result.stdout = old_toml
else:
result.stdout = new_toml
return result
mock_run_command.side_effect = side_effect
selective_checks = SelectiveChecks(
files=("providers/amazon/pyproject.toml",),
commit_ref=NEUTRAL_COMMIT,
pr_labels=(),
github_event=GithubEvents.PULL_REQUEST,
default_branch="main",
)
result = selective_checks.provider_dependency_bump
assert result is False
@patch("airflow_breeze.utils.selective_checks.run_command")
def test_provider_dependency_bump_check_in_optional_dependencies(mock_run_command):
"""Test that provider dependency bump check works for optional-dependencies section."""
old_toml = """
[project.optional-dependencies]
"cncf.kubernetes" = [
"apache-airflow-providers-cncf-kubernetes>=7.0.0",
]
"""
new_toml = """
[project.optional-dependencies]
"cncf.kubernetes" = [
"apache-airflow-providers-cncf-kubernetes>=7.2.0",
]
"""
def side_effect(*args, **kwargs):
result = Mock()
result.returncode = 0
if "^:" in args[0][2]:
result.stdout = old_toml
else:
result.stdout = new_toml
return result
mock_run_command.side_effect = side_effect
with pytest.raises(SystemExit):
_ = SelectiveChecks(
files=("providers/amazon/pyproject.toml",),
commit_ref=NEUTRAL_COMMIT,
pr_labels=(),
github_event=GithubEvents.PULL_REQUEST,
default_branch="main",
).provider_dependency_bump
@patch("airflow_breeze.utils.selective_checks.run_command")
def test_common_compat_changed_with_next_version_passes(mock_run_command):
"""Test that check passes when common.compat changes and other provider has '# use next version'."""
provider_toml = """
[project]
dependencies = [
"apache-airflow>=2.11.0",
"apache-airflow-providers-common-compat>=1.8.0", # use next version
]
"""
def side_effect(*args, **kwargs):
result = Mock()
result.returncode = 0
result.stdout = provider_toml
return result
mock_run_command.side_effect = side_effect
selective_checks = SelectiveChecks(
files=(
"providers/common/compat/src/airflow/providers/common/compat/file.py",
"providers/ftp/src/airflow/providers/ftp/hooks/ftp.py",
),
commit_ref=NEUTRAL_COMMIT,
pr_labels=(),
github_event=GithubEvents.PULL_REQUEST,
default_branch="main",
)
result = selective_checks.common_compat_changed_without_next_version
assert result is False
@patch("airflow_breeze.utils.selective_checks.run_command")
def test_common_compat_changed_without_next_version_fails(mock_run_command):
"""Test that check fails when common.compat changes and other provider doesn't have '# use next version'."""
provider_toml = """
[project]
dependencies = [
"apache-airflow>=2.11.0",
"apache-airflow-providers-common-compat>=1.8.0",
]
"""
def side_effect(*args, **kwargs):
result = Mock()
result.returncode = 0
result.stdout = provider_toml
return result
mock_run_command.side_effect = side_effect
with pytest.raises(SystemExit):
_ = SelectiveChecks(
files=(
"providers/common/compat/src/airflow/providers/common/compat/file.py",
"providers/ftp/src/airflow/providers/ftp/hooks/ftp.py",
),
commit_ref=NEUTRAL_COMMIT,
pr_labels=(),
github_event=GithubEvents.PULL_REQUEST,
default_branch="main",
).common_compat_changed_without_next_version
@patch("airflow_breeze.utils.selective_checks.run_command")
def test_common_compat_only_changed_passes(mock_run_command):
"""Test that check passes when only common.compat provider changes."""
selective_checks = SelectiveChecks(
files=("providers/common/compat/src/airflow/providers/common/compat/file.py",),
commit_ref=NEUTRAL_COMMIT,
pr_labels=(),
github_event=GithubEvents.PULL_REQUEST,
default_branch="main",
)
result = selective_checks.common_compat_changed_without_next_version
assert result is False
@patch("airflow_breeze.utils.selective_checks.run_command")
def test_common_compat_not_changed_passes(mock_run_command):
"""Test that check passes when common.compat provider doesn't change."""
selective_checks = SelectiveChecks(
files=("providers/ftp/src/airflow/providers/ftp/hooks/ftp.py",),
commit_ref=NEUTRAL_COMMIT,
pr_labels=(),
github_event=GithubEvents.PULL_REQUEST,
default_branch="main",
)
result = selective_checks.common_compat_changed_without_next_version
assert result is False
@patch("airflow_breeze.utils.selective_checks.run_command")
def test_common_compat_changed_with_provider_without_dependency_passes(mock_run_command):
"""Test that check passes when other provider doesn't depend on common-compat."""
provider_toml = """
[project]
dependencies = [
"apache-airflow>=2.11.0",
"some-other-package>=1.0.0",
]
"""
def side_effect(*args, **kwargs):
result = Mock()
result.returncode = 0
result.stdout = provider_toml
return result
mock_run_command.side_effect = side_effect
selective_checks = SelectiveChecks(
files=(
"providers/common/compat/src/airflow/providers/common/compat/file.py",
"providers/ftp/src/airflow/providers/ftp/hooks/ftp.py",
),
commit_ref=NEUTRAL_COMMIT,
pr_labels=(),
github_event=GithubEvents.PULL_REQUEST,
default_branch="main",
)
result = selective_checks.common_compat_changed_without_next_version
assert result is False
@patch("airflow_breeze.utils.selective_checks.run_command")
def test_common_compat_changed_without_next_version_skipped_on_release_branch(mock_run_command):
"""Test that common.compat next-version check is a no-op on release branches (v3-X-test)."""
provider_toml = """
[project]
dependencies = [
"apache-airflow>=2.11.0",
"apache-airflow-providers-common-compat>=1.8.0",
]
"""
def side_effect(*args, **kwargs):
result = Mock()
result.returncode = 0
result.stdout = provider_toml
return result
mock_run_command.side_effect = side_effect
assert not SelectiveChecks(
files=(
"providers/common/compat/src/airflow/providers/common/compat/file.py",
"providers/ftp/src/airflow/providers/ftp/hooks/ftp.py",
),
commit_ref=NEUTRAL_COMMIT,
pr_labels=(),
github_event=GithubEvents.PULL_REQUEST,
default_branch="v3-2-test",
).common_compat_changed_without_next_version
@patch("airflow_breeze.utils.selective_checks.run_command")
def test_common_compat_changed_without_next_version_bypassed_with_label(mock_run_command):
"""Test that check can be bypassed with 'skip common compat check' label."""
provider_toml = """
[project]
dependencies = [
"apache-airflow>=2.11.0",
"apache-airflow-providers-common-compat>=1.8.0",
]
"""
def side_effect(*args, **kwargs):
result = Mock()
result.returncode = 0
result.stdout = provider_toml
return result
mock_run_command.side_effect = side_effect
selective_checks = SelectiveChecks(
files=(
"providers/common/compat/src/airflow/providers/common/compat/file.py",
"providers/ftp/src/airflow/providers/ftp/hooks/ftp.py",
),
commit_ref=NEUTRAL_COMMIT,
pr_labels=("skip common compat check",),
github_event=GithubEvents.PULL_REQUEST,
default_branch="main",
)
# Should pass with the skip label
result = selective_checks.common_compat_changed_without_next_version
assert result is True
@pytest.mark.parametrize(
("files", "pr_labels", "expected_outputs"),
[
pytest.param(
("chart/tests/helm_tests/random_helm_test.py",),
(),
{
"helm-test-kubernetes-versions": DEFAULT_HELM_K8S_VERSIONS_JSON,
},
id="Default K8s version when no all-versions label",
),
pytest.param(
("chart/tests/helm_tests/random_helm_test.py",),
("all versions",),
{
"helm-test-kubernetes-versions": ALL_HELM_K8S_VERSIONS_JSON,
},
id="First and last K8s versions when all-versions label is set",
),
pytest.param(
("INTHEWILD.md",),
("full tests needed", "all versions"),
{
"helm-test-kubernetes-versions": ALL_HELM_K8S_VERSIONS_JSON,
"all-versions": "true",
},
id="First and last K8s versions when full tests needed with all versions",
),
pytest.param(
("INTHEWILD.md",),
("full tests needed",),
{
"helm-test-kubernetes-versions": DEFAULT_HELM_K8S_VERSIONS_JSON,
"all-versions": "false",
},
id="Default K8s version when full tests needed but no all-versions label",
),
],
)
def test_helm_test_kubernetes_versions(
files: tuple[str, ...], pr_labels: tuple[str, ...], expected_outputs: dict[str, str]
):
stderr = SelectiveChecks(
files=files,
commit_ref=NEUTRAL_COMMIT,
github_event=GithubEvents.PULL_REQUEST,
pr_labels=pr_labels,
default_branch="main",
)
assert_outputs_are_printed(expected_outputs, str(stderr))