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 4670c047f44 Stop airflow config update from writing a backup during
dry-run (#70979)
4670c047f44 is described below
commit 4670c047f44312471114df855eb8ce217fdc26df
Author: Y-C <[email protected]>
AuthorDate: Wed Aug 19 02:55:47 2026 +0800
Stop airflow config update from writing a backup during dry-run (#70979)
Without --fix the command is meant to be a pure preview, so it should
leave the filesystem alone. Creating the .bak unconditionally also made
the command abort before printing anything when the config directory is
not writable, hiding the very preview the user asked for.
Co-authored-by: Eason09053360
<[email protected]>
---
.../src/airflow/cli/commands/config_command.py | 20 +++++++++----------
.../tests/unit/cli/commands/test_config_command.py | 23 ++++++++++++++++++++++
2 files changed, 33 insertions(+), 10 deletions(-)
diff --git a/airflow-core/src/airflow/cli/commands/config_command.py
b/airflow-core/src/airflow/cli/commands/config_command.py
index e464fa1e80b..77b187b5899 100644
--- a/airflow-core/src/airflow/cli/commands/config_command.py
+++ b/airflow-core/src/airflow/cli/commands/config_command.py
@@ -941,8 +941,8 @@ def update_config(args) -> None:
the breaking configuration changes by scanning the current configuration
file for parameters that have
been renamed, removed, or had their default values changed in Airflow 3.0.
To see or fix all recommended
changes, use the --all-recommendations argument. To automatically update
your airflow.cfg file, use
- the --fix argument. This command cleans up the existing comments in
airflow.cfg but creates a backup of
- the old airflow.cfg file.
+ the --fix argument. Applying --fix cleans up the existing comments in
airflow.cfg, so a backup of the
+ old airflow.cfg file is written first. A dry-run leaves the filesystem
untouched.
CLI Arguments:
--fix: flag (optional)
@@ -1066,14 +1066,6 @@ def update_config(args) -> None:
modifications.add_remove(conf_section, conf_option)
changes_applied.append(f"{prefix} Removed
'{conf_section}/{conf_option}' from configuration.")
- backup_path = f"{AIRFLOW_CONFIG}.bak"
- try:
- shutil.copy2(AIRFLOW_CONFIG, backup_path)
- console.print(f"Backup saved as '{backup_path}'.")
- except Exception as e:
- console.print(f"Failed to create backup: {e}")
- raise AirflowConfigException("Backup creation failed. Aborting
update_config operation.")
-
if dry_run:
console.print("[blue]Dry-run mode enabled. No changes will be written
to airflow.cfg.[/blue]")
with StringIO() as config_output:
@@ -1086,6 +1078,14 @@ def update_config(args) -> None:
new_config = config_output.getvalue()
console.print(new_config)
else:
+ backup_path = f"{AIRFLOW_CONFIG}.bak"
+ try:
+ shutil.copy2(AIRFLOW_CONFIG, backup_path)
+ console.print(f"Backup saved as '{backup_path}'.")
+ except Exception as e:
+ console.print(f"Failed to create backup: {e}")
+ raise AirflowConfigException("Backup creation failed. Aborting
update_config operation.")
+
with open(AIRFLOW_CONFIG, "w") as config_file:
conf.write_custom_config(
file=config_file,
diff --git a/airflow-core/tests/unit/cli/commands/test_config_command.py
b/airflow-core/tests/unit/cli/commands/test_config_command.py
index c6345b96434..3e3913d6947 100644
--- a/airflow-core/tests/unit/cli/commands/test_config_command.py
+++ b/airflow-core/tests/unit/cli/commands/test_config_command.py
@@ -627,6 +627,29 @@ class TestCliConfigUpdate:
current_cfg = cfg_file.read_text()
assert initial_config in current_cfg, "Dry-run should not modify the
config file."
+ @conf_vars({("core", "executor"): "SequentialExecutor"})
+ def test_update_config_dry_run_does_not_touch_filesystem(self, tmp_path,
monkeypatch, capsys):
+ cfg_file = tmp_path / "airflow.cfg"
+ cfg_file.write_text("[core]\nexecutor = SequentialExecutor\n")
+
+ monkeypatch.setattr(config_command, "AIRFLOW_CONFIG", str(cfg_file))
+ monkeypatch.setattr(conf, "write_custom_config", lambda file,
**kwargs: file.write("preview_config"))
+
+ def read_only_copy2(src, dst):
+ raise OSError("Read-only file system")
+
+ monkeypatch.setattr(shutil, "copy2", read_only_copy2)
+
+ parser = cli_parser.get_parser()
+ args = parser.parse_args(["config", "update", "--all-recommendations"])
+
+ config_command.update_config(args)
+
+ output = capsys.readouterr().out
+ assert "preview_config" in output
+ assert "Backup saved as" not in output
+ assert not (tmp_path / "airflow.cfg.bak").exists()
+
@conf_vars({("core", "executor"): "SequentialExecutor"})
def test_update_config_all_options_fix(self, tmp_path, monkeypatch,
capsys):
cfg_file = tmp_path / "airflow.cfg"