-
Notifications
You must be signed in to change notification settings - Fork 0
[Feature] Get backend build version #555
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
233b8c0
build(version): generate git and build metadata during maven build
Kvanzi 636af6c
feat(version): add public endpoint for backend build version
Kvanzi b8729c5
test(version): cover version service and endpoint
Kvanzi a6c0f70
refactor(version): move response dto to dao/dto/response
Kvanzi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
src/main/java/com/itasocialacademy/oitassist/version/controller/VersionController.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| package com.itasocialacademy.oitassist.version.controller; | ||
|
|
||
| import com.itasocialacademy.oitassist.version.dao.dto.response.VersionResponse; | ||
| import com.itasocialacademy.oitassist.version.service.interfaces.VersionService; | ||
| import io.swagger.v3.oas.annotations.Operation; | ||
| import io.swagger.v3.oas.annotations.media.Content; | ||
| import io.swagger.v3.oas.annotations.media.Schema; | ||
| import io.swagger.v3.oas.annotations.responses.ApiResponse; | ||
| import io.swagger.v3.oas.annotations.tags.Tag; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.http.MediaType; | ||
| import org.springframework.web.bind.annotation.GetMapping; | ||
| import org.springframework.web.bind.annotation.RequestMapping; | ||
| import org.springframework.web.bind.annotation.RestController; | ||
|
|
||
| @RestController | ||
| @RequiredArgsConstructor | ||
| @RequestMapping("/api/v1/version") | ||
| @Tag(name = "Version", description = "Public API for the build version of the running application") | ||
| public class VersionController { | ||
| private final VersionService versionService; | ||
|
|
||
| @GetMapping | ||
| @Operation( | ||
| summary = "Get application build version", | ||
| description = """ | ||
| Returns the build version of the running application: the commit the backend | ||
| was built from and the date the artifact was built. | ||
| Values that were not available at build time are returned as null. | ||
| Publicly accessible, no authentication required. | ||
| """) | ||
| @ApiResponse( | ||
| responseCode = "200", | ||
| description = "Build version retrieved successfully", | ||
| content = @Content( | ||
| mediaType = MediaType.APPLICATION_JSON_VALUE, | ||
| schema = @Schema(implementation = VersionResponse.class))) | ||
| public VersionResponse getVersion() { | ||
| return versionService.getVersion(); | ||
| } | ||
| } |
22 changes: 22 additions & 0 deletions
22
src/main/java/com/itasocialacademy/oitassist/version/dao/dto/response/VersionResponse.java
|
StInvestigator marked this conversation as resolved.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| package com.itasocialacademy.oitassist.version.dao.dto.response; | ||
|
|
||
| import io.swagger.v3.oas.annotations.media.Schema; | ||
| import java.time.Instant; | ||
|
|
||
| @Schema(description = "Build version of the running application") | ||
| public record VersionResponse( | ||
| @Schema(description = "Backend build information") BackendVersion backend, | ||
| @Schema(description = "Date and time when the artifact was built") Instant buildTime) { | ||
| @Schema(description = "Backend build information") | ||
| public record BackendVersion( | ||
| @Schema( | ||
| description = "Full hash of the commit the artifact was built from", | ||
| example = "3534bab24568a602605078b9264711223f218dd2") String commitId, | ||
| @Schema( | ||
| description = "Short hash of the commit the artifact was built from", | ||
| example = "3534bab") String shortCommitId, | ||
| @Schema(description = "Date and time of the commit") Instant commitTime, | ||
| @Schema(description = "Branch the artifact was built from", example = "dev") String branch, | ||
| @Schema(description = "Artifact version", example = "0.0.1-SNAPSHOT") String version) { | ||
| } | ||
| } |
5 changes: 5 additions & 0 deletions
5
src/main/java/com/itasocialacademy/oitassist/version/package-info.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| @org.springframework.modulith.ApplicationModule( | ||
| displayName = "version", | ||
| allowedDependencies = {}) | ||
|
|
||
| package com.itasocialacademy.oitassist.version; |
57 changes: 57 additions & 0 deletions
57
src/main/java/com/itasocialacademy/oitassist/version/service/VersionServiceImpl.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| package com.itasocialacademy.oitassist.version.service; | ||
|
|
||
| import com.itasocialacademy.oitassist.version.dao.dto.response.VersionResponse; | ||
| import com.itasocialacademy.oitassist.version.service.interfaces.VersionService; | ||
| import lombok.extern.slf4j.Slf4j; | ||
| import org.jspecify.annotations.NonNull; | ||
| import org.springframework.beans.factory.ObjectProvider; | ||
| import org.springframework.boot.info.BuildProperties; | ||
| import org.springframework.boot.info.GitProperties; | ||
| import org.springframework.stereotype.Service; | ||
| import java.time.Instant; | ||
|
|
||
| @Slf4j | ||
| @Service | ||
| public class VersionServiceImpl implements VersionService { | ||
| private final GitProperties gitProperties; | ||
| private final BuildProperties buildProperties; | ||
|
|
||
| public VersionServiceImpl( | ||
| ObjectProvider<@NonNull GitProperties> gitPropertiesProvider, | ||
| ObjectProvider<@NonNull BuildProperties> buildPropertiesProvider) { | ||
| this.gitProperties = gitPropertiesProvider.getIfAvailable(); | ||
| this.buildProperties = buildPropertiesProvider.getIfAvailable(); | ||
|
|
||
| if (this.gitProperties == null) { | ||
| log.warn("git.properties is missing, commit data will not be reported"); | ||
| } | ||
| if (this.buildProperties == null) { | ||
| log.warn("build-info.properties is missing, build data will not be reported"); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public VersionResponse getVersion() { | ||
| return new VersionResponse(getBackendVersion(), getBuildTime()); | ||
| } | ||
|
|
||
| private VersionResponse.BackendVersion getBackendVersion() { | ||
| if (gitProperties == null) { | ||
| return new VersionResponse.BackendVersion(null, null, null, null, null); | ||
| } | ||
| return new VersionResponse.BackendVersion( | ||
| gitProperties.getCommitId(), | ||
| gitProperties.getShortCommitId(), | ||
| gitProperties.getCommitTime(), | ||
| gitProperties.getBranch(), | ||
| getArtifactVersion()); | ||
| } | ||
|
|
||
| private String getArtifactVersion() { | ||
| return buildProperties == null ? null : buildProperties.getVersion(); | ||
| } | ||
|
|
||
| private Instant getBuildTime() { | ||
| return buildProperties == null ? null : buildProperties.getTime(); | ||
| } | ||
| } |
7 changes: 7 additions & 0 deletions
7
src/main/java/com/itasocialacademy/oitassist/version/service/interfaces/VersionService.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package com.itasocialacademy.oitassist.version.service.interfaces; | ||
|
|
||
| import com.itasocialacademy.oitassist.version.dao.dto.response.VersionResponse; | ||
|
|
||
| public interface VersionService { | ||
| VersionResponse getVersion(); | ||
| } |
105 changes: 105 additions & 0 deletions
105
src/test/java/com/itasocialacademy/oitassist/version/controller/VersionControllerTest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| package com.itasocialacademy.oitassist.version.controller; | ||
|
|
||
| import static org.mockito.Mockito.when; | ||
| import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; | ||
| import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; | ||
| import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; | ||
| import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | ||
|
|
||
| import com.itasocialacademy.oitassist.core.web.AppExceptionHttpStatusMapper; | ||
| import com.itasocialacademy.oitassist.security.jwt.JwtFilter; | ||
| import com.itasocialacademy.oitassist.version.dao.dto.response.VersionResponse; | ||
| import com.itasocialacademy.oitassist.version.service.interfaces.VersionService; | ||
| import java.time.Instant; | ||
| import org.junit.jupiter.api.Test; | ||
| import org.springframework.beans.factory.annotation.Autowired; | ||
| import org.springframework.boot.test.context.TestConfiguration; | ||
| import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; | ||
| import org.springframework.context.annotation.Bean; | ||
| import org.springframework.context.annotation.ComponentScan; | ||
| import org.springframework.context.annotation.FilterType; | ||
| import org.springframework.context.annotation.Import; | ||
| import org.springframework.http.MediaType; | ||
| import org.springframework.security.config.annotation.web.builders.HttpSecurity; | ||
| import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; | ||
| import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; | ||
| import org.springframework.security.web.SecurityFilterChain; | ||
| import org.springframework.test.context.bean.override.mockito.MockitoBean; | ||
| import org.springframework.test.web.servlet.MockMvc; | ||
|
|
||
| @WebMvcTest( | ||
| controllers = VersionController.class, | ||
| excludeFilters = @ComponentScan.Filter( | ||
| type = FilterType.ASSIGNABLE_TYPE, | ||
| classes = JwtFilter.class)) | ||
| @Import(VersionControllerTest.SecurityTestConfiguration.class) | ||
| class VersionControllerTest { | ||
|
|
||
| private static final String ENDPOINT = "/api/v1/version"; | ||
| private static final String COMMIT_ID = "3534bab24568a602605078b9264711223f218dd2"; | ||
| private static final String SHORT_COMMIT_ID = "3534bab"; | ||
| private static final String COMMIT_TIME = "2026-08-19T08:22:05Z"; | ||
| private static final String BUILD_TIME = "2026-08-19T19:55:29.490Z"; | ||
|
|
||
| @Autowired | ||
| private MockMvc mockMvc; | ||
|
|
||
| @MockitoBean | ||
| private VersionService versionService; | ||
|
|
||
| @MockitoBean | ||
| private AppExceptionHttpStatusMapper appExceptionHttpStatusMapper; | ||
|
|
||
| @Test | ||
| void getVersion_ShouldReturnVersion_WhenCallerIsAnonymous() throws Exception { | ||
| when(versionService.getVersion()).thenReturn( | ||
| new VersionResponse( | ||
| new VersionResponse.BackendVersion( | ||
| COMMIT_ID, | ||
| SHORT_COMMIT_ID, | ||
| Instant.parse(COMMIT_TIME), | ||
| "dev", | ||
| "0.0.1-SNAPSHOT"), | ||
| Instant.parse(BUILD_TIME))); | ||
|
|
||
| mockMvc.perform(get(ENDPOINT)) | ||
| .andExpect(status().isOk()) | ||
| .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) | ||
| .andExpect(jsonPath("$.backend.commitId").value(COMMIT_ID)) | ||
| .andExpect(jsonPath("$.backend.shortCommitId").value(SHORT_COMMIT_ID)) | ||
| .andExpect(jsonPath("$.backend.commitTime").value(COMMIT_TIME)) | ||
| .andExpect(jsonPath("$.backend.branch").value("dev")) | ||
| .andExpect(jsonPath("$.backend.version").value("0.0.1-SNAPSHOT")) | ||
| .andExpect(jsonPath("$.buildTime").value(BUILD_TIME)); | ||
| } | ||
|
|
||
| @Test | ||
| void getVersion_ShouldReturnOkWithEmptyValues_WhenBuildMetadataIsMissing() throws Exception { | ||
| when(versionService.getVersion()).thenReturn( | ||
| new VersionResponse( | ||
| new VersionResponse.BackendVersion(null, null, null, null, null), | ||
| null)); | ||
|
|
||
| mockMvc.perform(get(ENDPOINT)) | ||
| .andExpect(status().isOk()) | ||
| .andExpect(jsonPath("$.backend").exists()) | ||
| .andExpect(jsonPath("$.backend.commitId").isEmpty()) | ||
| .andExpect(jsonPath("$.backend.commitTime").isEmpty()) | ||
| .andExpect(jsonPath("$.backend.branch").isEmpty()) | ||
| .andExpect(jsonPath("$.buildTime").isEmpty()); | ||
| } | ||
|
|
||
| @TestConfiguration(proxyBeanMethods = false) | ||
| @EnableWebSecurity | ||
| static class SecurityTestConfiguration { | ||
| @Bean | ||
| SecurityFilterChain securityFilterChain(HttpSecurity http) { | ||
| return http | ||
| .csrf(AbstractHttpConfigurer::disable) | ||
| .authorizeHttpRequests(authorization -> authorization | ||
| .anyRequest() | ||
| .permitAll()) | ||
| .build(); | ||
| } | ||
| } | ||
| } |
95 changes: 95 additions & 0 deletions
95
src/test/java/com/itasocialacademy/oitassist/version/service/VersionServiceImplTest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| package com.itasocialacademy.oitassist.version.service; | ||
|
|
||
| import static org.assertj.core.api.Assertions.assertThat; | ||
| import static org.mockito.Mockito.when; | ||
|
|
||
| import com.itasocialacademy.oitassist.version.dao.dto.response.VersionResponse; | ||
| import java.time.Instant; | ||
| import java.util.Properties; | ||
| import org.junit.jupiter.api.Test; | ||
| import org.junit.jupiter.api.extension.ExtendWith; | ||
| import org.mockito.Mock; | ||
| import org.mockito.junit.jupiter.MockitoExtension; | ||
| import org.springframework.beans.factory.ObjectProvider; | ||
| import org.springframework.boot.info.BuildProperties; | ||
| import org.springframework.boot.info.GitProperties; | ||
|
|
||
| @ExtendWith(MockitoExtension.class) | ||
| class VersionServiceImplTest { | ||
|
|
||
| private static final String COMMIT_ID = "3534bab24568a602605078b9264711223f218dd2"; | ||
| private static final String SHORT_COMMIT_ID = "3534bab"; | ||
| private static final String BRANCH = "dev"; | ||
| private static final String ARTIFACT_VERSION = "0.0.1-SNAPSHOT"; | ||
| private static final Instant COMMIT_TIME = Instant.parse("2026-08-19T08:22:05Z"); | ||
| private static final Instant BUILD_TIME = Instant.parse("2026-08-19T19:55:29.490Z"); | ||
|
|
||
| @Mock | ||
| private ObjectProvider<GitProperties> gitPropertiesProvider; | ||
|
|
||
| @Mock | ||
| private ObjectProvider<BuildProperties> buildPropertiesProvider; | ||
|
|
||
| @Test | ||
| void getVersion_ShouldReturnFullVersion_WhenBuildMetadataIsPresent() { | ||
| when(gitPropertiesProvider.getIfAvailable()).thenReturn(gitProperties()); | ||
| when(buildPropertiesProvider.getIfAvailable()).thenReturn(buildProperties()); | ||
|
|
||
| VersionResponse version = createService().getVersion(); | ||
|
|
||
| assertThat(version.buildTime()).isEqualTo(BUILD_TIME); | ||
| assertThat(version.backend().commitId()).isEqualTo(COMMIT_ID); | ||
| assertThat(version.backend().shortCommitId()).isEqualTo(SHORT_COMMIT_ID); | ||
| assertThat(version.backend().commitTime()).isEqualTo(COMMIT_TIME); | ||
| assertThat(version.backend().branch()).isEqualTo(BRANCH); | ||
| assertThat(version.backend().version()).isEqualTo(ARTIFACT_VERSION); | ||
| } | ||
|
|
||
| @Test | ||
| void getVersion_ShouldReturnEmptyValues_WhenBuildMetadataIsMissing() { | ||
| VersionResponse version = createService().getVersion(); | ||
|
|
||
| assertThat(version.buildTime()).isNull(); | ||
| assertThat(version.backend()).isNotNull(); | ||
| assertThat(version.backend().commitId()).isNull(); | ||
| assertThat(version.backend().shortCommitId()).isNull(); | ||
| assertThat(version.backend().commitTime()).isNull(); | ||
| assertThat(version.backend().branch()).isNull(); | ||
| assertThat(version.backend().version()).isNull(); | ||
| } | ||
|
|
||
| @Test | ||
| void getVersion_ShouldReturnCommitDataOnly_WhenBuildInfoIsMissing() { | ||
| when(gitPropertiesProvider.getIfAvailable()).thenReturn(gitProperties()); | ||
|
|
||
| VersionResponse version = createService().getVersion(); | ||
|
|
||
| assertThat(version.backend().commitId()).isEqualTo(COMMIT_ID); | ||
| assertThat(version.backend().commitTime()).isEqualTo(COMMIT_TIME); | ||
| assertThat(version.backend().branch()).isEqualTo(BRANCH); | ||
| assertThat(version.backend().version()).isNull(); | ||
| assertThat(version.buildTime()).isNull(); | ||
| } | ||
|
|
||
| private VersionServiceImpl createService() { | ||
| return new VersionServiceImpl(gitPropertiesProvider, buildPropertiesProvider); | ||
| } | ||
|
|
||
| private GitProperties gitProperties() { | ||
| Properties entries = new Properties(); | ||
| entries.setProperty("branch", BRANCH); | ||
| entries.setProperty("commit.id", COMMIT_ID); | ||
| entries.setProperty("commit.id.abbrev", SHORT_COMMIT_ID); | ||
| entries.setProperty("commit.time", COMMIT_TIME.toString()); | ||
| return new GitProperties(entries); | ||
| } | ||
|
|
||
| private BuildProperties buildProperties() { | ||
| Properties entries = new Properties(); | ||
| entries.setProperty("group", "com.ita-social-academy"); | ||
| entries.setProperty("artifact", "OITAssist"); | ||
| entries.setProperty("version", ARTIFACT_VERSION); | ||
| entries.setProperty("time", BUILD_TIME.toString()); | ||
| return new BuildProperties(entries); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.