This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch v3-2-test
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/v3-2-test by this push:
new ab2b50e0d5b [v3-2-test] Exclude text non-doc files from triggering
full CI test runs (#64584) (#64809)
ab2b50e0d5b is described below
commit ab2b50e0d5bc2af420b24b064bd7941f43a850ad
Author: Jarek Potiuk <[email protected]>
AuthorDate: Mon Apr 6 22:39:13 2026 +0200
[v3-2-test] Exclude text non-doc files from triggering full CI test runs
(#64584) (#64809)
Changes to .txt and .md files that are not part of the doc build
should not trigger the full test suite. This adds a new
TEXT_NON_DOC_FILES file group to selective checks and an
only_text_non_doc_files_changed property so these files are
subtracted from the "remaining files" set, avoiding unnecessary
CI runs for text-only, non-doc-build changes.
Also removes the overly broad `^dev/.*` pattern from the
test-always file group since dev/ changes should be evaluated
by more specific file group patterns.
(cherry picked from commit aca2d59ffa7b471738e868a8aea8d2dc69fa8174)
---
.../src/airflow_breeze/utils/selective_checks.py | 21 ++++-
dev/breeze/tests/test_selective_checks.py | 101 +++++++++++++++------
2 files changed, 94 insertions(+), 28 deletions(-)
diff --git a/dev/breeze/src/airflow_breeze/utils/selective_checks.py
b/dev/breeze/src/airflow_breeze/utils/selective_checks.py
index 5167505275a..99e74fcfa50 100644
--- a/dev/breeze/src/airflow_breeze/utils/selective_checks.py
+++ b/dev/breeze/src/airflow_breeze/utils/selective_checks.py
@@ -113,6 +113,7 @@ class FileGroupForCi(Enum):
HELM_FILES = auto()
DEPENDENCY_FILES = auto()
DOC_FILES = auto()
+ TEXT_NON_DOC_FILES = auto()
UI_FILES = auto()
SYSTEM_TEST_FILES = auto()
KUBERNETES_FILES = auto()
@@ -257,6 +258,10 @@ CI_FILE_GROUP_MATCHES: HashableDict[FileGroupForCi] =
HashableDict(
r"^chart/values\.json",
r"^RELEASE_NOTES\.rst",
],
+ FileGroupForCi.TEXT_NON_DOC_FILES: [
+ r"^.*\.txt",
+ r"^.*\.md",
+ ],
FileGroupForCi.UI_FILES: [
r"^airflow-core/src/airflow/ui/",
r"^airflow-core/src/airflow/api_fastapi/auth/managers/simple/ui/",
@@ -304,7 +309,6 @@ CI_FILE_GROUP_MATCHES: HashableDict[FileGroupForCi] =
HashableDict(
r"^helm-tests/tests/.*",
r"^kubernetes-tests/tests/.*",
r"^docker-tests/tests/.*",
- r"^dev/.*",
],
FileGroupForCi.SYSTEM_TEST_FILES: [
r"^airflow-core/tests/system/",
@@ -589,6 +593,11 @@ class SelectiveChecks:
def _should_run_all_tests_and_versions(self) -> bool:
if self._github_event in [GithubEvents.PUSH, GithubEvents.SCHEDULE,
GithubEvents.WORKFLOW_DISPATCH]:
+ if self.only_text_non_doc_files_changed:
+ console_print(
+ f"[warning]Only text non doc files changed in
{self._github_event}, skip full tests[/]"
+ )
+ return False
console_print(f"[warning]Running everything because event is
{self._github_event}[/]")
return True
if not self._commit_ref:
@@ -1056,6 +1065,13 @@ class SelectiveChecks:
def only_pyproject_toml_files_changed(self) -> bool:
return all(Path(file).name == "pyproject.toml" for file in self._files)
+ @cached_property
+ def only_text_non_doc_files_changed(self) -> bool:
+ text_non_doc_files = set(
+ self._matching_files(FileGroupForCi.TEXT_NON_DOC_FILES,
CI_FILE_GROUP_MATCHES)
+ )
+ return len(self._files) > 0 and set(self._files) <= text_non_doc_files
+
@cached_property
def ci_image_build(self) -> bool:
# in case pyproject.toml changed, CI image should be built - even if
no build dependencies
@@ -1125,11 +1141,13 @@ class SelectiveChecks:
test_always_files =
self._matching_files(FileGroupForCi.ALWAYS_TESTS_FILES, CI_FILE_GROUP_MATCHES)
test_ui_files = self._matching_files(FileGroupForCi.UI_FILES,
CI_FILE_GROUP_MATCHES)
+ text_non_doc_files =
self._matching_files(FileGroupForCi.TEXT_NON_DOC_FILES, CI_FILE_GROUP_MATCHES)
remaining_files = (
set(all_source_files)
- set(all_providers_source_files)
- set(all_providers_distribution_config_files)
- set(matched_files)
+ - set(text_non_doc_files)
- set(kubernetes_files)
- set(system_test_files)
- set(test_always_files)
@@ -1735,6 +1753,7 @@ class SelectiveChecks:
return (
self._github_event in [GithubEvents.SCHEDULE, GithubEvents.PUSH,
GithubEvents.WORKFLOW_DISPATCH]
and self._github_repository == APACHE_AIRFLOW_GITHUB_REPOSITORY
+ and not self.only_text_non_doc_files_changed
) or CANARY_LABEL in self._pr_labels
@cached_property
diff --git a/dev/breeze/tests/test_selective_checks.py
b/dev/breeze/tests/test_selective_checks.py
index 6135a9f7739..5d6ff376872 100644
--- a/dev/breeze/tests/test_selective_checks.py
+++ b/dev/breeze/tests/test_selective_checks.py
@@ -1358,6 +1358,53 @@ def test_full_test_needed_when_pyproject_toml_changes(
assert_outputs_are_printed(expected_outputs, str(stderr))
[email protected](
+ ("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",),
@@ -1870,44 +1917,44 @@ def test_expected_output_pull_request_v2_7(
(),
"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",
- "docs-list-as-string": ALL_DOCS_SELECTED_FOR_BUILD,
- "skip-prek-hooks":
ALL_SKIPPED_COMMITS_BY_DEFAULT_ON_ALL_TESTS_NEEDED,
+ "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",
- "core-test-types-list-as-strings-in-json":
ALL_CI_SELECTIVE_TEST_TYPES_AS_JSON,
- "run-mypy": "true",
- "mypy-checks": ALL_MYPY_CHECKS,
+ "skip-prek-hooks":
ALL_SKIPPED_COMMITS_IF_NOT_IMPORTANT_FILES_CHANGED,
+ "core-test-types-list-as-strings-in-json": None,
+ "run-mypy": "false",
+ "mypy-checks": "[]",
},
- id="All tests run on push even if unimportant file changed",
+ id="No tests run on push if only text non-doc files changed",
),
pytest.param(
("INTHEWILD.md",),
(),
"v2-3-stable",
{
- "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",
+ "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": "true",
- "docs-build": "true",
- "skip-prek-hooks": All_SKIPPED_COMMITS_IF_NON_MAIN_BRANCH,
- "docs-list-as-string": "apache-airflow docker-stack",
+ "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":
ALL_CI_SELECTIVE_TEST_TYPES_AS_JSON,
- "run-mypy": "true",
- "mypy-checks": ALL_MYPY_CHECKS_EXCEPT_PROVIDERS,
+ "core-test-types-list-as-strings-in-json": None,
+ "run-mypy": "false",
+ "mypy-checks": "[]",
},
- id="All tests except Providers and Helm run on push"
- " even if unimportant file changed in non-main branch",
+ 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",),