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

Reply via email to