Skip to content

Commit 56fdbe5

Browse files
authored
Merge pull request #42 from KamilAdd-Byte/develop
Develop
2 parents 227806b + c69485e commit 56fdbe5

12 files changed

+465
-128
lines changed

src/main/java/pl/commit/craft/controller/CommitTranslateController.java

+17
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
package pl.commit.craft.controller;
22

33
import io.swagger.v3.oas.annotations.Operation;
4+
import io.swagger.v3.oas.annotations.media.Content;
5+
import io.swagger.v3.oas.annotations.media.Schema;
6+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
7+
import io.swagger.v3.oas.annotations.responses.ApiResponses;
8+
import io.swagger.v3.oas.annotations.tags.Tag;
49
import org.springframework.web.bind.annotation.*;
510
import pl.commit.craft.service.CommitTranslateService;
611

712
@RestController
813
@RequestMapping("/api/v1/commit-translate")
14+
@Tag(name = "Commit Translation Controller", description = "Translate commit wit deepl api")
915
public class CommitTranslateController {
1016

1117
private final CommitTranslateService commitTranslateService;
@@ -18,8 +24,19 @@ public CommitTranslateController(CommitTranslateService commitTranslateService)
1824
summary = "Generate commit translation",
1925
description = "Generates a translated commit message based on the provided request information."
2026
)
27+
@ApiResponses({
28+
@ApiResponse(responseCode = "200", description = "Successfully generated commit translation",
29+
content = @Content(mediaType = "text/plain", schema = @Schema(type = "string"))),
30+
@ApiResponse(responseCode = "400", description = "Bad request, invalid input data",
31+
content = @Content(mediaType = "application/json")),
32+
@ApiResponse(responseCode = "500", description = "Internal server error",
33+
content = @Content(mediaType = "application/json"))
34+
})
2135
@PostMapping("/craft")
2236
public String generateCommit(
37+
@io.swagger.v3.oas.annotations.parameters.RequestBody(description = "Commit translation request data",
38+
required = true,
39+
content = @Content(schema = @Schema(implementation = CommitTranslateRequest.class)))
2340
@RequestBody CommitTranslateRequest commitTranslateRequest) {
2441
return commitTranslateService.generateTranslateCommit(
2542
commitTranslateRequest.major(),

src/main/java/pl/commit/craft/flow/CommitFlowController.java

+19-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
package pl.commit.craft.flow;
22

33
import io.swagger.v3.oas.annotations.Operation;
4+
import io.swagger.v3.oas.annotations.media.Content;
5+
import io.swagger.v3.oas.annotations.media.Schema;
6+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
7+
import io.swagger.v3.oas.annotations.responses.ApiResponses;
8+
import io.swagger.v3.oas.annotations.tags.Tag;
49
import org.springframework.web.bind.annotation.PostMapping;
510
import org.springframework.web.bind.annotation.RequestBody;
611
import org.springframework.web.bind.annotation.RequestMapping;
@@ -9,6 +14,7 @@
914

1015
@RestController
1116
@RequestMapping("/api/v1/commit-flow")
17+
@Tag(name = "Commit Flow Controller", description = "Flow commit")
1218
public class CommitFlowController {
1319

1420
private final CommitTranslateService commitTranslateService;
@@ -21,8 +27,20 @@ public CommitFlowController(CommitTranslateService commitTranslateService) {
2127
summary = "Generate a commit message based on the provided commit flow data",
2228
description = "This endpoint receives commit flow details and generates the corresponding commit message."
2329
)
30+
@ApiResponses({
31+
@ApiResponse(responseCode = "200", description = "Successfully generated commit message",
32+
content = @Content(mediaType = "text/plain", schema = @Schema(type = "string"))),
33+
@ApiResponse(responseCode = "400", description = "Bad request, invalid input data",
34+
content = @Content(mediaType = "application/json")),
35+
@ApiResponse(responseCode = "500", description = "Internal server error",
36+
content = @Content(mediaType = "application/json"))
37+
})
2438
@PostMapping("/craft")
25-
public String generateCommit(@RequestBody CommitFlowRequest commitFlowRequest) {
39+
public String generateCommit(
40+
@io.swagger.v3.oas.annotations.parameters.RequestBody(description = "Commit flow request data",
41+
required = true,
42+
content = @Content(schema = @Schema(implementation = CommitFlowRequest.class)))
43+
@RequestBody CommitFlowRequest commitFlowRequest) {
2644
return commitTranslateService.generateFlowCommit(
2745
commitFlowRequest.major(),
2846
commitFlowRequest.type(),

src/main/java/pl/commit/craft/template/CommitCraftTemplateController.java

+45-20
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
11
package pl.commit.craft.template;
22

33
import io.swagger.v3.oas.annotations.Operation;
4+
import io.swagger.v3.oas.annotations.media.Content;
5+
import io.swagger.v3.oas.annotations.media.Schema;
6+
import io.swagger.v3.oas.annotations.parameters.RequestBody;
47
import io.swagger.v3.oas.annotations.responses.ApiResponse;
8+
import io.swagger.v3.oas.annotations.responses.ApiResponses;
9+
import io.swagger.v3.oas.annotations.tags.Tag;
510
import lombok.RequiredArgsConstructor;
11+
import org.springframework.http.HttpStatus;
612
import org.springframework.http.ResponseEntity;
713
import org.springframework.web.bind.annotation.*;
814
import java.io.IOException;
15+
import java.util.Collections;
916
import java.util.List;
1017
import java.util.Map;
1118

1219
@RestController
1320
@RequestMapping("/api/v1/craft-template")
1421
@RequiredArgsConstructor
22+
@Tag(name = "Commit Template Controller", description = "Management template commit model")
1523
public class CommitCraftTemplateController {
1624

1725
private final CommitTemplateService commitTemplateService;
@@ -20,6 +28,11 @@ public class CommitCraftTemplateController {
2028
summary = "Get all commit templates",
2129
description = "Fetches a list of all available commit craft templates."
2230
)
31+
@ApiResponses({
32+
@ApiResponse(responseCode = "200", description = "Successfully fetched templates",
33+
content = @Content(mediaType = "application/json",
34+
schema = @Schema(implementation = CommitCraftTemplate.class)))
35+
})
2336
@GetMapping("/all")
2437
public ResponseEntity<List<CommitCraftTemplate>> getAllTemplates() throws IOException {
2538
List<CommitCraftTemplate> templates = commitTemplateService.getAllTemplates();
@@ -28,29 +41,40 @@ public ResponseEntity<List<CommitCraftTemplate>> getAllTemplates() throws IOExce
2841

2942
@Operation(
3043
summary = "Create a dedicated commit template",
31-
description = "Creates a new dedicated commit template if the pattern and model scope are valid.",
32-
responses = {
33-
@ApiResponse(responseCode = "200", description = "Template added successfully"),
34-
@ApiResponse(responseCode = "400", description = "Template already exists")
35-
}
44+
description = "Creates a new dedicated commit template if the pattern and model scope are valid."
3645
)
46+
@ApiResponses({
47+
@ApiResponse(responseCode = "201", description = "Template created successfully",
48+
content = @Content(mediaType = "application/json")),
49+
@ApiResponse(responseCode = "400", description = "Invalid template format or template already exists",
50+
content = @Content(mediaType = "application/json"))
51+
})
3752
@PostMapping("/dedicated")
38-
public ResponseEntity<String> createDedicatedTemplate(@RequestBody CommitCraftTemplate template) throws IOException {
39-
boolean patternAndModelScope = CommitDedicatedTemplateValidator.validatePatternAndModelScope(template);
40-
if (patternAndModelScope) {
41-
commitTemplateService.createDedicatedTemplate(template);
42-
return ResponseEntity.ok("Template added successfully.");
43-
}
44-
return ResponseEntity.badRequest().body("Template already exists.");
53+
public ResponseEntity<Map<String, String>> createDedicatedTemplate(
54+
@RequestBody(description = "Commit template data", required = true,
55+
content = @Content(schema = @Schema(implementation = CommitCraftTemplate.class)))
56+
@org.springframework.web.bind.annotation.RequestBody CommitCraftTemplate template) throws IOException {
57+
TemplateOperationResult result = commitTemplateService.createDedicatedTemplate(template);
58+
59+
if (result.success()) {
60+
return ResponseEntity
61+
.status(HttpStatus.CREATED)
62+
.body(Collections.singletonMap("message", result.message()));
63+
}
64+
65+
return ResponseEntity
66+
.status(HttpStatus.BAD_REQUEST)
67+
.body(Collections.singletonMap("error", result.message()));
4568
}
4669

4770
@Operation(
4871
summary = "Remove a commit template",
49-
description = "Removes a dedicated commit template by name.",
50-
responses = {
51-
@ApiResponse(responseCode = "200", description = "Template removed successfully")
52-
}
72+
description = "Removes a dedicated commit template by name."
5373
)
74+
@ApiResponses({
75+
@ApiResponse(responseCode = "200", description = "Template removed successfully",
76+
content = @Content(mediaType = "text/plain"))
77+
})
5478
@DeleteMapping("/removed/{name}")
5579
public ResponseEntity<String> addTemplate(@PathVariable("name") String name) throws IOException {
5680
commitTemplateService.removeDedicatedTemplate(name);
@@ -59,11 +83,12 @@ public ResponseEntity<String> addTemplate(@PathVariable("name") String name) thr
5983

6084
@Operation(
6185
summary = "Generate commit template JSON",
62-
description = "Generates a JSON representation of the commit template based on its name.",
63-
responses = {
64-
@ApiResponse(responseCode = "200", description = "JSON generated successfully")
65-
}
86+
description = "Generates a JSON representation of the commit template based on its name."
6687
)
88+
@ApiResponses({
89+
@ApiResponse(responseCode = "200", description = "JSON generated successfully",
90+
content = @Content(mediaType = "application/json"))
91+
})
6792
@PostMapping("/generate-json/{name}")
6893
public Map<String, Object> generateJson(@PathVariable String name) throws IOException {
6994
CommitCraftJson commitCraftJson = commitTemplateService.prepareJsonByModel(name);
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,79 @@
11
package pl.commit.craft.template;
22

33
import lombok.extern.slf4j.Slf4j;
4-
import java.util.Map;
4+
import java.util.HashSet;
55
import java.util.Set;
6+
import java.util.regex.Matcher;
7+
import java.util.regex.Pattern;
8+
import java.util.stream.Collectors;
69

710
@Slf4j
811
class CommitDedicatedTemplateValidator {
9-
private static final String PATTERN_VALIDATE_MODEL = "\\{(\\w+)\\}(-\\{(\\w+)\\})*";
12+
private static final String PLACEHOLDER_REGEX = "\\{(\\w+)\\}";
13+
private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile(PLACEHOLDER_REGEX);
1014

11-
static boolean validatePatternAndModelScope(CommitCraftTemplate template) {
12-
log.info("Validating pattern and model scope starting");
13-
String pattern = template.getPattern();
14-
Map<String, Object> model = template.getModel();
15+
/**
16+
* For backward compatibility
17+
*/
18+
public static boolean validatePatternAndModelScope(CommitCraftTemplate template) {
19+
return validatePatternAndModelScopeDetailed(template).isValid();
20+
}
1521

16-
Set<String> modelKeys = model.keySet();
22+
/**
23+
* Validates that all keys in the model exist in the pattern and vice versa.
24+
*
25+
* @param template The commit template to validate
26+
* @return result of validation with details about any mismatches
27+
*/
28+
public static ValidationResult validatePatternAndModelScopeDetailed(CommitCraftTemplate template) {
29+
log.info("Validating pattern and model scope starting for template: {}", template.getName());
1730

18-
boolean matches = true;
19-
for (String key : modelKeys) {
20-
if (!pattern.contains(key)) {
21-
log.warn("Pattern is missing key: {}", key);
22-
matches = false;
23-
}
24-
}
31+
Set<String> modelKeys = template.getModel().keySet();
32+
Set<String> patternKeys = extractPlaceholdersFromPattern(template.getPattern());
2533

26-
String[] patternWords = pattern.split(PATTERN_VALIDATE_MODEL);
27-
for (String word : patternWords) {
28-
if (!modelKeys.contains(word)) {
29-
log.warn("Pattern contains an extra key not in the model: {}", word);
30-
matches = false;
31-
}
32-
}
34+
Set<String> missingInPattern = findMissingKeys(modelKeys, patternKeys);
35+
Set<String> extraInPattern = findMissingKeys(patternKeys, modelKeys);
36+
37+
boolean isValid = missingInPattern.isEmpty() && extraInPattern.isEmpty();
3338

34-
if (matches) {
39+
if (isValid) {
3540
log.info("Pattern matches the model keys.");
41+
return ValidationResult.valid();
3642
} else {
37-
log.warn("Pattern does not match the model keys.");
43+
if (!missingInPattern.isEmpty()) {
44+
log.warn("Pattern is missing keys: {}", missingInPattern);
45+
}
46+
if (!extraInPattern.isEmpty()) {
47+
log.warn("Pattern contains extra keys not in the model: {}", extraInPattern);
48+
}
49+
return ValidationResult.invalid(missingInPattern, extraInPattern);
3850
}
51+
}
52+
53+
54+
/**
55+
* Extracts all placeholder keys from the pattern string.
56+
*
57+
* @param pattern The pattern string containing placeholders
58+
* @return A set of placeholder keys
59+
*/
60+
private static Set<String> extractPlaceholdersFromPattern(String pattern) {
61+
Set<String> patternKeys = new HashSet<>();
62+
Matcher matcher = PLACEHOLDER_PATTERN.matcher(pattern);
63+
64+
while (matcher.find()) {
65+
patternKeys.add(matcher.group(1));
66+
}
67+
68+
return patternKeys;
69+
}
3970

40-
return matches;
71+
/**
72+
* Finds keys that are in the first set but not in the second set
73+
*/
74+
private static Set<String> findMissingKeys(Set<String> sourceKeys, Set<String> targetKeys) {
75+
return sourceKeys.stream()
76+
.filter(key -> !targetKeys.contains(key))
77+
.collect(Collectors.toSet());
4178
}
4279
}

src/main/java/pl/commit/craft/template/CommitTemplateService.java

+53-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.fasterxml.jackson.databind.node.ArrayNode;
77
import com.fasterxml.jackson.databind.node.ObjectNode;
88
import lombok.RequiredArgsConstructor;
9+
import lombok.extern.slf4j.Slf4j;
910
import org.springframework.stereotype.Service;
1011
import java.io.File;
1112
import java.io.IOException;
@@ -14,6 +15,7 @@
1415
import java.util.List;
1516
import java.util.Map;
1617

18+
@Slf4j
1719
@Service
1820
@RequiredArgsConstructor
1921
class CommitTemplateService {
@@ -78,10 +80,57 @@ public List<CommitCraftTemplate> readTemplates() throws IOException {
7880
});
7981
}
8082

81-
public void createDedicatedTemplate(CommitCraftTemplate newTemplate) throws IOException {
82-
List<CommitCraftTemplate> templates = readTemplates();
83-
templates.add(newTemplate);
84-
saveTemplates(templates);
83+
/**
84+
* Creates a dedicated template after validating it.
85+
*
86+
* @param template The template to create
87+
* @return Result containing success/failure status and a message
88+
* @throws IOException If there's an issue accessing the template storage
89+
*/
90+
public TemplateOperationResult createDedicatedTemplate(CommitCraftTemplate template) throws IOException {
91+
ValidationResult validationResult =
92+
CommitDedicatedTemplateValidator.validatePatternAndModelScopeDetailed(template);
93+
94+
if (!validationResult.isValid()) {
95+
String errorMessage = validationResult.getErrorMessage();
96+
log.warn("Template validation failed: {}", errorMessage);
97+
return new TemplateOperationResult(false, errorMessage);
98+
}
99+
100+
if (templateExists(template.getName())) {
101+
log.warn("Template with name '{}' already exists", template.getName());
102+
return new TemplateOperationResult(false, "Template with name '" + template.getName() + "' already exists");
103+
}
104+
105+
saveTemplate(template);
106+
log.info("Template '{}' created successfully", template.getName());
107+
return new TemplateOperationResult(true, "Template created successfully");
108+
}
109+
110+
/**
111+
* Checks if a template with the given name already exists
112+
*
113+
* @param templateName Name of the template to check
114+
* @return true if the template exists, false otherwise
115+
* @throws IOException If there's an issue accessing the template storage
116+
*/
117+
private boolean templateExists(String templateName) throws IOException {
118+
List<CommitCraftTemplate> existingTemplates = getAllTemplates();
119+
return existingTemplates.stream()
120+
.anyMatch(template -> template.getName().equals(templateName));
121+
}
122+
123+
/**
124+
* Saves a new template to the dedicated templates file
125+
*
126+
* @param template The template to save
127+
* @throws IOException If there's an issue accessing or writing to the template storage
128+
*/
129+
private void saveTemplate(CommitCraftTemplate template) throws IOException {
130+
List<CommitCraftTemplate> existingTemplates = readTemplates();
131+
existingTemplates.add(template);
132+
saveTemplates(existingTemplates);
133+
log.debug("Template saved successfully: {}", template.getName());
85134
}
86135

87136
public void removeDedicatedTemplate(String dedicatedTemplateName) throws IOException {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package pl.commit.craft.template;
2+
3+
record TemplateOperationResult(boolean success, String message) {
4+
}

0 commit comments

Comments
 (0)