Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ on:

env:
REGISTRY: ghcr.io
FRONTEND_REF: dev

jobs:
build:
Expand Down Expand Up @@ -73,9 +74,22 @@ jobs:
uses: actions/checkout@v4
with:
repository: ita-social-projects/oitClient
ref: dev
ref: ${{ env.FRONTEND_REF }}
path: frontend

- name: Capture frontend build metadata
run: |
COMMIT_ID=$(git -C frontend rev-parse HEAD)
COMMIT_TIME=$(date -u -d "$(git -C frontend log -1 --format=%cI)" +%Y-%m-%dT%H:%M:%SZ)
VERSION=$(node -p "require('./frontend/package.json').version || ''")
{
echo "oit.frontend.commit-id=$COMMIT_ID"
echo "oit.frontend.short-commit-id=${COMMIT_ID:0:7}"
echo "oit.frontend.commit-time=$COMMIT_TIME"
echo "oit.frontend.branch=$FRONTEND_REF"
echo "oit.frontend.version=$VERSION"
} > src/main/resources/frontend-info.properties

- name: Build frontend
run: |
cd frontend
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,7 @@ build/
.vscode/

myenv-example
/.env
/.env

# Generated by CI during the backend image build
src/main/resources/frontend-info.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.itasocialacademy.oitassist.version.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
@PropertySource(value = "classpath:frontend-info.properties", ignoreResourceNotFound = true)
public class VersionConfig {
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ public class VersionController {
@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.
Returns the build version of the running application: the commits the backend
and the bundled frontend were 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.
""")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
@Schema(description = "Build version of the running application")
public record VersionResponse(
@Schema(description = "Backend build information") BackendVersion backend,
@Schema(description = "Frontend build information") FrontendVersion frontend,
@Schema(description = "Date and time when the artifact was built") Instant buildTime) {
@Schema(description = "Backend build information")
public record BackendVersion(
Expand All @@ -19,4 +20,17 @@ public record BackendVersion(
@Schema(description = "Branch the artifact was built from", example = "dev") String branch,
@Schema(description = "Artifact version", example = "0.0.1-SNAPSHOT") String version) {
}

@Schema(description = "Frontend build information")
public record FrontendVersion(
@Schema(
description = "Full hash of the commit the frontend was built from",
example = "5164fc9928b3cfde344f3320fee540fba1f78873") String commitId,
@Schema(
description = "Short hash of the commit the frontend was built from",
example = "5164fc9") String shortCommitId,
@Schema(description = "Date and time of the commit") Instant commitTime,
@Schema(description = "Branch the frontend was built from", example = "dev") String branch,
@Schema(description = "Frontend version", example = "1.4.2") String version) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.itasocialacademy.oitassist.version.properties;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "oit.frontend")
public record FrontendVersionProperties(
String commitId,
String shortCommitId,
String commitTime,
String branch,
String version) {
public FrontendVersionProperties {
commitId = blankToNull(commitId);
shortCommitId = blankToNull(shortCommitId);
commitTime = blankToNull(commitTime);
branch = blankToNull(branch);
version = blankToNull(version);
}

private static String blankToNull(String value) {
return value == null || value.isBlank() ? null : value.strip();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.itasocialacademy.oitassist.version.service;

import com.itasocialacademy.oitassist.version.dao.dto.response.VersionResponse;
import com.itasocialacademy.oitassist.version.properties.FrontendVersionProperties;
import com.itasocialacademy.oitassist.version.service.interfaces.VersionService;
import lombok.extern.slf4j.Slf4j;
import org.jspecify.annotations.NonNull;
Expand All @@ -9,30 +10,38 @@
import org.springframework.boot.info.GitProperties;
import org.springframework.stereotype.Service;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.format.DateTimeParseException;

@Slf4j
@Service
public class VersionServiceImpl implements VersionService {
private final GitProperties gitProperties;
private final BuildProperties buildProperties;
private final FrontendVersionProperties frontendVersionProperties;

public VersionServiceImpl(
ObjectProvider<@NonNull GitProperties> gitPropertiesProvider,
ObjectProvider<@NonNull BuildProperties> buildPropertiesProvider) {
ObjectProvider<@NonNull BuildProperties> buildPropertiesProvider,
FrontendVersionProperties frontendVersionProperties) {
this.gitProperties = gitPropertiesProvider.getIfAvailable();
this.buildProperties = buildPropertiesProvider.getIfAvailable();
this.frontendVersionProperties = frontendVersionProperties;

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");
}
if (frontendVersionProperties.commitId() == null) {
log.warn("frontend-info.properties is missing, frontend build data will not be reported");
}
}

@Override
public VersionResponse getVersion() {
return new VersionResponse(getBackendVersion(), getBuildTime());
return new VersionResponse(getBackendVersion(), getFrontendVersion(), getBuildTime());
}

private VersionResponse.BackendVersion getBackendVersion() {
Expand All @@ -47,11 +56,32 @@
getArtifactVersion());
}

private VersionResponse.FrontendVersion getFrontendVersion() {
return new VersionResponse.FrontendVersion(
frontendVersionProperties.commitId(),
frontendVersionProperties.shortCommitId(),
parseCommitTime(frontendVersionProperties.commitTime()),
frontendVersionProperties.branch(),
frontendVersionProperties.version());
}

private String getArtifactVersion() {
return buildProperties == null ? null : buildProperties.getVersion();
}

private Instant getBuildTime() {
return buildProperties == null ? null : buildProperties.getTime();
}

private static Instant parseCommitTime(String commitTime) {
if (commitTime == null) {
return null;
}
try {
return OffsetDateTime.parse(commitTime).toInstant();
} catch (DateTimeParseException e) {

Check warning on line 82 in src/main/java/com/itasocialacademy/oitassist/version/service/VersionServiceImpl.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace "e" with an unnamed pattern.

See more on https://sonarcloud.io/project/issues?id=ita-social-projects_oitAssist&issues=AaAzWWfRLmq8TrQkO90O&open=AaAzWWfRLmq8TrQkO90O&pullRequest=556
log.warn("Frontend commit time '{}' is not a valid date, it will not be reported", commitTime);
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ class VersionControllerTest {
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";
private static final String FRONTEND_COMMIT_ID = "9f1c2ab7d4e58306b1c0f2a4d7e93b5c8a6d1e42";
private static final String FRONTEND_SHORT_COMMIT_ID = "9f1c2ab";
private static final String FRONTEND_COMMIT_TIME = "2026-08-21T10:15:00Z";
private static final String FRONTEND_VERSION = "1.4.2";

@Autowired
private MockMvc mockMvc;
Expand All @@ -60,6 +64,12 @@ void getVersion_ShouldReturnVersion_WhenCallerIsAnonymous() throws Exception {
Instant.parse(COMMIT_TIME),
"dev",
"0.0.1-SNAPSHOT"),
new VersionResponse.FrontendVersion(
FRONTEND_COMMIT_ID,
FRONTEND_SHORT_COMMIT_ID,
Instant.parse(FRONTEND_COMMIT_TIME),
"dev",
FRONTEND_VERSION),
Instant.parse(BUILD_TIME)));

mockMvc.perform(get(ENDPOINT))
Expand All @@ -70,6 +80,11 @@ void getVersion_ShouldReturnVersion_WhenCallerIsAnonymous() throws Exception {
.andExpect(jsonPath("$.backend.commitTime").value(COMMIT_TIME))
.andExpect(jsonPath("$.backend.branch").value("dev"))
.andExpect(jsonPath("$.backend.version").value("0.0.1-SNAPSHOT"))
.andExpect(jsonPath("$.frontend.commitId").value(FRONTEND_COMMIT_ID))
.andExpect(jsonPath("$.frontend.shortCommitId").value(FRONTEND_SHORT_COMMIT_ID))
.andExpect(jsonPath("$.frontend.commitTime").value(FRONTEND_COMMIT_TIME))
.andExpect(jsonPath("$.frontend.branch").value("dev"))
.andExpect(jsonPath("$.frontend.version").value(FRONTEND_VERSION))
.andExpect(jsonPath("$.buildTime").value(BUILD_TIME));
}

Expand All @@ -78,6 +93,7 @@ void getVersion_ShouldReturnOkWithEmptyValues_WhenBuildMetadataIsMissing() throw
when(versionService.getVersion()).thenReturn(
new VersionResponse(
new VersionResponse.BackendVersion(null, null, null, null, null),
new VersionResponse.FrontendVersion(null, null, null, null, null),
null));

mockMvc.perform(get(ENDPOINT))
Expand All @@ -86,6 +102,12 @@ void getVersion_ShouldReturnOkWithEmptyValues_WhenBuildMetadataIsMissing() throw
.andExpect(jsonPath("$.backend.commitId").isEmpty())
.andExpect(jsonPath("$.backend.commitTime").isEmpty())
.andExpect(jsonPath("$.backend.branch").isEmpty())
.andExpect(jsonPath("$.frontend").exists())
.andExpect(jsonPath("$.frontend.commitId").isEmpty())
.andExpect(jsonPath("$.frontend.shortCommitId").isEmpty())
.andExpect(jsonPath("$.frontend.commitTime").isEmpty())
.andExpect(jsonPath("$.frontend.branch").isEmpty())
.andExpect(jsonPath("$.frontend.version").isEmpty())
.andExpect(jsonPath("$.buildTime").isEmpty());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.itasocialacademy.oitassist.version.properties;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.Test;

class FrontendVersionPropertiesTest {

private static final String COMMIT_ID = "9f1c2ab7d4e58306b1c0f2a4d7e93b5c8a6d1e42";
private static final String SHORT_COMMIT_ID = "9f1c2ab";
private static final String COMMIT_TIME = "2026-08-21T10:15:00Z";
private static final String BRANCH = "dev";
private static final String VERSION = "1.4.2";

@Test
void constructor_ShouldReplaceValuesWithNull_WhenTheyAreBlank() {
FrontendVersionProperties properties = new FrontendVersionProperties("", " ", "", "", "");

assertThat(properties.commitId()).isNull();
assertThat(properties.shortCommitId()).isNull();
assertThat(properties.commitTime()).isNull();
assertThat(properties.branch()).isNull();
assertThat(properties.version()).isNull();
}

@Test
void constructor_ShouldKeepValues_WhenTheyArePresent() {
FrontendVersionProperties properties = new FrontendVersionProperties(
COMMIT_ID, SHORT_COMMIT_ID, COMMIT_TIME, BRANCH, VERSION);

assertThat(properties.commitId()).isEqualTo(COMMIT_ID);
assertThat(properties.shortCommitId()).isEqualTo(SHORT_COMMIT_ID);
assertThat(properties.commitTime()).isEqualTo(COMMIT_TIME);
assertThat(properties.branch()).isEqualTo(BRANCH);
assertThat(properties.version()).isEqualTo(VERSION);
}

@Test
void constructor_ShouldStripValues_WhenTheyAreSurroundedByWhitespace() {
FrontendVersionProperties properties = new FrontendVersionProperties(
" " + COMMIT_ID + " ",
" " + SHORT_COMMIT_ID + " ",
" " + COMMIT_TIME + " ",
" " + BRANCH + " ",
" " + VERSION + " ");

assertThat(properties.commitId()).isEqualTo(COMMIT_ID);
assertThat(properties.shortCommitId()).isEqualTo(SHORT_COMMIT_ID);
assertThat(properties.commitTime()).isEqualTo(COMMIT_TIME);
assertThat(properties.branch()).isEqualTo(BRANCH);
assertThat(properties.version()).isEqualTo(VERSION);
}
}
Loading
Loading