diff --git a/dev/breeze/src/airflow_breeze/commands/kubernetes_commands.py b/dev/breeze/src/airflow_breeze/commands/kubernetes_commands.py index c12231d72669b..e8881674c78ff 100644 --- a/dev/breeze/src/airflow_breeze/commands/kubernetes_commands.py +++ b/dev/breeze/src/airflow_breeze/commands/kubernetes_commands.py @@ -2585,7 +2585,9 @@ def _lang_sdk_build_go_bundle( go_example's go.mod ``replace``s go-sdk by relative path, so the build runs in a scratch workspace mirroring the repo layout with ``upstream_go_sdk`` at ``/go-sdk``, - letting the unmodified directive resolve against the upstream copy. + letting the unmodified directive resolve against the upstream copy. The scratch go_example is + re-tidied before packing so its go.sum reconciles to that upstream go-sdk (which may differ from + the in-repo go-sdk its committed go.sum was tidied against). """ go_dir = staging / "go-artifacts" go_dir.mkdir(parents=True, exist_ok=True) @@ -2603,12 +2605,20 @@ def _lang_sdk_build_go_bundle( # CGO_ENABLED=0 yields a fully static binary that runs on the stock worker. The package built is # the current dir (".") because go_example is its own module. + # + # go_example's go.sum is tidied against the in-repo go-sdk, but the bundle is built against the + # upstream-main go-sdk copied in above. When a branch changes go-sdk's dependency graph those two + # go-sdks differ, and Go refuses to build on the resulting go.sum drift. Re-tidy the scratch copy + # first so the build reconciles to whichever go-sdk it is actually compiled against; the committed + # go.sum is untouched and stays guarded by the check-go-example-mod-tidy prek hook. if native: get_console(output=output).print("[info]Building Go bundle with the host Go toolchain") + go_env = {**os.environ, "CGO_ENABLED": "0"} + run_command(["go", "mod", "tidy"], cwd=example_path, env=go_env, output=output, check=True) run_command( ["go", "tool", "airflow-go-pack", "--output", str(output_bin), "."], cwd=example_path, - env={**os.environ, "CGO_ENABLED": "0"}, + env=go_env, output=output, check=True, ) @@ -2620,26 +2630,30 @@ def _lang_sdk_build_go_bundle( # the real go_example's gitignored cache dir so the caches persist across scratch workspaces. (LANG_SDK_GO_EXAMPLE_PATH / ".home").mkdir(parents=True, exist_ok=True) get_console(output=output).print(f"[info]Building Go bundle in {LANG_SDK_GO_BUILDER_IMAGE}") + docker_base = [ + "docker", + "run", + "--rm", + "--user", + uid_gid, + "-e", + f"HOME={go_example_ctr}/.home", + "-e", + "USER=airflow", + "-e", + "CGO_ENABLED=0", + "-v", + f"{workspace}:/repo", + "-v", + f"{LANG_SDK_GO_EXAMPLE_PATH / '.home'}:{go_example_ctr}/.home", + "-w", + go_example_ctr, + LANG_SDK_GO_BUILDER_IMAGE, + ] + run_command([*docker_base, "go", "mod", "tidy"], output=output, check=True) run_command( [ - "docker", - "run", - "--rm", - "--user", - uid_gid, - "-e", - f"HOME={go_example_ctr}/.home", - "-e", - "USER=airflow", - "-e", - "CGO_ENABLED=0", - "-v", - f"{workspace}:/repo", - "-v", - f"{LANG_SDK_GO_EXAMPLE_PATH / '.home'}:{go_example_ctr}/.home", - "-w", - go_example_ctr, - LANG_SDK_GO_BUILDER_IMAGE, + *docker_base, "go", "tool", "airflow-go-pack", diff --git a/dev/breeze/tests/test_kubernetes_lang_sdk_commands.py b/dev/breeze/tests/test_kubernetes_lang_sdk_commands.py index ab5eb9946ea53..31332c24d1675 100644 --- a/dev/breeze/tests/test_kubernetes_lang_sdk_commands.py +++ b/dev/breeze/tests/test_kubernetes_lang_sdk_commands.py @@ -93,6 +93,10 @@ def test_native_uses_host_go_toolchain(self, mock_run, tmp_path, go_example, ups # The workspace mirrors the repo layout, with go-sdk swapped for the upstream copy. assert (workspace_example.parent / "go-sdk" / "marker.go").read_text() == "upstream" assert (tmp_path / "go-artifacts" / kubernetes_commands.LANG_SDK_GO_BUNDLE_NAME).exists() + # The scratch copy is re-tidied against the upstream go-sdk before packing, in the same dir. + tidy_call = mock_run.call_args_list[0] + assert tidy_call.args[0] == ["go", "mod", "tidy"] + assert tidy_call.kwargs["cwd"] == workspace_example @mock.patch.object(kubernetes_commands, "run_command") def test_container_mode_runs_in_docker(self, mock_run, tmp_path, go_example, upstream_go_sdk): @@ -108,6 +112,11 @@ def test_container_mode_runs_in_docker(self, mock_run, tmp_path, go_example, ups assert repo_mount.split(":")[0] != str(go_example.parent) home_mount = next(m for m in mounts if m.endswith("/.home")) assert home_mount.startswith(str(go_example / ".home")) + # The scratch copy is re-tidied in the same container image before packing. + tidy_cmd = mock_run.call_args_list[0].args[0] + assert tidy_cmd[0] == "docker" + assert kubernetes_commands.LANG_SDK_GO_BUILDER_IMAGE in tidy_cmd + assert tidy_cmd[-3:] == ["go", "mod", "tidy"] class TestLangSdkBuildJavaJar: