feat: remove 5-tag limit and return all tags alphabetically (#7)
* feat: remove 5-tag limit and return all tags alphabetically The /rest/home/tasks/tags endpoint previously returned only the top 5 most-used tags. This change removes that restriction so all existing tags are returned, sorted alphabetically. Fixes #6 Co-authored-by: Ricardo Campos <RMCampos@users.noreply.github.com> Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * chore: fix test issue and add log version to the right place * ci: add server ci --------- Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Ricardo Campos <RMCampos@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
committed by
GitHub
co-authored by
claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Ricardo Campos
Claude Sonnet 4.5
parent
2dc59d14d2
commit
3b335d6f1e
@@ -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
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<String> getTasksTags() {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String> getTopTasksTag() {
|
||||
logger.info("Getting top tags for the tasks");
|
||||
logger.info("Getting all tags for the tasks");
|
||||
|
||||
List<TaskResponse> tasks = taskService.getTasksByFilter("all");
|
||||
logger.info(String.format(N_TASKS_FOUND, tasks.size()));
|
||||
|
||||
Map<String, Integer> tagsCount = new HashMap<>();
|
||||
Set<String> 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<String, Integer> sortedDesc =
|
||||
tagsCount.entrySet().stream()
|
||||
.sorted(Map.Entry.<String, Integer>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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String> topTags = homeService.getTopTasksTag();
|
||||
List<String> 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
|
||||
|
||||
+11
-1
@@ -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
|
||||
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
|
||||
```
|
||||
Reference in New Issue
Block a user