diff --git a/.github/workflows/server-ci.yml b/.github/workflows/server-ci.yml new file mode 100644 index 0000000..67f60ec --- /dev/null +++ b/.github/workflows/server-ci.yml @@ -0,0 +1,43 @@ +name: Server API CI + +on: + workflow_dispatch: + # run for all pushes, not only main + push: + branches: + - '**' + paths: + - 'server/**/*.java' + - 'server/**/*.xml' + - 'server/pom.xml' + +jobs: + run-checks: + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - name: Checkout code + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '21' + cache: 'maven' + + - name: Run Check Style + working-directory: ./server + run: ./mvnw --no-transfer-progress checkstyle:check -Dcheckstyle.skip=false + + - name: Run build + working-directory: ./server + run: ./mvnw --no-transfer-progress clean compile -DskipTests + + - name: Run tests + working-directory: ./server + run: ./mvnw --no-transfer-progress clean verify -P tests --file pom.xml diff --git a/server/src/main/java/br/com/tasknoteapp/server/JavaApiApplication.java b/server/src/main/java/br/com/tasknoteapp/server/JavaApiApplication.java index d5dae2c..2579941 100644 --- a/server/src/main/java/br/com/tasknoteapp/server/JavaApiApplication.java +++ b/server/src/main/java/br/com/tasknoteapp/server/JavaApiApplication.java @@ -1,23 +1,11 @@ package br.com.tasknoteapp.server; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.ApplicationArguments; -import org.springframework.boot.ApplicationRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import br.com.tasknoteapp.server.service.AppVersionService; - /** Entrypoint of the Java API service application. */ @SpringBootApplication -public class JavaApiApplication implements ApplicationRunner { - - private static final Logger logger = LoggerFactory.getLogger(JavaApiApplication.class); - - @Autowired - private AppVersionService appVersionService; +public class JavaApiApplication { /** * Main method of the application. @@ -27,9 +15,4 @@ public class JavaApiApplication implements ApplicationRunner { public static void main(String[] args) { SpringApplication.run(JavaApiApplication.class, args); } - - @Override - public void run(ApplicationArguments args) throws Exception { - logger.info("Task Note API started successfully - Version: {}", appVersionService.getVersion()); - } } diff --git a/server/src/main/java/br/com/tasknoteapp/server/controller/HealthController.java b/server/src/main/java/br/com/tasknoteapp/server/controller/HealthController.java index d22ab31..a0c610d 100644 --- a/server/src/main/java/br/com/tasknoteapp/server/controller/HealthController.java +++ b/server/src/main/java/br/com/tasknoteapp/server/controller/HealthController.java @@ -1,5 +1,6 @@ package br.com.tasknoteapp.server.controller; +import br.com.tasknoteapp.server.service.AppVersionService; import java.sql.Connection; import java.util.HashMap; import java.util.Map; @@ -10,8 +11,6 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import br.com.tasknoteapp.server.service.AppVersionService; - /** Controller to handle health check requests. */ @RestController public class HealthController { diff --git a/server/src/main/java/br/com/tasknoteapp/server/controller/HomeController.java b/server/src/main/java/br/com/tasknoteapp/server/controller/HomeController.java index 567baa8..4346457 100644 --- a/server/src/main/java/br/com/tasknoteapp/server/controller/HomeController.java +++ b/server/src/main/java/br/com/tasknoteapp/server/controller/HomeController.java @@ -18,9 +18,9 @@ public class HomeController { } /** - * Get the top 5 tags. + * Get all existing tags, ordered alphabetically. * - * @returns List of String with the tags. + * @return List of String with the tags. */ @GetMapping("/tasks/tags") public List getTasksTags() { diff --git a/server/src/main/java/br/com/tasknoteapp/server/service/AppVersionService.java b/server/src/main/java/br/com/tasknoteapp/server/service/AppVersionService.java index 815d530..a8b7707 100644 --- a/server/src/main/java/br/com/tasknoteapp/server/service/AppVersionService.java +++ b/server/src/main/java/br/com/tasknoteapp/server/service/AppVersionService.java @@ -1,12 +1,20 @@ package br.com.tasknoteapp.server.service; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.info.BuildProperties; +import org.springframework.context.event.EventListener; +import org.springframework.lang.Nullable; import org.springframework.stereotype.Service; /** Service to retrieve application version information. */ @Service public class AppVersionService { + private static final Logger logger = LoggerFactory.getLogger(AppVersionService.class); + private final BuildProperties buildProperties; /** @@ -14,16 +22,25 @@ public class AppVersionService { * * @param buildProperties the build properties injected by Spring Boot */ - public AppVersionService(BuildProperties buildProperties) { + public AppVersionService(@Autowired(required = false) @Nullable BuildProperties buildProperties) { this.buildProperties = buildProperties; } + /** Logs the application version once the application context is fully started. */ + @EventListener(ApplicationReadyEvent.class) + public void onApplicationReady() { + logger.info("Task Note API started successfully - Version: {}", getVersion()); + } + /** * Retrieves the application version combined with the build time. * * @return a string representing the application version and build time */ public String getVersion() { + if (buildProperties == null) { + return "unknown"; + } return buildProperties.getVersion() + "-" + buildProperties.getTime(); } } diff --git a/server/src/main/java/br/com/tasknoteapp/server/service/HomeService.java b/server/src/main/java/br/com/tasknoteapp/server/service/HomeService.java index 99c8d46..f8cf104 100644 --- a/server/src/main/java/br/com/tasknoteapp/server/service/HomeService.java +++ b/server/src/main/java/br/com/tasknoteapp/server/service/HomeService.java @@ -1,11 +1,9 @@ package br.com.tasknoteapp.server.service; import br.com.tasknoteapp.server.response.TaskResponse; -import java.util.HashMap; -import java.util.LinkedHashMap; +import java.util.HashSet; import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; +import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; @@ -25,37 +23,25 @@ public class HomeService { } /** - * Get up to 5 most used tags. + * Get all existing tags, ordered alphabetically. * * @return List of String with the tags. */ public List getTopTasksTag() { - logger.info("Getting top tags for the tasks"); + logger.info("Getting all tags for the tasks"); List tasks = taskService.getTasksByFilter("all"); logger.info(String.format(N_TASKS_FOUND, tasks.size())); - Map tagsCount = new HashMap<>(); + Set tags = new HashSet<>(); for (TaskResponse task : tasks) { - if (tagsCount.size() == 5) { - break; - } - String tag = task.tag(); if (tag.isBlank()) { tag = "untagged"; } - tagsCount.putIfAbsent(tag, 0); - tagsCount.put(tag, tagsCount.get(tag) + 1); + tags.add(tag); } - Map sortedDesc = - tagsCount.entrySet().stream() - .sorted(Map.Entry.comparingByValue().reversed()) - .collect( - Collectors.toMap( - Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); - - return sortedDesc.keySet().stream().toList(); + return tags.stream().sorted().toList(); } } diff --git a/server/src/test/java/br/com/tasknoteapp/server/service/HomeServiceTest.java b/server/src/test/java/br/com/tasknoteapp/server/service/HomeServiceTest.java index 4550fe1..861806e 100644 --- a/server/src/test/java/br/com/tasknoteapp/server/service/HomeServiceTest.java +++ b/server/src/test/java/br/com/tasknoteapp/server/service/HomeServiceTest.java @@ -32,8 +32,8 @@ class HomeServiceTest { } @Test - @DisplayName("Get top tasks tag should return up to 5 most used tags") - void getTopTasksTag_shouldReturnTopTags() { + @DisplayName("Get tasks tags should return all tags ordered alphabetically") + void getTopTasksTag_shouldReturnAllTagsAlphabetically() { TaskResponse task1 = new TaskResponse(1L, "Task 1", false, false, null, null, null, "tag1", List.of()); TaskResponse task2 = @@ -54,15 +54,11 @@ class HomeServiceTest { when(taskService.getTasksByFilter("all")) .thenReturn(List.of(task1, task2, task3, task4, task5, task6, task7, task8)); - List topTags = homeService.getTopTasksTag(); + List tags = homeService.getTopTasksTag(); - Assertions.assertNotNull(topTags); - Assertions.assertEquals(5, topTags.size()); - Assertions.assertTrue(topTags.contains("tag1")); - Assertions.assertTrue(topTags.contains("tag2")); - Assertions.assertTrue(topTags.contains("tag3")); - Assertions.assertTrue(topTags.contains("tag4")); - Assertions.assertTrue(topTags.contains("tag5")); + Assertions.assertNotNull(tags); + Assertions.assertEquals(6, tags.size()); + Assertions.assertEquals(List.of("tag1", "tag2", "tag3", "tag4", "tag5", "tag6"), tags); } @Test diff --git a/tools/tools.md b/tools/tools.md index 8e66604..c89636e 100644 --- a/tools/tools.md +++ b/tools/tools.md @@ -170,4 +170,14 @@ docker run --rm -p 8080:8080 \ -e CORS_ALLOWED_ORIGINS=http://localhost:5000 \ -e SERVER_SERVLET_CONTEXT_PATH=/ \ --network host \ - docker.io/rmcampos/tasknote:api-latest \ No newline at end of file + docker.io/rmcampos/tasknote:api-latest + +## Running a single class test file + +``` +# For a single class +mvn test -P test -Dtest=YourTestClassName + +# For a single class method +mvn test -P test -Dtest=YourTestClassName#method +``` \ No newline at end of file