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 d122d0386d6 Fix config lint warnings for remove_if_equals rules
(#66370)
d122d0386d6 is described below
commit d122d0386d684dd449d6581dd5b4244e30f7e607
Author: Henry Chen <[email protected]>
AuthorDate: Sun Jul 5 06:26:33 2026 +0800
Fix config lint warnings for remove_if_equals rules (#66370)
---
.../src/airflowctl/ctl/commands/config_command.py | 32 +++++++----
.../ctl/commands/test_config_command.py | 67 ++++++++++++++++++++++
2 files changed, 88 insertions(+), 11 deletions(-)
diff --git a/airflow-ctl/src/airflowctl/ctl/commands/config_command.py
b/airflow-ctl/src/airflowctl/ctl/commands/config_command.py
index 20147484d94..b83600697ad 100644
--- a/airflow-ctl/src/airflowctl/ctl/commands/config_command.py
+++ b/airflow-ctl/src/airflowctl/ctl/commands/config_command.py
@@ -67,10 +67,10 @@ class ConfigChange:
breaking: bool = False
remove_if_equals: str | bool | int | float | None = None
- def message(self, api_client=NEW_API_CLIENT) -> str | None:
+ def message(self, all_configs: Config) -> str | None:
"""Generate a message for this configuration change."""
if self.default_change:
- value = self._get_option_value(api_client.configs.list())
+ value = self._get_option_value(all_configs)
if value != self.new_default:
return (
f"Changed default value of `{self.config.option}` in
`{self.config.section}` "
@@ -86,14 +86,15 @@ class ConfigChange:
f"`{self.config.option}` configuration parameter renamed to
`{self.renamed_to.option}` "
f"in the `{self.config.section}` section."
)
- if self.was_removed and not self.remove_if_equals:
- return (
- f"Removed{' deprecated' if self.was_deprecated else ''}
`{self.config.option}` configuration parameter "
- f"from `{self.config.section}` section."
- f"{self.suggestion}"
- )
+ if self.was_removed:
+ if self.remove_if_equals is None:
+ return self._removed_message
+
+ value = self._get_option_value(all_configs)
+ if value == str(self.remove_if_equals):
+ return self._removed_message
if self.is_invalid_if is not None:
- value = self._get_option_value(api_client.configs.list())
+ value = self._get_option_value(all_configs)
if value == self.is_invalid_if:
return (
f"Invalid value `{self.is_invalid_if}` set for
`{self.config.option}` configuration parameter "
@@ -109,6 +110,14 @@ class ConfigChange:
return option.value if isinstance(option.value, str)
else str(option.value)
return None
+ @property
+ def _removed_message(self) -> str:
+ return (
+ f"Removed{' deprecated' if self.was_deprecated else ''}
`{self.config.option}` configuration parameter "
+ f"from `{self.config.section}` section."
+ f"{self.suggestion}"
+ )
+
CONFIGS_CHANGES = [
# admin
@@ -805,8 +814,9 @@ def lint(args, api_client=NEW_API_CLIENT) -> None:
None,
)
if target_option:
- if configuration.message(api_client=api_client) is not
None:
-
lint_issues.append(configuration.message(api_client=api_client))
+ msg = configuration.message(all_configs)
+ if msg is not None:
+ lint_issues.append(msg)
if lint_issues:
rich.print("[red]Found issues in your airflow.cfg:[/red]")
diff --git a/airflow-ctl/tests/airflow_ctl/ctl/commands/test_config_command.py
b/airflow-ctl/tests/airflow_ctl/ctl/commands/test_config_command.py
index 731e30137c7..77705a4c63c 100644
--- a/airflow-ctl/tests/airflow_ctl/ctl/commands/test_config_command.py
+++ b/airflow-ctl/tests/airflow_ctl/ctl/commands/test_config_command.py
@@ -19,6 +19,8 @@ from __future__ import annotations
import os
from unittest.mock import patch
+import pytest
+
from airflowctl.api.client import ClientKind
from airflowctl.api.datamodels.generated import Config, ConfigOption,
ConfigSection
from airflowctl.ctl import cli_parser
@@ -158,6 +160,71 @@ class TestCliConfigCommands:
in calls[1]
)
+ @pytest.mark.parametrize(
+ ("remove_if_equals", "config_value", "expected_has_issue"),
+ [
+ pytest.param("matching_value", "matching_value", True,
id="non-empty-match"),
+ pytest.param("", "", True, id="empty-string-match"),
+ pytest.param("", "non_matching_value", False,
id="empty-string-no-match"),
+ ],
+ )
+ def test_lint_handles_remove_if_equals_rules(
+ self, api_client_maker, remove_if_equals, config_value,
expected_has_issue
+ ):
+ with (
+ patch("airflowctl.api.client.Credentials.load"),
+ patch.dict(os.environ, {"AIRFLOW_CLI_TOKEN": "TEST_TOKEN"}),
+ patch.dict(os.environ, {"AIRFLOW_CLI_ENVIRONMENT": "TEST_CONFIG"}),
+ patch("rich.print") as mock_rich_print,
+ patch(
+ "airflowctl.ctl.commands.config_command.CONFIGS_CHANGES",
+ [
+ ConfigChange(
+ config=ConfigParameter("test_section", "test_option"),
+ was_removed=True,
+ remove_if_equals=remove_if_equals,
+ ),
+ ],
+ ),
+ ):
+ response_config = Config(
+ sections=[
+ ConfigSection(
+ name="test_section",
+ options=[
+ ConfigOption(
+ key="test_option",
+ value=config_value,
+ )
+ ],
+ )
+ ]
+ )
+
+ api_client = api_client_maker(
+ path="/api/v2/config",
+ response_json=response_config.model_dump(),
+ expected_http_status_code=200,
+ kind=ClientKind.CLI,
+ )
+
+ config_command.lint(
+ self.parser.parse_args(["config", "lint"]),
+ api_client=api_client,
+ )
+
+ calls = [call[0][0] for call in mock_rich_print.call_args_list]
+ if expected_has_issue:
+ assert "[red]Found issues in your airflow.cfg:[/red]" in calls[0]
+ assert (
+ "- [yellow]Removed deprecated `test_option` configuration
parameter from `test_section` section.[/yellow]"
+ in calls[1]
+ )
+ else:
+ assert (
+ "[green]No issues found in your airflow.cfg. It is ready for
Airflow 3![/green]" in calls[0]
+ )
+
@patch("airflowctl.api.client.Credentials.load")
@patch.dict(os.environ, {"AIRFLOW_CLI_TOKEN": "TEST_TOKEN"})
@patch.dict(os.environ, {"AIRFLOW_CLI_ENVIRONMENT": "TEST_CONFIG"})