From 69f274702b2bd40465c6f48d8f9655d58ba3a4f3 Mon Sep 17 00:00:00 2001 From: Martin Wittlinger Date: Tue, 26 Sep 2023 21:48:07 +0200 Subject: [PATCH] refactor(infrastructure): Update code to convert from mutiny to VThreads (#1103) --- .../analyzer/spoon/SpoonBasedAnalyzer.java | 5 +- github-bot/build.gradle | 1 + .../graphql/endpoints/BadSmellGraphQL.java | 2 + .../api/graphql/endpoints/ProjectGraphQL.java | 5 +- .../graphql/endpoints/RefactorGraphQL.java | 2 + .../laughing_train/data/ProjectResult.java | 3 +- .../data/result/CodeAnalyzerResult.java | 3 +- .../mining/ProjectSupplier.java | 11 ++++ .../mining/SpoonPeriodicMiner.java | 62 +++++++++---------- .../AnalyzerResultPersistenceService.java | 30 +++------ .../services/SpoonAnalyzerService.java | 37 ++++++----- gradle.properties | 12 ++-- .../spoon_analyzer/SpoonAnalyzer.java | 7 +-- 13 files changed, 90 insertions(+), 90 deletions(-) diff --git a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/analyzer/spoon/SpoonBasedAnalyzer.java b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/analyzer/spoon/SpoonBasedAnalyzer.java index 3ac31eea8..d166f7ff7 100644 --- a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/analyzer/spoon/SpoonBasedAnalyzer.java +++ b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/analyzer/spoon/SpoonBasedAnalyzer.java @@ -5,6 +5,7 @@ import io.github.martinwitt.spoon_analyzer.SpoonAnalyzer; import java.nio.file.Path; import java.util.List; +import java.util.Optional; public class SpoonBasedAnalyzer { @@ -14,8 +15,8 @@ public List analyze(Path sourceRoot) { List analyze = analyzer.analyze(sourceRoot.toAbsolutePath().toString()); return analyze.stream() .map(analyzerResultVisitor::toAnalyzerResult) - .filter(v -> v.isPresent()) - .map(v -> v.get()) + .filter(Optional::isPresent) + .map(Optional::get) .toList(); } } diff --git a/github-bot/build.gradle b/github-bot/build.gradle index f421ee3a2..3ab29d9f7 100644 --- a/github-bot/build.gradle +++ b/github-bot/build.gradle @@ -5,6 +5,7 @@ plugins { } dependencies { + implementation 'io.quarkiverse.jgit:quarkus-jgit:3.0.5' implementation enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}") implementation 'io.quarkiverse.githubapi:quarkus-github-api:1.316.0' implementation 'io.quarkiverse.githubapp:quarkus-github-app:2.1.0' diff --git a/github-bot/src/main/java/io/github/martinwitt/laughing_train/api/graphql/endpoints/BadSmellGraphQL.java b/github-bot/src/main/java/io/github/martinwitt/laughing_train/api/graphql/endpoints/BadSmellGraphQL.java index 3aed63701..bcad7e971 100644 --- a/github-bot/src/main/java/io/github/martinwitt/laughing_train/api/graphql/endpoints/BadSmellGraphQL.java +++ b/github-bot/src/main/java/io/github/martinwitt/laughing_train/api/graphql/endpoints/BadSmellGraphQL.java @@ -7,6 +7,7 @@ import io.github.martinwitt.laughing_train.persistence.repository.ProjectRepository; import io.github.martinwitt.laughing_train.summary.GetFixableBadSmells; import io.github.martinwitt.spoon_analyzer.badsmells.SpoonRules; +import io.smallrye.common.annotation.RunOnVirtualThread; import jakarta.enterprise.context.RequestScoped; import jakarta.inject.Inject; import java.util.Arrays; @@ -18,6 +19,7 @@ @GraphQLApi @RequestScoped +@RunOnVirtualThread public class BadSmellGraphQL { @Inject BadSmellRepository badSmellRepository; diff --git a/github-bot/src/main/java/io/github/martinwitt/laughing_train/api/graphql/endpoints/ProjectGraphQL.java b/github-bot/src/main/java/io/github/martinwitt/laughing_train/api/graphql/endpoints/ProjectGraphQL.java index f1c1dd337..78664807e 100644 --- a/github-bot/src/main/java/io/github/martinwitt/laughing_train/api/graphql/endpoints/ProjectGraphQL.java +++ b/github-bot/src/main/java/io/github/martinwitt/laughing_train/api/graphql/endpoints/ProjectGraphQL.java @@ -12,7 +12,7 @@ import io.github.martinwitt.laughing_train.persistence.repository.ProjectRepository; import io.github.martinwitt.laughing_train.services.ProjectConfigService; import io.quarkus.security.Authenticated; -import io.vertx.core.Vertx; +import io.smallrye.common.annotation.RunOnVirtualThread; import jakarta.enterprise.context.RequestScoped; import jakarta.inject.Inject; import java.util.List; @@ -24,12 +24,11 @@ @GraphQLApi @RequestScoped +@RunOnVirtualThread public class ProjectGraphQL { private static final FluentLogger logger = FluentLogger.forEnclosingClass(); - @Inject Vertx vertx; - @Inject ProjectConfigService projectConfigService; @Inject ProjectRepository projectRepository; diff --git a/github-bot/src/main/java/io/github/martinwitt/laughing_train/api/graphql/endpoints/RefactorGraphQL.java b/github-bot/src/main/java/io/github/martinwitt/laughing_train/api/graphql/endpoints/RefactorGraphQL.java index 5d8dbb127..e0caf7ee4 100644 --- a/github-bot/src/main/java/io/github/martinwitt/laughing_train/api/graphql/endpoints/RefactorGraphQL.java +++ b/github-bot/src/main/java/io/github/martinwitt/laughing_train/api/graphql/endpoints/RefactorGraphQL.java @@ -6,6 +6,7 @@ import io.github.martinwitt.laughing_train.persistence.repository.BadSmellRepository; import io.github.martinwitt.laughing_train.services.RefactorService; import io.quarkus.security.Authenticated; +import io.smallrye.common.annotation.RunOnVirtualThread; import jakarta.enterprise.context.RequestScoped; import jakarta.inject.Inject; import java.util.Arrays; @@ -22,6 +23,7 @@ @GraphQLApi @RequestScoped +@RunOnVirtualThread public class RefactorGraphQL { private static final FluentLogger logger = FluentLogger.forEnclosingClass(); diff --git a/github-bot/src/main/java/io/github/martinwitt/laughing_train/data/ProjectResult.java b/github-bot/src/main/java/io/github/martinwitt/laughing_train/data/ProjectResult.java index 107fc5640..d81a4a6d3 100644 --- a/github-bot/src/main/java/io/github/martinwitt/laughing_train/data/ProjectResult.java +++ b/github-bot/src/main/java/io/github/martinwitt/laughing_train/data/ProjectResult.java @@ -2,7 +2,8 @@ import java.io.Serializable; -public sealed interface ProjectResult extends Serializable { +public sealed interface ProjectResult extends Serializable + permits ProjectResult.Success, ProjectResult.Error { record Success(Project project) implements ProjectResult {} diff --git a/github-bot/src/main/java/io/github/martinwitt/laughing_train/data/result/CodeAnalyzerResult.java b/github-bot/src/main/java/io/github/martinwitt/laughing_train/data/result/CodeAnalyzerResult.java index 261d2aa67..ee880e08f 100644 --- a/github-bot/src/main/java/io/github/martinwitt/laughing_train/data/result/CodeAnalyzerResult.java +++ b/github-bot/src/main/java/io/github/martinwitt/laughing_train/data/result/CodeAnalyzerResult.java @@ -5,7 +5,8 @@ import java.io.Serializable; import java.util.List; -public interface CodeAnalyzerResult extends Serializable { +public sealed interface CodeAnalyzerResult extends Serializable + permits CodeAnalyzerResult.Success, CodeAnalyzerResult.Failure { record Success(List results, Project project) implements CodeAnalyzerResult {} diff --git a/github-bot/src/main/java/io/github/martinwitt/laughing_train/mining/ProjectSupplier.java b/github-bot/src/main/java/io/github/martinwitt/laughing_train/mining/ProjectSupplier.java index 52032aa3f..12830cd6d 100644 --- a/github-bot/src/main/java/io/github/martinwitt/laughing_train/mining/ProjectSupplier.java +++ b/github-bot/src/main/java/io/github/martinwitt/laughing_train/mining/ProjectSupplier.java @@ -57,6 +57,17 @@ void supplyProject(Message getProject) { } } + public ProjectResult supplyProject() { + try { + RemoteProject project = getRandomProject(); + ProjectResult checkoutProject = checkoutProject(project); + Log.info("Project %s checked out".formatted(project.getProjectUrl())); + return checkoutProject; + } catch (IOException e) { + return new ProjectResult.Error(e.getMessage()); + } + } + private ProjectResult checkoutProject(RemoteProject project) throws IOException { return projectService.handleProjectRequest(new ProjectRequest.WithUrl(project.getProjectUrl())); } diff --git a/github-bot/src/main/java/io/github/martinwitt/laughing_train/mining/SpoonPeriodicMiner.java b/github-bot/src/main/java/io/github/martinwitt/laughing_train/mining/SpoonPeriodicMiner.java index f32f21fe0..0d59c9e3d 100644 --- a/github-bot/src/main/java/io/github/martinwitt/laughing_train/mining/SpoonPeriodicMiner.java +++ b/github-bot/src/main/java/io/github/martinwitt/laughing_train/mining/SpoonPeriodicMiner.java @@ -5,19 +5,18 @@ import io.github.martinwitt.laughing_train.data.ProjectResult.Success; import io.github.martinwitt.laughing_train.data.request.AnalyzerRequest; import io.github.martinwitt.laughing_train.data.result.CodeAnalyzerResult; -import io.github.martinwitt.laughing_train.mining.requests.GetProject; import io.github.martinwitt.laughing_train.mining.requests.MineNextProject; import io.github.martinwitt.laughing_train.mining.requests.StoreResults; import io.github.martinwitt.laughing_train.services.SpoonAnalyzerService; import io.quarkus.arc.Unremovable; import io.vertx.core.AbstractVerticle; -import io.vertx.core.Future; import io.vertx.core.Vertx; -import io.vertx.core.eventbus.DeliveryOptions; -import io.vertx.core.eventbus.Message; import jakarta.enterprise.context.ApplicationScoped; +import java.io.File; import java.io.IOException; -import java.util.concurrent.TimeUnit; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; import org.apache.commons.io.FileUtils; @Unremovable @@ -28,10 +27,13 @@ public class SpoonPeriodicMiner extends AbstractVerticle { public static final String ANALYZER_NAME = "spoon-analyzer"; final Vertx vertx; final SpoonAnalyzerService spoonAnalyzerService; + final ProjectSupplier projectSupplier; - public SpoonPeriodicMiner(Vertx vertx, SpoonAnalyzerService spoonAnalyzerService) { + public SpoonPeriodicMiner( + Vertx vertx, SpoonAnalyzerService spoonAnalyzerService, ProjectSupplier projectSupplier) { this.vertx = vertx; this.spoonAnalyzerService = spoonAnalyzerService; + this.projectSupplier = projectSupplier; } private CodeAnalyzerResult analyzeProjectWithSpoon(Success success) { @@ -60,34 +62,26 @@ void mineWithSpoon(MineNextProject event) { return; } logger.atInfo().log("Start mining with spoon"); - Future> request = - vertx - .eventBus() - .request( - ProjectSupplier.SERVICE_NAME, - new GetProject(ANALYZER_NAME), - new DeliveryOptions().setSendTimeout(TimeUnit.MINUTES.toMillis(5))); - request - .onSuccess( - v -> { - if (v.body() instanceof ProjectResult.Success success) { - var spoonResult = analyzeProjectWithSpoon(success); - if (spoonResult instanceof CodeAnalyzerResult.Success spoonSuccess) { - storeSuccess(success, spoonSuccess); - } else { - if (spoonResult instanceof CodeAnalyzerResult.Failure error) { - storeFailure(success, error); - } - } - FileUtils.deleteQuietly(success.project().folder()); - } - }) - .onComplete(v -> vertx.eventBus().publish("miner", new MineNextProject(ANALYZER_NAME))); - request.onFailure( - v -> { - logger.atWarning().withCause(v).log("Failed to get project"); - vertx.eventBus().publish("miner", new MineNextProject(ANALYZER_NAME)); - }); + ProjectResult projectResult = projectSupplier.supplyProject(); + switch (projectResult) { + case Success success -> { + CodeAnalyzerResult analyzerResult = analyzeProjectWithSpoon(success); + switch (analyzerResult) { + case CodeAnalyzerResult.Success spoonSuccess -> storeSuccess(success, spoonSuccess); + case CodeAnalyzerResult.Failure error -> storeFailure(success, error); + } + try (var dirStream = Files.walk(success.project().folder().toPath())) { + dirStream.map(Path::toFile).sorted(Comparator.reverseOrder()).forEach(File::delete); + } catch (IOException e) { + logger.atWarning().log("Failed to delete project " + success.project().folder()); + } + FileUtils.deleteQuietly(success.project().folder()); + } + case ProjectResult.Error error -> { + logger.atWarning().log("Failed to get project %s", error.message()); + } + } + vertx.eventBus().publish("miner", new MineNextProject(ANALYZER_NAME)); } private void storeFailure(ProjectResult.Success success, CodeAnalyzerResult.Failure error) { 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 30ee51412..a24c9cdf2 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 @@ -37,26 +37,14 @@ void persistResults(QodanaResult result) { } } - void persistResults(CodeAnalyzerResult result) { - if (result instanceof CodeAnalyzerResult.Success success) { - logger.atInfo().log( - "Persisting %s results for project %s", - success.results().size(), success.project().name()); - Project project = success.project(); - Multi.createFrom() - .iterable(success.results()) - .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 bad smells for project %s", badSmell, project.name())); - } + void persistResults(CodeAnalyzerResult.Success success) { + logger.atInfo().log( + "Persisting %s results for project %s", success.results().size(), success.project().name()); + Project project = success.project(); + success.results().stream() + .map( + badSmell -> new BadSmell(badSmell, project.name(), project.url(), project.commitHash())) + .filter(it -> badSmellRepository.findByIdentifier(it.getIdentifier()).isEmpty()) + .forEach(badSmellRepository::save); } } diff --git a/github-bot/src/main/java/io/github/martinwitt/laughing_train/services/SpoonAnalyzerService.java b/github-bot/src/main/java/io/github/martinwitt/laughing_train/services/SpoonAnalyzerService.java index f43013922..cdfba871c 100644 --- a/github-bot/src/main/java/io/github/martinwitt/laughing_train/services/SpoonAnalyzerService.java +++ b/github-bot/src/main/java/io/github/martinwitt/laughing_train/services/SpoonAnalyzerService.java @@ -28,23 +28,26 @@ public class SpoonAnalyzerService { public CodeAnalyzerResult analyze(AnalyzerRequest request) { logger.atInfo().log("Received request %s", request); try { - if (request instanceof AnalyzerRequest.WithProject project) { - File folder = project.project().folder(); - SpoonBasedAnalyzer analyzer = new SpoonBasedAnalyzer(); - List analyze = analyzer.analyze(folder.toPath()); - logger.atInfo().log( - "Spoon found %s results with the following rules: %s", - analyze.size(), - analyze.stream() - .map(v -> v.ruleID().toString()) - .distinct() - .collect(Collectors.joining(","))); - CodeAnalyzerResult.Success success = - new CodeAnalyzerResult.Success(analyze, project.project()); - analyzerResultPersistenceService.persistResults(success); - return success; - } else { - return new CodeAnalyzerResult.Failure("Unknown request type"); + switch (request) { + case AnalyzerRequest.WithProject project -> { + File folder = project.project().folder(); + SpoonBasedAnalyzer analyzer = new SpoonBasedAnalyzer(); + List analyze = analyzer.analyze(folder.toPath()); + logger.atFine().log( + "Spoon found %s results with the following rules: %s", + analyze.size(), + analyze.stream() + .map(v -> v.ruleID().toString()) + .distinct() + .collect(Collectors.joining(","))); + CodeAnalyzerResult.Success success = + new CodeAnalyzerResult.Success(analyze, project.project()); + analyzerResultPersistenceService.persistResults(success); + return success; + } + default -> { + return new CodeAnalyzerResult.Failure("Unknown request type"); + } } } catch (Throwable e) { logger.atSevere().log("Error while analyzing code analyzer %s", e.getMessage()); diff --git a/gradle.properties b/gradle.properties index bfd385135..b36781131 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,8 +1,6 @@ -org.gradle.jvmargs=--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ - --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \ - --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \ - --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \ - --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED -org.gradle.parallel=true +#Gradle properties +#Sat Sep 23 17:47:13 CEST 2023 org.gradle.caching=true -org.gradle.vfs.watch=true \ No newline at end of file +org.gradle.jvmargs=--add-exports jdk.compiler/com.sun.tools.javac.api\=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.file\=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.parser\=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.tree\=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.util\=ALL-UNNAMED +org.gradle.parallel=true +org.gradle.vfs.watch=true diff --git a/spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/SpoonAnalyzer.java b/spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/SpoonAnalyzer.java index 583fa1747..961593d7d 100644 --- a/spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/SpoonAnalyzer.java +++ b/spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/SpoonAnalyzer.java @@ -15,6 +15,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.stream.Stream; import spoon.Launcher; import spoon.reflect.declaration.CtType; @@ -42,10 +43,8 @@ public SpoonAnalyzer() { public List analyze(String path) { List badSmells = new ArrayList<>(); - try { - List files = Files.walk(Path.of(path)).filter(v -> Files.isDirectory(v)).toList(); - files = PathUtils.filterResourcePaths(files); - + try (Stream walk = Files.walk(Path.of(path))) { + List files = PathUtils.filterResourcePaths(walk.filter(Files::isDirectory).toList()); Launcher launcher = new Launcher(); for (Path p : files) { launcher.addInputResource(p.toString());