From 74b5b209b355cf61cb491df2148b69b9023ffb5a Mon Sep 17 00:00:00 2001 From: Martin Wittlinger Date: Sat, 10 Jun 2023 01:05:33 +0200 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=F0=9F=9A=91=EF=B8=8F=20Fix=20FileSy?= =?UTF-8?q?stemnotFound=20for=20resource=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../analyzer/spoon/TemplateHelper.java | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/analyzer/spoon/TemplateHelper.java b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/analyzer/spoon/TemplateHelper.java index c44c0d1db..df7a05aaf 100644 --- a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/analyzer/spoon/TemplateHelper.java +++ b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/analyzer/spoon/TemplateHelper.java @@ -1,9 +1,7 @@ package xyz.keksdose.spoon.code_solver.analyzer.spoon; import com.google.common.flogger.FluentLogger; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; +import java.io.InputStream; import spoon.Launcher; import spoon.reflect.declaration.CtType; import spoon.support.compiler.VirtualFile; @@ -15,15 +13,11 @@ private TemplateHelper() {} public static CtType fromResource(String resource) { ClassLoader classLoader = TemplateHelper.class.getClassLoader(); - URL resourceUrl = classLoader.getResource(resource); - if (resourceUrl == null) { - logger.atSevere().log("Resource not found: %s", resource); - throw new IllegalArgumentException("Resource not found: " + resource); - } - try { - String content = Files.readString(Path.of(resourceUrl.toURI())); + try (InputStream inputStream = classLoader.getResourceAsStream(resource); ) { + byte[] content = inputStream.readAllBytes(); + String contentString = new String(content); Launcher launcher = new Launcher(); - VirtualFile file = new VirtualFile(content, "Test"); + VirtualFile file = new VirtualFile(contentString, "Test"); launcher.addInputResource(file); var model = launcher.buildModel(); return model.getAllTypes().iterator().next(); From ad45d2b50309038f565f748ceaa07e3f0e0b5aa1 Mon Sep 17 00:00:00 2001 From: Martin Wittlinger Date: Sat, 10 Jun 2023 02:21:24 +0200 Subject: [PATCH 2/2] =?UTF-8?q?feat(pattern):=20=E2=9C=A8=20Persist=20spoo?= =?UTF-8?q?n=20pattern=20results=20and=20expose=20them=20in=20the=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../analyzer/spoon/SpoonAnalyzer.java | 5 ++-- .../api/graphql/dto/BadSmellGraphQLDto.java | 15 ++++++++++++ .../data/SpoonPatternAnalyzerResult.java | 4 ++-- .../laughing_train/mining/PeriodicMiner.java | 6 +++-- .../AnalyzerResultPersistenceService.java | 23 +++++++++++++++++-- .../services/SpoonPatternAnalyzer.java | 8 ++++++- .../api/BadSmellGraphQLTest.java | 10 ++++---- .../data/SpoonPatternAnalyzerResultTest.java | 11 ++++----- 8 files changed, 60 insertions(+), 22 deletions(-) diff --git a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/analyzer/spoon/SpoonAnalyzer.java b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/analyzer/spoon/SpoonAnalyzer.java index b76fdf6d2..238e08a9c 100644 --- a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/analyzer/spoon/SpoonAnalyzer.java +++ b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/analyzer/spoon/SpoonAnalyzer.java @@ -1,7 +1,6 @@ package xyz.keksdose.spoon.code_solver.analyzer.spoon; import com.google.common.flogger.FluentLogger; -import io.github.martinwitt.laughing_train.domain.entity.AnalyzerResult; import java.nio.file.Path; import java.util.Arrays; import java.util.List; @@ -14,11 +13,11 @@ public class SpoonAnalyzer { private static final FluentLogger logger = FluentLogger.forEnclosingClass(); - public List analyze(Path path) { + public List analyze(Path path) { logger.atInfo().log("Received request for SpoonAnalyzer with path %s", path.toString()); CtModel model = buildModel(path); - List list = model.getAllTypes().stream() + List list = model.getAllTypes().stream() .flatMap(v -> analyzeType(v).stream()) .collect(Collectors.toList()); logger.atInfo().log("SpoonAnalyzer finished with %d results", list.size()); diff --git a/github-bot/src/main/java/io/github/martinwitt/laughing_train/api/graphql/dto/BadSmellGraphQLDto.java b/github-bot/src/main/java/io/github/martinwitt/laughing_train/api/graphql/dto/BadSmellGraphQLDto.java index 04a589d40..062e12e1e 100644 --- a/github-bot/src/main/java/io/github/martinwitt/laughing_train/api/graphql/dto/BadSmellGraphQLDto.java +++ b/github-bot/src/main/java/io/github/martinwitt/laughing_train/api/graphql/dto/BadSmellGraphQLDto.java @@ -8,6 +8,7 @@ @Name("BadSmell") public class BadSmellGraphQLDto { + private String analyzer; private String identifier; private String name; private String messageMarkdown; @@ -29,6 +30,7 @@ public BadSmellGraphQLDto(BadSmell badSmell) { this.commitHashes = List.of(badSmell.getCommitHash()); this.filePath = badSmell.filePath(); this.position = badSmell.position(); + this.analyzer = badSmell.getAnalyzer(); } /** @@ -142,4 +144,17 @@ public Position getPosition() { public void setPosition(Position position) { this.position = position; } + + /** + * @return the analyzer + */ + public String getAnalyzer() { + return analyzer; + } + /** + * @param analyzer the analyzer to set + */ + public void setAnalyzer(String analyzer) { + this.analyzer = analyzer; + } } diff --git a/github-bot/src/main/java/io/github/martinwitt/laughing_train/data/SpoonPatternAnalyzerResult.java b/github-bot/src/main/java/io/github/martinwitt/laughing_train/data/SpoonPatternAnalyzerResult.java index e4f224f8f..fc3487696 100644 --- a/github-bot/src/main/java/io/github/martinwitt/laughing_train/data/SpoonPatternAnalyzerResult.java +++ b/github-bot/src/main/java/io/github/martinwitt/laughing_train/data/SpoonPatternAnalyzerResult.java @@ -1,11 +1,11 @@ package io.github.martinwitt.laughing_train.data; -import io.github.martinwitt.laughing_train.domain.entity.AnalyzerResult; import java.io.Serializable; import java.util.List; +import xyz.keksdose.spoon.code_solver.analyzer.spoon.SpoonAnalyzerResult; public sealed interface SpoonPatternAnalyzerResult extends Serializable { - record Success(List result, Project project) implements SpoonPatternAnalyzerResult {} + record Success(List result, Project project) implements SpoonPatternAnalyzerResult {} record Failure(String message) implements SpoonPatternAnalyzerResult {} } diff --git a/github-bot/src/main/java/io/github/martinwitt/laughing_train/mining/PeriodicMiner.java b/github-bot/src/main/java/io/github/martinwitt/laughing_train/mining/PeriodicMiner.java index fe935e2f1..8343f2e72 100644 --- a/github-bot/src/main/java/io/github/martinwitt/laughing_train/mining/PeriodicMiner.java +++ b/github-bot/src/main/java/io/github/martinwitt/laughing_train/mining/PeriodicMiner.java @@ -25,6 +25,7 @@ import java.util.Queue; import java.util.Random; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import org.apache.commons.io.FileUtils; import org.kohsuke.github.GHRepository; import org.kohsuke.github.GitHub; @@ -133,12 +134,13 @@ private void mineRandomRepo() { private void saveSpoonResults(Success spoonSuccess) { spoonSuccess.project().runInContext(() -> { try { - List results = spoonSuccess.result(); + List results = spoonSuccess.result(); if (results.isEmpty()) { logger.atInfo().log("No results for %s", spoonSuccess); return Optional.empty(); } - String content = printFormattedResults(spoonSuccess, results); + var list = results.stream().map(v -> (AnalyzerResult) v).collect(Collectors.toList()); + String content = printFormattedResults(spoonSuccess, list); var laughingRepo = getLaughingRepo(); updateOrCreateContent(laughingRepo, spoonSuccess.project().name(), content); } catch (Exception e) { diff --git a/github-bot/src/main/java/io/github/martinwitt/laughing_train/services/AnalyzerResultPersistenceService.java b/github-bot/src/main/java/io/github/martinwitt/laughing_train/services/AnalyzerResultPersistenceService.java index bc942fca1..ec5e0c07b 100644 --- a/github-bot/src/main/java/io/github/martinwitt/laughing_train/services/AnalyzerResultPersistenceService.java +++ b/github-bot/src/main/java/io/github/martinwitt/laughing_train/services/AnalyzerResultPersistenceService.java @@ -3,6 +3,7 @@ import com.google.common.flogger.FluentLogger; import io.github.martinwitt.laughing_train.data.Project; import io.github.martinwitt.laughing_train.data.QodanaResult; +import io.github.martinwitt.laughing_train.data.SpoonPatternAnalyzerResult; import io.github.martinwitt.laughing_train.persistence.BadSmell; import io.github.martinwitt.laughing_train.persistence.repository.BadSmellRepository; import io.smallrye.mutiny.Multi; @@ -30,8 +31,26 @@ void persistResults(QodanaResult result) { .collect() .with(Collectors.counting()) .subscribe() - .with(badSmell -> - logger.atInfo().log("Persisted %d bad smells for project %s", badSmell, project.name())); + .with(badSmell -> logger.atInfo().log( + "Persisted %d qodana bad smells for project %s", badSmell, project.name())); + } + } + + void persistResults(SpoonPatternAnalyzerResult result) { + if (result instanceof SpoonPatternAnalyzerResult.Success success) { + Project project = success.project(); + Multi.createFrom() + .iterable(success.result()) + .map(badSmell -> new BadSmell(badSmell, project.name(), project.url(), project.commitHash())) + .filter(v -> badSmellRepository + .findByIdentifier(v.getIdentifier()) + .isEmpty()) + .map(badSmellRepository::save) + .collect() + .with(Collectors.counting()) + .subscribe() + .with(badSmell -> logger.atInfo().log( + "Persisted %d spoon bad smells for project %s", badSmell, project.name())); } } } diff --git a/github-bot/src/main/java/io/github/martinwitt/laughing_train/services/SpoonPatternAnalyzer.java b/github-bot/src/main/java/io/github/martinwitt/laughing_train/services/SpoonPatternAnalyzer.java index 4e8a73114..8dde2bdb5 100644 --- a/github-bot/src/main/java/io/github/martinwitt/laughing_train/services/SpoonPatternAnalyzer.java +++ b/github-bot/src/main/java/io/github/martinwitt/laughing_train/services/SpoonPatternAnalyzer.java @@ -35,8 +35,10 @@ public SpoonPatternAnalyzerResult analyze(AnalyzerRequest request) { if (request instanceof AnalyzerRequest.WithProject project) { SpoonAnalyzer analyzer = new SpoonAnalyzer(); - return new SpoonPatternAnalyzerResult.Success( + SpoonPatternAnalyzerResult.Success success = new SpoonPatternAnalyzerResult.Success( analyzer.analyze(project.project().folder().toPath()), project.project()); + persistResults(success); + return success; } else { return new SpoonPatternAnalyzerResult.Failure("Unknown request type"); } @@ -45,6 +47,10 @@ public SpoonPatternAnalyzerResult analyze(AnalyzerRequest request) { } } + private void persistResults(SpoonPatternAnalyzerResult result) { + analyzerResultPersistenceService.persistResults(result); + } + @Readiness @ApplicationScoped private static class HealthCheck implements AsyncHealthCheck { diff --git a/github-bot/src/test/java/io/github/martinwitt/laughing_train/api/BadSmellGraphQLTest.java b/github-bot/src/test/java/io/github/martinwitt/laughing_train/api/BadSmellGraphQLTest.java index df8266834..3dd544803 100644 --- a/github-bot/src/test/java/io/github/martinwitt/laughing_train/api/BadSmellGraphQLTest.java +++ b/github-bot/src/test/java/io/github/martinwitt/laughing_train/api/BadSmellGraphQLTest.java @@ -21,7 +21,6 @@ import io.smallrye.graphql.client.dynamic.api.DynamicGraphQLClientBuilder; import jakarta.inject.Inject; import java.util.regex.Pattern; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @QuarkusTest @@ -59,7 +58,6 @@ private BadSmell createWithMessage(String ruleID) { } @Test - @Disabled("Only for local testing") void getBadSmellFromLive() throws Exception { client = DynamicGraphQLClientBuilder.newBuilder() .url("https://laughing-train.keksdose.xyz/graphql") @@ -69,11 +67,11 @@ void getBadSmellFromLive() throws Exception { OperationType.QUERY, field( "byRuleID", - Argument.args(Argument.arg("ruleID", "InnerClassMayBeStatic")), + Argument.args(Argument.arg("ruleID", "UNNECESSARY_TOSTRING_CALL")), field("ruleID"), - field("message"), - field("projectName"), - field("filePath"), + field("name"), + field("identifier"), + field("messageMarkdown"), field("position", field("startLine"))))); Response response = client.executeSync(document); System.out.println(response.getData().toString().replaceAll(Pattern.quote("},{"), "\n")); diff --git a/github-bot/src/test/java/io/github/martinwitt/laughing_train/data/SpoonPatternAnalyzerResultTest.java b/github-bot/src/test/java/io/github/martinwitt/laughing_train/data/SpoonPatternAnalyzerResultTest.java index 13b668a5b..5e56d2898 100644 --- a/github-bot/src/test/java/io/github/martinwitt/laughing_train/data/SpoonPatternAnalyzerResultTest.java +++ b/github-bot/src/test/java/io/github/martinwitt/laughing_train/data/SpoonPatternAnalyzerResultTest.java @@ -2,20 +2,19 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -import io.github.martinwitt.laughing_train.domain.entity.AnalyzerResult; -import io.github.martinwitt.laughing_train.domain.value.Position; -import io.github.martinwitt.laughing_train.utils.TestAnalyzerResult; import java.util.List; +import org.instancio.Instancio; import org.junit.jupiter.api.Test; +import xyz.keksdose.spoon.code_solver.analyzer.spoon.SpoonAnalyzerResult; public class SpoonPatternAnalyzerResultTest { @Test public void testSuccessRecord() { Project project = new Project("test-owner", "test-name", null, "test-url", "#9999"); - AnalyzerResult result1 = new TestAnalyzerResult("test-rule-1", new Position(0, 0, 0, 0, 0, 0)); - AnalyzerResult result2 = new TestAnalyzerResult("test-rule-2", new Position(0, 0, 0, 0, 0, 0)); - List results = List.of(result1, result2); + SpoonAnalyzerResult result1 = Instancio.create(SpoonAnalyzerResult.class); + SpoonAnalyzerResult result2 = Instancio.create(SpoonAnalyzerResult.class); + List results = List.of(result1, result2); SpoonPatternAnalyzerResult.Success success = new SpoonPatternAnalyzerResult.Success(results, project); assertEquals(results, success.result()); assertEquals(project, success.project());