This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 2d0b1e77f58 Skip ktlint prek hook unless java-sdk files changed
(#68210)
2d0b1e77f58 is described below
commit 2d0b1e77f58a0e900884ea1388894dd4860b6ac2
Author: Yuseok Jo <[email protected]>
AuthorDate: Tue Jun 9 00:27:08 2026 +0900
Skip ktlint prek hook unless java-sdk files changed (#68210)
---
dev/breeze/doc/ci/04_selective_checks.md | 3 +
.../src/airflow_breeze/utils/selective_checks.py | 5 ++
dev/breeze/tests/test_selective_checks.py | 72 +++++++++++++++-------
3 files changed, 58 insertions(+), 22 deletions(-)
diff --git a/dev/breeze/doc/ci/04_selective_checks.md
b/dev/breeze/doc/ci/04_selective_checks.md
index 2076aa280cd..fbe33278684 100644
--- a/dev/breeze/doc/ci/04_selective_checks.md
+++ b/dev/breeze/doc/ci/04_selective_checks.md
@@ -464,6 +464,9 @@ when some files are not changed. Those are the rules
implemented:
* if no `WWW files` changed - `ts-compile-format-lint-www` check is skipped
* if no `All Python files` changed - `flynt` check is skipped
* if no `Helm files` changed - `lint-helm-chart` check is skipped
+ * if no `Java SDK files` changed - `ktlint` check is skipped (it runs the
java-sdk Gradle
+ wrapper, which downloads the Gradle distribution, so we avoid that
download on PRs that do
+ not touch `java-sdk/`)
* if no `All Providers Python files` and no `All Providers Yaml files` are
changed -
`check-provider-yaml-valid` check is skipped
diff --git a/dev/breeze/src/airflow_breeze/utils/selective_checks.py
b/dev/breeze/src/airflow_breeze/utils/selective_checks.py
index 022096624d5..cc1e2126145 100644
--- a/dev/breeze/src/airflow_breeze/utils/selective_checks.py
+++ b/dev/breeze/src/airflow_breeze/utils/selective_checks.py
@@ -1562,6 +1562,11 @@ class SelectiveChecks:
CI_FILE_GROUP_MATCHES,
):
prek_hooks_to_skip.add("lint-helm-chart")
+ if not self._matching_files(FileGroupForCi.JAVA_SDK_FILES,
CI_FILE_GROUP_MATCHES):
+ # ktlint runs the java-sdk Gradle wrapper, which downloads the
Gradle distribution
+ # on a cold cache. Skip it when no java-sdk files changed so
unrelated PRs do not
+ # depend on that (intermittently failing) download.
+ prek_hooks_to_skip.add("ktlint")
if not (
self._matching_files(
FileGroupForCi.ALL_PROVIDERS_DISTRIBUTION_CONFIG_FILES,
CI_FILE_GROUP_MATCHES
diff --git a/dev/breeze/tests/test_selective_checks.py
b/dev/breeze/tests/test_selective_checks.py
index 7615a3db3b6..f11438e0440 100644
--- a/dev/breeze/tests/test_selective_checks.py
+++ b/dev/breeze/tests/test_selective_checks.py
@@ -100,7 +100,7 @@ LIST_OF_ALL_PROVIDER_TESTS_AS_JSON = json.dumps(
ALL_SKIPPED_COMMITS_ON_NO_CI_IMAGE = (
- "check-provider-yaml-valid,flynt,identity,lint-helm-chart,"
+ "check-provider-yaml-valid,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,"
@@ -114,7 +114,7 @@ ALL_SKIPPED_COMMITS_ON_NO_CI_IMAGE = (
ALL_SKIPPED_COMMITS_BY_DEFAULT_ON_ALL_TESTS_NEEDED = "identity,update-uv-lock"
ALL_SKIPPED_COMMITS_IF_NO_UI = (
-
"identity,mypy-airflow-core,mypy-airflow-ctl,mypy-airflow-ctl-tests,mypy-airflow-e2e-tests,"
+
"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,"
@@ -124,7 +124,7 @@ ALL_SKIPPED_COMMITS_IF_NO_UI = (
"ts-compile-lint-simple-auth-manager-ui,ts-compile-lint-ui,update-uv-lock"
)
ALL_SKIPPED_COMMITS_IF_NO_HELM_TESTS = (
- "identity,lint-helm-chart,"
+ "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,"
@@ -135,7 +135,7 @@ ALL_SKIPPED_COMMITS_IF_NO_HELM_TESTS = (
)
ALL_SKIPPED_COMMITS_IF_NO_UI_AND_HELM_TESTS = (
- "identity,lint-helm-chart,"
+ "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,"
@@ -150,7 +150,7 @@ ALL_SKIPPED_COMMITS_IF_NO_UI_AND_HELM_TESTS = (
# 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,identity,lint-helm-chart,"
+ "check-provider-yaml-valid,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,"
@@ -163,7 +163,7 @@ ALL_SKIPPED_COMMITS_IF_ONLY_API_SOURCE_CHANGED = (
)
ALL_SKIPPED_COMMITS_IF_NO_PROVIDERS_AND_UI = (
- "check-provider-yaml-valid,identity,"
+ "check-provider-yaml-valid,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,"
@@ -175,7 +175,7 @@ ALL_SKIPPED_COMMITS_IF_NO_PROVIDERS_AND_UI = (
)
ALL_SKIPPED_COMMITS_IF_NO_PROVIDERS = (
- "check-provider-yaml-valid,identity,lint-helm-chart,"
+ "check-provider-yaml-valid,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,"
@@ -188,7 +188,7 @@ ALL_SKIPPED_COMMITS_IF_NO_PROVIDERS = (
ALL_SKIPPED_COMMITS_IF_NO_PROVIDERS_UI_AND_HELM_TESTS = (
- "check-provider-yaml-valid,identity,lint-helm-chart,"
+ "check-provider-yaml-valid,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,"
@@ -200,7 +200,7 @@ ALL_SKIPPED_COMMITS_IF_NO_PROVIDERS_UI_AND_HELM_TESTS = (
)
ALL_SKIPPED_COMMITS_IF_NO_CODE_PROVIDERS_AND_HELM_TESTS = (
- "check-provider-yaml-valid,flynt,identity,lint-helm-chart,"
+ "check-provider-yaml-valid,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,"
@@ -211,7 +211,7 @@ ALL_SKIPPED_COMMITS_IF_NO_CODE_PROVIDERS_AND_HELM_TESTS = (
)
ALL_SKIPPED_COMMITS_IF_NOT_IMPORTANT_FILES_CHANGED = (
- "check-provider-yaml-valid,flynt,identity,lint-helm-chart,"
+ "check-provider-yaml-valid,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,"
@@ -456,7 +456,7 @@ def assert_outputs_are_printed(expected_outputs: dict[str,
str], stderr: str):
"run-amazon-tests": "false",
"docs-build": "true",
"skip-prek-hooks": (
- "check-provider-yaml-valid,identity,lint-helm-chart,"
+
"check-provider-yaml-valid,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,"
@@ -502,7 +502,7 @@ def assert_outputs_are_printed(expected_outputs: dict[str,
str], stderr: str):
"run-api-tests": "true",
"docs-build": "true",
"skip-prek-hooks": (
- "identity,lint-helm-chart,"
+ "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,"
@@ -753,7 +753,7 @@ def assert_outputs_are_printed(expected_outputs: dict[str,
str], stderr: str):
"docs-build": "true",
"full-tests-needed": "false",
"skip-prek-hooks": (
- "check-provider-yaml-valid,identity,lint-helm-chart,"
+
"check-provider-yaml-valid,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,"
@@ -791,7 +791,7 @@ def assert_outputs_are_printed(expected_outputs: dict[str,
str], stderr: str):
"docs-build": "false",
"full-tests-needed": "false",
"skip-prek-hooks": (
- "check-provider-yaml-valid,identity,lint-helm-chart,"
+
"check-provider-yaml-valid,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,"
@@ -828,7 +828,7 @@ def assert_outputs_are_printed(expected_outputs: dict[str,
str], stderr: str):
"docs-build": "true",
"full-tests-needed": "false",
"skip-prek-hooks": (
- "check-provider-yaml-valid,identity,lint-helm-chart,"
+
"check-provider-yaml-valid,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,"
@@ -864,7 +864,7 @@ def assert_outputs_are_printed(expected_outputs: dict[str,
str], stderr: str):
"docs-build": "false",
"full-tests-needed": "false",
"skip-prek-hooks": (
- "check-provider-yaml-valid,identity,lint-helm-chart,"
+
"check-provider-yaml-valid,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,"
@@ -1205,7 +1205,7 @@ def assert_outputs_are_printed(expected_outputs:
dict[str, str], stderr: str):
"docs-build": "false",
"run-kubernetes-tests": "false",
"skip-prek-hooks": (
- "identity,lint-helm-chart,"
+ "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,"
@@ -1369,7 +1369,7 @@ def assert_outputs_are_printed(expected_outputs:
dict[str, str], stderr: str):
"run-amazon-tests": "false",
"docs-build": "true",
"skip-prek-hooks": (
- "check-provider-yaml-valid,flynt,identity,"
+ "check-provider-yaml-valid,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,"
@@ -1583,7 +1583,7 @@ def assert_outputs_are_printed(expected_outputs:
dict[str, str], stderr: str):
("shared/logging/src/airflow_shared/logging/remote.py",),
{
"skip-prek-hooks": (
- "check-provider-yaml-valid,identity,lint-helm-chart,"
+
"check-provider-yaml-valid,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,"
@@ -1615,6 +1615,34 @@ def test_expected_output_pull_request_main(
assert_outputs_are_printed(expected_outputs, str(stderr))
[email protected](
+ ("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",
+ ),
+ ],
+)
+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.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)",
@@ -2321,7 +2349,7 @@ def test_expected_output_push(
"docs-build": "true",
"docs-list-as-string": ALL_DOCS_SELECTED_FOR_BUILD,
"skip-prek-hooks": (
- "check-provider-yaml-valid,identity,lint-helm-chart,"
+
"check-provider-yaml-valid,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,"
@@ -2363,7 +2391,7 @@ def test_expected_output_push(
"microsoft.mssql mysql openlineage oracle postgres "
"presto salesforce samba sftp ssh standard trino",
"skip-prek-hooks": (
-
"identity,mypy-airflow-ctl,mypy-airflow-ctl-tests,mypy-airflow-e2e-tests,"
+
"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,"
@@ -2408,7 +2436,7 @@ def test_expected_output_push(
"docs-build": "true",
"docs-list-as-string": "apache-airflow",
"skip-prek-hooks": (
- "check-provider-yaml-valid,identity,lint-helm-chart,"
+
"check-provider-yaml-valid,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,"