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 b171e3eddc1 Drop duplicate build_raw copy from
CloudBuildCreateBuildOperator (#73592)
b171e3eddc1 is described below
commit b171e3eddc10babf7ea7f0cb477d0d657a69634d
Author: Shahar Epstein <[email protected]>
AuthorDate: Wed Sep 23 18:20:45 2026 +0300
Drop duplicate build_raw copy from CloudBuildCreateBuildOperator (#73592)
* Fix Cloud Build operator template preparation
* Cover CloudBuildCreateBuildOperator template preparation with tests
prepare_template() now reads self.build instead of the removed
build_raw copy, so a second call short-circuits on the already-parsed
dict instead of re-reading the build file from disk. Add a test that
constructing the operator keeps no second attribute referencing the
build argument, and a test that calling prepare_template() twice after
the backing file is gone still leaves operator.build populated with the
parsed content from the first call.
The duplicate-attribute test matches on object identity rather than on
the removed build_raw name, so it also catches a copy reintroduced
under any other attribute name.
The operator leaves template_ext empty, so resolve_template_files()
never replaces self.build with the file's contents before
prepare_template() runs; prepare_template() is the only place that
reads the file, which is what makes the second call idempotent.
---------
Co-authored-by: Abhisek Behera
<[email protected]>
---
.../google/cloud/operators/cloud_build.py | 12 ++++++------
.../google/cloud/operators/test_cloud_build.py | 22 ++++++++++++++++++++++
.../ci/prek/validate_operators_init_exemptions.txt | 1 -
3 files changed, 28 insertions(+), 7 deletions(-)
diff --git
a/providers/google/src/airflow/providers/google/cloud/operators/cloud_build.py
b/providers/google/src/airflow/providers/google/cloud/operators/cloud_build.py
index 85963e81e47..14d500731ac 100644
---
a/providers/google/src/airflow/providers/google/cloud/operators/cloud_build.py
+++
b/providers/google/src/airflow/providers/google/cloud/operators/cloud_build.py
@@ -190,8 +190,6 @@ class
CloudBuildCreateBuildOperator(GoogleCloudBaseOperator):
) -> None:
super().__init__(**kwargs)
self.build = build
- # Not template fields to keep original value
- self.build_raw = build
self.project_id = project_id
self.wait = wait
self.retry = retry
@@ -205,12 +203,14 @@ class
CloudBuildCreateBuildOperator(GoogleCloudBaseOperator):
def prepare_template(self) -> None:
# if no file is specified, skip
- if not isinstance(self.build_raw, str):
+ if not isinstance(self.build, str):
return
- with open(self.build_raw) as file:
- if self.build_raw.endswith((".yaml", ".yml")):
+ # Keep the path in a local: the branches below replace self.build with
a dict.
+ build_path = self.build
+ with open(build_path) as file:
+ if build_path.endswith((".yaml", ".yml")):
self.build = yaml.safe_load(file.read())
- if self.build_raw.endswith(".json"):
+ if build_path.endswith(".json"):
self.build = json.loads(file.read())
@property
diff --git
a/providers/google/tests/unit/google/cloud/operators/test_cloud_build.py
b/providers/google/tests/unit/google/cloud/operators/test_cloud_build.py
index 854cc97923b..8726a7c8350 100644
--- a/providers/google/tests/unit/google/cloud/operators/test_cloud_build.py
+++ b/providers/google/tests/unit/google/cloud/operators/test_cloud_build.py
@@ -165,6 +165,28 @@ class TestCloudBuildOperator:
expected_body = {"steps": [{"name": "ubuntu", "args": ["echo",
"Hello {{ params.name }}!"]}]}
assert expected_body == operator.build
+ def test_init_does_not_duplicate_build(self):
+ build_path = "path/to/build.json"
+ operator = CloudBuildCreateBuildOperator(build=build_path,
task_id="task-id")
+ assert operator.build == build_path
+ # Any second attribute referencing the same object would be a copy
prepare_template()
+ # could read instead of self.build, whatever it is named.
+ assert [name for name, value in vars(operator).items() if value is
build_path] == ["build"]
+
+ def test_prepare_template_second_call_is_no_op(self, tmp_path):
+ expected_body = {"steps": [{"name": "ubuntu", "args": ["echo", "Hello
{{ params.name }}!"]}]}
+ build_file = tmp_path / "build.json"
+ build_file.write_text(json.dumps(expected_body))
+
+ operator = CloudBuildCreateBuildOperator(build=str(build_file),
task_id="task-id")
+ operator.prepare_template()
+ assert expected_body == operator.build
+
+ build_file.unlink()
+
+ operator.prepare_template()
+ assert expected_body == operator.build
+
@mock.patch(CLOUD_BUILD_HOOK_PATH)
def test_create_build_trigger(self, mock_hook):
mock_hook.return_value.create_build_trigger.return_value =
BuildTrigger()
diff --git a/scripts/ci/prek/validate_operators_init_exemptions.txt
b/scripts/ci/prek/validate_operators_init_exemptions.txt
index ada2c476766..a4d2e7f04ae 100644
--- a/scripts/ci/prek/validate_operators_init_exemptions.txt
+++ b/scripts/ci/prek/validate_operators_init_exemptions.txt
@@ -7,5 +7,4 @@
# Burn-down tracked at https://github.com/apache/airflow/issues/70296
providers/amazon/src/airflow/providers/amazon/aws/operators/neptune.py::NeptuneStartDbClusterOperator
providers/amazon/src/airflow/providers/amazon/aws/operators/neptune.py::NeptuneStopDbClusterOperator
-providers/google/src/airflow/providers/google/cloud/operators/cloud_build.py::CloudBuildCreateBuildOperator
providers/google/src/airflow/providers/google/cloud/operators/dataproc.py::DataprocCreateClusterOperator