From c5afa35ee6de97474f25d3ac68614e7b4869f6e5 Mon Sep 17 00:00:00 2001 From: Shelley Shen Date: Tue, 25 Aug 2026 13:32:13 -0700 Subject: [PATCH 1/6] feat(java): add shared GET /info REST controller to nv-boot-starter-core Add an auto-configured InfoController serving a flat {service, version, commit} body on GET /info, mirroring the existing shared HealthController. Reads git.properties directly for the commit SHA and build version, so it works consistently across consuming services without depending on Actuator's info exposure or property-source ordering. --- .../boot/core/CoreAutoConfiguration.java | 2 + .../nvidia/boot/core/info/GitBuildInfo.java | 81 +++++++++++++++++++ .../boot/core/info/InfoConfiguration.java | 44 ++++++++++ .../nvidia/boot/core/info/InfoController.java | 40 +++++++++ .../nvidia/boot/core/info/InfoResponse.java | 22 +++++ .../boot/core/info/InfoResponseService.java | 38 +++++++++ .../boot/core/info/GitBuildInfoTest.java | 59 ++++++++++++++ .../boot/core/info/InfoControllerTest.java | 48 +++++++++++ .../core/info/InfoResponseServiceTest.java | 55 +++++++++++++ 9 files changed, 389 insertions(+) create mode 100644 src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/GitBuildInfo.java create mode 100644 src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoConfiguration.java create mode 100644 src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoController.java create mode 100644 src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponse.java create mode 100644 src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponseService.java create mode 100644 src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/GitBuildInfoTest.java create mode 100644 src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoControllerTest.java create mode 100644 src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoResponseServiceTest.java diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/CoreAutoConfiguration.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/CoreAutoConfiguration.java index f5bd919f3..9ae1ae1df 100644 --- a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/CoreAutoConfiguration.java +++ b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/CoreAutoConfiguration.java @@ -20,6 +20,7 @@ import com.nvidia.boot.core.cors.ServletCoreCorsConfiguration; import com.nvidia.boot.core.cors.ReactiveCoreCorsConfiguration; import com.nvidia.boot.core.health.HealthConfiguration; +import com.nvidia.boot.core.info.InfoConfiguration; import com.nvidia.boot.core.openapi.OpenApiConfiguration; import com.nvidia.boot.core.openapi.ServletOpenApiCorsConfiguration; import com.nvidia.boot.core.openapi.ReactiveOpenApiCorsConfiguration; @@ -29,6 +30,7 @@ @AutoConfiguration @Import({ HealthConfiguration.class, + InfoConfiguration.class, OpenApiConfiguration.class, ReactiveCoreCorsConfiguration.class, ReactiveOpenApiCorsConfiguration.class, diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/GitBuildInfo.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/GitBuildInfo.java new file mode 100644 index 000000000..ebcf18298 --- /dev/null +++ b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/GitBuildInfo.java @@ -0,0 +1,81 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nvidia.boot.core.info; + +import java.io.IOException; +import java.util.Properties; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.support.PropertiesLoaderUtils; + +/** + * Reads {@code git.properties} directly off the classpath for {@code GET /info}, rather than + * from the {@link org.springframework.core.env.Environment}. This avoids depending on + * {@code BootCoreEnvironmentPostProcessor}'s property-source ordering relative to Spring Boot's + * {@code ApplicationInfoPropertySource} (see that class for details). + * + *

Fallback order for version matches {@code BootCoreEnvironmentPostProcessor}: + * "git.closest.tag.name" -> "git.commit.id.abbrev" -> "unknown". + */ +@Slf4j +public class GitBuildInfo { + + private static final String GIT_PROPERTIES_FILE = "git.properties"; + private static final String UNKNOWN = "unknown"; + + private final String version; + private final String commit; + + public GitBuildInfo() { + this(loadGitProperties()); + } + + GitBuildInfo(Properties gitProperties) { + this.version = resolveVersion(gitProperties); + this.commit = gitProperties.getProperty("git.commit.id.full", UNKNOWN); + } + + public String version() { + return version; + } + + public String commit() { + return commit; + } + + private static String resolveVersion(Properties gitProperties) { + var version = gitProperties.getProperty("git.closest.tag.name"); + if (StringUtils.isBlank(version)) { + version = gitProperties.getProperty("git.commit.id.abbrev"); + } + return StringUtils.isNotBlank(version) ? version : UNKNOWN; + } + + private static Properties loadGitProperties() { + try { + var resource = new ClassPathResource(GIT_PROPERTIES_FILE); + if (resource.exists()) { + return PropertiesLoaderUtils.loadProperties(resource); + } + } catch (IOException e) { + log.warn("Failed to load '{}'", GIT_PROPERTIES_FILE); + } + return new Properties(); + } +} diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoConfiguration.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoConfiguration.java new file mode 100644 index 000000000..882606612 --- /dev/null +++ b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoConfiguration.java @@ -0,0 +1,44 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nvidia.boot.core.info; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +/** Auto-configuration for the shared {@code GET /info} endpoint and controller. */ +@Configuration +@ConditionalOnWebApplication +public class InfoConfiguration { + + @Bean + public GitBuildInfo gitBuildInfo() { + return new GitBuildInfo(); + } + + @Bean + public InfoResponseService infoResponseService(Environment environment, GitBuildInfo gitBuildInfo) { + return new InfoResponseService(environment, gitBuildInfo); + } + + @Bean + public InfoController infoController(InfoResponseService infoResponseService) { + return new InfoController(infoResponseService); + } +} diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoController.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoController.java new file mode 100644 index 000000000..899e4bd38 --- /dev/null +++ b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoController.java @@ -0,0 +1,40 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nvidia.boot.core.info; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * Shared build-info controller for {@code GET /info}. Returns a flat {service, version, commit} + * body, matching the equivalent Go services' contract, so build identification is consistent + * across NVCF control plane services. + */ +@RestController +@RequiredArgsConstructor +public class InfoController { + + private final InfoResponseService infoResponseService; + + @GetMapping("/info") + public ResponseEntity getInfo() { + return ResponseEntity.ok(infoResponseService.getInfo()); + } +} diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponse.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponse.java new file mode 100644 index 000000000..bd2195f33 --- /dev/null +++ b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponse.java @@ -0,0 +1,22 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nvidia.boot.core.info; + +/** Flat response body for {@code GET /info}: service name, build version, and git commit SHA. */ +public record InfoResponse(String service, String version, String commit) { +} diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponseService.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponseService.java new file mode 100644 index 000000000..db58cd533 --- /dev/null +++ b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponseService.java @@ -0,0 +1,38 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nvidia.boot.core.info; + +import lombok.RequiredArgsConstructor; +import org.springframework.core.env.Environment; + +/** Builds the {@link InfoResponse} served by {@link InfoController}. */ +@RequiredArgsConstructor +public class InfoResponseService { + + private static final String UNKNOWN = "unknown"; + + private final Environment environment; + private final GitBuildInfo gitBuildInfo; + + public InfoResponse getInfo() { + return new InfoResponse( + environment.getProperty("spring.application.name", UNKNOWN), + gitBuildInfo.version(), + gitBuildInfo.commit()); + } +} diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/GitBuildInfoTest.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/GitBuildInfoTest.java new file mode 100644 index 000000000..3fc2acadc --- /dev/null +++ b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/GitBuildInfoTest.java @@ -0,0 +1,59 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nvidia.boot.core.info; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Properties; +import org.junit.jupiter.api.Test; + +class GitBuildInfoTest { + + @Test + void usesClosestTagNameWhenPresent() { + var properties = new Properties(); + properties.setProperty("git.closest.tag.name", "v1.2.3"); + properties.setProperty("git.commit.id.abbrev", "77c5d93"); + properties.setProperty("git.commit.id.full", "77c5d932abcdef1234567890abcdef1234567890"); + + var gitBuildInfo = new GitBuildInfo(properties); + + assertThat(gitBuildInfo.version()).isEqualTo("v1.2.3"); + assertThat(gitBuildInfo.commit()).isEqualTo("77c5d932abcdef1234567890abcdef1234567890"); + } + + @Test + void fallsBackToCommitAbbrevWhenNoTag() { + var properties = new Properties(); + properties.setProperty("git.commit.id.abbrev", "77c5d93"); + properties.setProperty("git.commit.id.full", "77c5d932abcdef1234567890abcdef1234567890"); + + var gitBuildInfo = new GitBuildInfo(properties); + + assertThat(gitBuildInfo.version()).isEqualTo("77c5d93"); + assertThat(gitBuildInfo.commit()).isEqualTo("77c5d932abcdef1234567890abcdef1234567890"); + } + + @Test + void fallsBackToUnknownWhenGitPropertiesEmpty() { + var gitBuildInfo = new GitBuildInfo(new Properties()); + + assertThat(gitBuildInfo.version()).isEqualTo("unknown"); + assertThat(gitBuildInfo.commit()).isEqualTo("unknown"); + } +} diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoControllerTest.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoControllerTest.java new file mode 100644 index 000000000..fb1c0dd17 --- /dev/null +++ b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoControllerTest.java @@ -0,0 +1,48 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nvidia.boot.core.info; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class InfoControllerTest { + + private InfoResponseService infoResponseService; + private InfoController controller; + + @BeforeEach + void setUp() { + infoResponseService = mock(InfoResponseService.class); + controller = new InfoController(infoResponseService); + } + + @Test + void getInfoReturnsOkWithResponseBody() { + var expected = new InfoResponse("nvcf-ess", "v1.2.3", "77c5d932abcdef1234567890abcdef1234567890"); + when(infoResponseService.getInfo()).thenReturn(expected); + + var response = controller.getInfo(); + + assertThat(response.getStatusCode().is2xxSuccessful()).isTrue(); + assertThat(response.getBody()).isEqualTo(expected); + } +} diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoResponseServiceTest.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoResponseServiceTest.java new file mode 100644 index 000000000..65f31a8e7 --- /dev/null +++ b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoResponseServiceTest.java @@ -0,0 +1,55 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.nvidia.boot.core.info; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Properties; +import org.junit.jupiter.api.Test; +import org.springframework.core.env.Environment; + +class InfoResponseServiceTest { + + @Test + void buildsResponseFromApplicationNameAndGitBuildInfo() { + var environment = mock(Environment.class); + when(environment.getProperty("spring.application.name", "unknown")).thenReturn("nvcf-ess"); + + var properties = new Properties(); + properties.setProperty("git.closest.tag.name", "v1.2.3"); + properties.setProperty("git.commit.id.full", "77c5d932abcdef1234567890abcdef1234567890"); + var gitBuildInfo = new GitBuildInfo(properties); + + var service = new InfoResponseService(environment, gitBuildInfo); + + assertThat(service.getInfo()) + .isEqualTo(new InfoResponse("nvcf-ess", "v1.2.3", "77c5d932abcdef1234567890abcdef1234567890")); + } + + @Test + void fallsBackToUnknownServiceNameWhenApplicationNameMissing() { + var environment = mock(Environment.class); + when(environment.getProperty("spring.application.name", "unknown")).thenReturn("unknown"); + + var service = new InfoResponseService(environment, new GitBuildInfo(new Properties())); + + assertThat(service.getInfo()).isEqualTo(new InfoResponse("unknown", "unknown", "unknown")); + } +} From dcda9ab67e6f00db64b5de9d5e70864283f2e12d Mon Sep 17 00:00:00 2001 From: Shelley Shen Date: Tue, 25 Aug 2026 14:43:19 -0700 Subject: [PATCH 2/6] fix(java): normalize blank git.commit.id.full to unknown in GitBuildInfo Properties.getProperty(key, default) only falls back when the key is absent, not when it's present but blank. Use StringUtils.defaultIfBlank so /info still reports "unknown" for a blank git.commit.id.full instead of an empty string. --- .../java/com/nvidia/boot/core/info/GitBuildInfo.java | 3 ++- .../com/nvidia/boot/core/info/GitBuildInfoTest.java | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/GitBuildInfo.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/GitBuildInfo.java index ebcf18298..d26ad53e2 100644 --- a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/GitBuildInfo.java +++ b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/GitBuildInfo.java @@ -48,7 +48,8 @@ public GitBuildInfo() { GitBuildInfo(Properties gitProperties) { this.version = resolveVersion(gitProperties); - this.commit = gitProperties.getProperty("git.commit.id.full", UNKNOWN); + this.commit = StringUtils.defaultIfBlank( + gitProperties.getProperty("git.commit.id.full"), UNKNOWN); } public String version() { diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/GitBuildInfoTest.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/GitBuildInfoTest.java index 3fc2acadc..383ac3e40 100644 --- a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/GitBuildInfoTest.java +++ b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/GitBuildInfoTest.java @@ -56,4 +56,15 @@ void fallsBackToUnknownWhenGitPropertiesEmpty() { assertThat(gitBuildInfo.version()).isEqualTo("unknown"); assertThat(gitBuildInfo.commit()).isEqualTo("unknown"); } + + @Test + void fallsBackToUnknownWhenCommitFullIsBlank() { + var properties = new Properties(); + properties.setProperty("git.closest.tag.name", "v1.2.3"); + properties.setProperty("git.commit.id.full", " "); + + var gitBuildInfo = new GitBuildInfo(properties); + + assertThat(gitBuildInfo.commit()).isEqualTo("unknown"); + } } From 4e04d9401406546d0fe663f7a27349c5a879e98d Mon Sep 17 00:00:00 2001 From: Shelley Shen Date: Tue, 25 Aug 2026 14:51:32 -0700 Subject: [PATCH 3/6] fix(java): log the caught exception when git.properties fails to load log.warn omitted the IOException as the final SLF4J argument, so the stack trace/cause was never recorded when git.properties failed to load. --- .../src/main/java/com/nvidia/boot/core/info/GitBuildInfo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/GitBuildInfo.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/GitBuildInfo.java index d26ad53e2..15e6f45c2 100644 --- a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/GitBuildInfo.java +++ b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/GitBuildInfo.java @@ -75,7 +75,7 @@ private static Properties loadGitProperties() { return PropertiesLoaderUtils.loadProperties(resource); } } catch (IOException e) { - log.warn("Failed to load '{}'", GIT_PROPERTIES_FILE); + log.warn("Failed to load '{}'", GIT_PROPERTIES_FILE, e); } return new Properties(); } From d29eca7b4d01c9a08321d02f040b98900dac4b2a Mon Sep 17 00:00:00 2001 From: Shelley Shen Date: Thu, 27 Aug 2026 16:46:50 -0700 Subject: [PATCH 4/6] refactor(java): read /info version and commit from Environment Add app.git.commit.full to the nv-boot-git-properties source in BootCoreEnvironmentPostProcessor, then have InfoResponseService read spring.application.version and app.git.commit.full from Environment directly instead of re-parsing git.properties in a separate GitBuildInfo class. Removes the now-unneeded GitBuildInfo/GitBuildInfoTest. --- .../env/BootCoreEnvironmentPostProcessor.java | 5 ++ .../nvidia/boot/core/info/GitBuildInfo.java | 82 ------------------- .../boot/core/info/InfoConfiguration.java | 9 +- .../boot/core/info/InfoResponseService.java | 11 ++- .../BootCoreEnvironmentPostProcessorTest.java | 5 ++ .../boot/core/info/GitBuildInfoTest.java | 70 ---------------- .../core/info/InfoResponseServiceTest.java | 27 ++---- 7 files changed, 28 insertions(+), 181 deletions(-) delete mode 100644 src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/GitBuildInfo.java delete mode 100644 src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/GitBuildInfoTest.java diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/env/BootCoreEnvironmentPostProcessor.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/env/BootCoreEnvironmentPostProcessor.java index 17d45a010..9bd957106 100644 --- a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/env/BootCoreEnvironmentPostProcessor.java +++ b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/env/BootCoreEnvironmentPostProcessor.java @@ -107,6 +107,11 @@ private void loadAppVersionFromGitProperties(ConfigurableEnvironment environment versionProps.put("app.git.commit", commitId); } + var commitIdFull = gitProperties.getProperty("git.commit.id.full"); + if (StringUtils.isNotBlank(commitIdFull)) { + versionProps.put("app.git.commit.full", commitIdFull); + } + var branch = gitProperties.getProperty("git.branch"); if (StringUtils.isNotBlank(branch)) { versionProps.put("app.git.branch", branch); diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/GitBuildInfo.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/GitBuildInfo.java deleted file mode 100644 index 15e6f45c2..000000000 --- a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/GitBuildInfo.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nvidia.boot.core.info; - -import java.io.IOException; -import java.util.Properties; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.support.PropertiesLoaderUtils; - -/** - * Reads {@code git.properties} directly off the classpath for {@code GET /info}, rather than - * from the {@link org.springframework.core.env.Environment}. This avoids depending on - * {@code BootCoreEnvironmentPostProcessor}'s property-source ordering relative to Spring Boot's - * {@code ApplicationInfoPropertySource} (see that class for details). - * - *

Fallback order for version matches {@code BootCoreEnvironmentPostProcessor}: - * "git.closest.tag.name" -> "git.commit.id.abbrev" -> "unknown". - */ -@Slf4j -public class GitBuildInfo { - - private static final String GIT_PROPERTIES_FILE = "git.properties"; - private static final String UNKNOWN = "unknown"; - - private final String version; - private final String commit; - - public GitBuildInfo() { - this(loadGitProperties()); - } - - GitBuildInfo(Properties gitProperties) { - this.version = resolveVersion(gitProperties); - this.commit = StringUtils.defaultIfBlank( - gitProperties.getProperty("git.commit.id.full"), UNKNOWN); - } - - public String version() { - return version; - } - - public String commit() { - return commit; - } - - private static String resolveVersion(Properties gitProperties) { - var version = gitProperties.getProperty("git.closest.tag.name"); - if (StringUtils.isBlank(version)) { - version = gitProperties.getProperty("git.commit.id.abbrev"); - } - return StringUtils.isNotBlank(version) ? version : UNKNOWN; - } - - private static Properties loadGitProperties() { - try { - var resource = new ClassPathResource(GIT_PROPERTIES_FILE); - if (resource.exists()) { - return PropertiesLoaderUtils.loadProperties(resource); - } - } catch (IOException e) { - log.warn("Failed to load '{}'", GIT_PROPERTIES_FILE, e); - } - return new Properties(); - } -} diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoConfiguration.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoConfiguration.java index 882606612..6b1592e11 100644 --- a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoConfiguration.java +++ b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoConfiguration.java @@ -28,13 +28,8 @@ public class InfoConfiguration { @Bean - public GitBuildInfo gitBuildInfo() { - return new GitBuildInfo(); - } - - @Bean - public InfoResponseService infoResponseService(Environment environment, GitBuildInfo gitBuildInfo) { - return new InfoResponseService(environment, gitBuildInfo); + public InfoResponseService infoResponseService(Environment environment) { + return new InfoResponseService(environment); } @Bean diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponseService.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponseService.java index db58cd533..e10ec990e 100644 --- a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponseService.java +++ b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponseService.java @@ -20,19 +20,22 @@ import lombok.RequiredArgsConstructor; import org.springframework.core.env.Environment; -/** Builds the {@link InfoResponse} served by {@link InfoController}. */ +/** + * Builds the {@link InfoResponse} served by {@link InfoController}, reading {@code version} and + * {@code commit} from the {@code nv-boot-git-properties} {@link Environment} property source + * that {@code BootCoreEnvironmentPostProcessor} populates from {@code git.properties} at startup. + */ @RequiredArgsConstructor public class InfoResponseService { private static final String UNKNOWN = "unknown"; private final Environment environment; - private final GitBuildInfo gitBuildInfo; public InfoResponse getInfo() { return new InfoResponse( environment.getProperty("spring.application.name", UNKNOWN), - gitBuildInfo.version(), - gitBuildInfo.commit()); + environment.getProperty("spring.application.version", UNKNOWN), + environment.getProperty("app.git.commit.full", UNKNOWN)); } } diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/env/BootCoreEnvironmentPostProcessorTest.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/env/BootCoreEnvironmentPostProcessorTest.java index f3ae70d46..6e168e575 100644 --- a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/env/BootCoreEnvironmentPostProcessorTest.java +++ b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/env/BootCoreEnvironmentPostProcessorTest.java @@ -54,11 +54,13 @@ void usesClosestTagNameAsVersionWhenPresent() { git.closest.tag.name=v2.5.0 git.build.version=2.5.0-SNAPSHOT git.commit.id.abbrev=abc1234 + git.commit.id.full=abc1234def5678901234567890abcdef12345678 """); assertThat(env.getProperty("spring.application.version")).isEqualTo("v2.5.0"); assertThat(env.getProperty("app.git.tag")).isEqualTo("v2.5.0"); assertThat(env.getProperty("app.git.commit")).isEqualTo("abc1234"); + assertThat(env.getProperty("app.git.commit.full")).isEqualTo("abc1234def5678901234567890abcdef12345678"); assertThat(env.getProperty("app.git.branch")).isNull(); } @@ -96,6 +98,7 @@ void fallsBackToUnknownWhenAllVersionFieldsAbsent() { assertThat(env.getProperty("spring.application.version")).isEqualTo("unknown"); assertThat(env.getProperty("app.git.tag")).isNull(); assertThat(env.getProperty("app.git.commit")).isNull(); + assertThat(env.getProperty("app.git.commit.full")).isNull(); assertThat(env.getProperty("app.git.branch")).isEqualTo("main"); } @@ -105,10 +108,12 @@ void populatesAllGitMetadataProperties() { git.closest.tag.name=v2.5.0 git.build.version=2.5.0-SNAPSHOT git.commit.id.abbrev=abc1234 + git.commit.id.full=abc1234def5678901234567890abcdef12345678 git.branch=main """); assertThat(env.getProperty("app.git.commit")).isEqualTo("abc1234"); + assertThat(env.getProperty("app.git.commit.full")).isEqualTo("abc1234def5678901234567890abcdef12345678"); assertThat(env.getProperty("app.git.branch")).isEqualTo("main"); assertThat(env.getProperty("app.git.tag")).isEqualTo("v2.5.0"); } diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/GitBuildInfoTest.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/GitBuildInfoTest.java deleted file mode 100644 index 383ac3e40..000000000 --- a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/GitBuildInfoTest.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nvidia.boot.core.info; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.Properties; -import org.junit.jupiter.api.Test; - -class GitBuildInfoTest { - - @Test - void usesClosestTagNameWhenPresent() { - var properties = new Properties(); - properties.setProperty("git.closest.tag.name", "v1.2.3"); - properties.setProperty("git.commit.id.abbrev", "77c5d93"); - properties.setProperty("git.commit.id.full", "77c5d932abcdef1234567890abcdef1234567890"); - - var gitBuildInfo = new GitBuildInfo(properties); - - assertThat(gitBuildInfo.version()).isEqualTo("v1.2.3"); - assertThat(gitBuildInfo.commit()).isEqualTo("77c5d932abcdef1234567890abcdef1234567890"); - } - - @Test - void fallsBackToCommitAbbrevWhenNoTag() { - var properties = new Properties(); - properties.setProperty("git.commit.id.abbrev", "77c5d93"); - properties.setProperty("git.commit.id.full", "77c5d932abcdef1234567890abcdef1234567890"); - - var gitBuildInfo = new GitBuildInfo(properties); - - assertThat(gitBuildInfo.version()).isEqualTo("77c5d93"); - assertThat(gitBuildInfo.commit()).isEqualTo("77c5d932abcdef1234567890abcdef1234567890"); - } - - @Test - void fallsBackToUnknownWhenGitPropertiesEmpty() { - var gitBuildInfo = new GitBuildInfo(new Properties()); - - assertThat(gitBuildInfo.version()).isEqualTo("unknown"); - assertThat(gitBuildInfo.commit()).isEqualTo("unknown"); - } - - @Test - void fallsBackToUnknownWhenCommitFullIsBlank() { - var properties = new Properties(); - properties.setProperty("git.closest.tag.name", "v1.2.3"); - properties.setProperty("git.commit.id.full", " "); - - var gitBuildInfo = new GitBuildInfo(properties); - - assertThat(gitBuildInfo.commit()).isEqualTo("unknown"); - } -} diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoResponseServiceTest.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoResponseServiceTest.java index 65f31a8e7..630d1cae0 100644 --- a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoResponseServiceTest.java +++ b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoResponseServiceTest.java @@ -18,37 +18,28 @@ package com.nvidia.boot.core.info; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import java.util.Properties; import org.junit.jupiter.api.Test; -import org.springframework.core.env.Environment; +import org.springframework.mock.env.MockEnvironment; class InfoResponseServiceTest { @Test - void buildsResponseFromApplicationNameAndGitBuildInfo() { - var environment = mock(Environment.class); - when(environment.getProperty("spring.application.name", "unknown")).thenReturn("nvcf-ess"); + void buildsResponseFromEnvironmentProperties() { + var environment = new MockEnvironment() + .withProperty("spring.application.name", "nvcf-ess") + .withProperty("spring.application.version", "v1.2.3") + .withProperty("app.git.commit.full", "77c5d932abcdef1234567890abcdef1234567890"); - var properties = new Properties(); - properties.setProperty("git.closest.tag.name", "v1.2.3"); - properties.setProperty("git.commit.id.full", "77c5d932abcdef1234567890abcdef1234567890"); - var gitBuildInfo = new GitBuildInfo(properties); - - var service = new InfoResponseService(environment, gitBuildInfo); + var service = new InfoResponseService(environment); assertThat(service.getInfo()) .isEqualTo(new InfoResponse("nvcf-ess", "v1.2.3", "77c5d932abcdef1234567890abcdef1234567890")); } @Test - void fallsBackToUnknownServiceNameWhenApplicationNameMissing() { - var environment = mock(Environment.class); - when(environment.getProperty("spring.application.name", "unknown")).thenReturn("unknown"); - - var service = new InfoResponseService(environment, new GitBuildInfo(new Properties())); + void fallsBackToUnknownWhenPropertiesAbsent() { + var service = new InfoResponseService(new MockEnvironment()); assertThat(service.getInfo()).isEqualTo(new InfoResponse("unknown", "unknown", "unknown")); } From b09f8a323ae996e3cdec651f3d3ec618d46b5844 Mon Sep 17 00:00:00 2001 From: Shelley Shen Date: Thu, 27 Aug 2026 16:57:24 -0700 Subject: [PATCH 5/6] refactor(java): nest InfoResponse inside InfoResponseService, drop generic javadoc Move InfoResponse into InfoResponseService as a nested record since it's only ever created there, and remove the class-level javadoc that only restated what the code already says. --- .../nvidia/boot/core/info/InfoController.java | 1 + .../nvidia/boot/core/info/InfoResponse.java | 22 ------------------- .../boot/core/info/InfoResponseService.java | 8 +++---- .../boot/core/info/InfoControllerTest.java | 1 + .../core/info/InfoResponseServiceTest.java | 1 + 5 files changed, 6 insertions(+), 27 deletions(-) delete mode 100644 src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponse.java diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoController.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoController.java index 899e4bd38..b746040db 100644 --- a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoController.java +++ b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoController.java @@ -17,6 +17,7 @@ package com.nvidia.boot.core.info; +import com.nvidia.boot.core.info.InfoResponseService.InfoResponse; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponse.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponse.java deleted file mode 100644 index bd2195f33..000000000 --- a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponse.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.nvidia.boot.core.info; - -/** Flat response body for {@code GET /info}: service name, build version, and git commit SHA. */ -public record InfoResponse(String service, String version, String commit) { -} diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponseService.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponseService.java index e10ec990e..8f58aaacc 100644 --- a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponseService.java +++ b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponseService.java @@ -20,11 +20,6 @@ import lombok.RequiredArgsConstructor; import org.springframework.core.env.Environment; -/** - * Builds the {@link InfoResponse} served by {@link InfoController}, reading {@code version} and - * {@code commit} from the {@code nv-boot-git-properties} {@link Environment} property source - * that {@code BootCoreEnvironmentPostProcessor} populates from {@code git.properties} at startup. - */ @RequiredArgsConstructor public class InfoResponseService { @@ -38,4 +33,7 @@ public InfoResponse getInfo() { environment.getProperty("spring.application.version", UNKNOWN), environment.getProperty("app.git.commit.full", UNKNOWN)); } + + public record InfoResponse(String service, String version, String commit) { + } } diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoControllerTest.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoControllerTest.java index fb1c0dd17..aff8690f6 100644 --- a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoControllerTest.java +++ b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoControllerTest.java @@ -21,6 +21,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import com.nvidia.boot.core.info.InfoResponseService.InfoResponse; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoResponseServiceTest.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoResponseServiceTest.java index 630d1cae0..bc00d43b8 100644 --- a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoResponseServiceTest.java +++ b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoResponseServiceTest.java @@ -19,6 +19,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.nvidia.boot.core.info.InfoResponseService.InfoResponse; import org.junit.jupiter.api.Test; import org.springframework.mock.env.MockEnvironment; From 4abc7dd5bfaabd710a7860766aebf93abeadde93 Mon Sep 17 00:00:00 2001 From: Shelley Shen Date: Mon, 31 Aug 2026 10:19:12 -0700 Subject: [PATCH 6/6] fix(nv-boot): treat blank spring.application.version and app.git.commit.full as unresolved Environment#getProperty only falls back to "unknown" when a key is missing, so a configured but empty value passed through unchanged. Resolve properties through a StringUtils.isBlank check, matching the existing pattern in ValidateEnvironmentPostProcessor. Signed-off-by: Shelley Shen --- .../nvidia/boot/core/info/InfoResponseService.java | 12 +++++++++--- .../boot/core/info/InfoResponseServiceTest.java | 12 ++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponseService.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponseService.java index 8f58aaacc..dce7b729c 100644 --- a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponseService.java +++ b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/main/java/com/nvidia/boot/core/info/InfoResponseService.java @@ -18,6 +18,7 @@ package com.nvidia.boot.core.info; import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; import org.springframework.core.env.Environment; @RequiredArgsConstructor @@ -29,9 +30,14 @@ public class InfoResponseService { public InfoResponse getInfo() { return new InfoResponse( - environment.getProperty("spring.application.name", UNKNOWN), - environment.getProperty("spring.application.version", UNKNOWN), - environment.getProperty("app.git.commit.full", UNKNOWN)); + resolve("spring.application.name"), + resolve("spring.application.version"), + resolve("app.git.commit.full")); + } + + private String resolve(String key) { + String value = environment.getProperty(key); + return StringUtils.isBlank(value) ? UNKNOWN : value; } public record InfoResponse(String service, String version, String commit) { diff --git a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoResponseServiceTest.java b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoResponseServiceTest.java index bc00d43b8..177eccd4f 100644 --- a/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoResponseServiceTest.java +++ b/src/libraries/java/nv-boot-parent/nv-boot-starter-core/src/test/java/com/nvidia/boot/core/info/InfoResponseServiceTest.java @@ -44,4 +44,16 @@ void fallsBackToUnknownWhenPropertiesAbsent() { assertThat(service.getInfo()).isEqualTo(new InfoResponse("unknown", "unknown", "unknown")); } + + @Test + void fallsBackToUnknownWhenPropertiesBlank() { + var environment = new MockEnvironment() + .withProperty("spring.application.name", " ") + .withProperty("spring.application.version", "") + .withProperty("app.git.commit.full", ""); + + var service = new InfoResponseService(environment); + + assertThat(service.getInfo()).isEqualTo(new InfoResponse("unknown", "unknown", "unknown")); + } }