Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Refactor spoon/qodana mining to event based strategy #829

Merged
merged 4 commits into from
Jul 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ dependencies {
// Use JUnit Jupiter for testing.
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.3'
implementation 'com.google.guava:guava:32.1.1-jre'
implementation 'fr.inria.gforge.spoon:spoon-core:+'
implementation 'fr.inria.gforge.spoon:spoon-core:10.4.0'
implementation 'com.google.flogger:flogger:0.7.4'
implementation 'com.google.flogger:flogger-system-backend:0.7.4'
implementation group: 'ch.qos.logback', name: 'logback-core', version: '1.4.8'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,8 @@ public ProjectGraphQLDto addProject(String projectUrl, String projectName) {
if (!projectRepository.existsByProjectUrl(projectUrl)) {
logger.atInfo().log("Project does not exist yet, creating it");
Project project = new Project(projectUrl, projectName);
periodicMiner.addToQueue(project);
return mapToDto(projectRepository.create(project));
} else {
periodicMiner.addToQueue(
projectRepository.findByProjectUrl(projectUrl).get(0));

logger.atInfo().log("Project %s already exists", projectName);
throw new RuntimeException("Project already exists");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package io.github.martinwitt.laughing_train.mining;

import com.google.common.flogger.FluentLogger;
import io.github.martinwitt.laughing_train.data.Project;
import io.github.martinwitt.laughing_train.data.result.CodeAnalyzerResult;
import io.github.martinwitt.laughing_train.domain.entity.AnalyzerStatus;
import io.github.martinwitt.laughing_train.domain.entity.GitHubCommit;
import io.github.martinwitt.laughing_train.mining.requests.MineNextProject;
import io.github.martinwitt.laughing_train.mining.requests.StoreResults;
import io.github.martinwitt.laughing_train.persistence.repository.ProjectRepository;
import io.quarkus.vertx.ConsumeEvent;
import io.vertx.core.eventbus.EventBus;
import java.util.ArrayList;
import java.util.List;

public class AnalyzerResultsPersistence {

public static final String SERVICE_NAME = "analyzerResultsPersistence";
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
ProjectRepository projectRepository;
EventBus eventBus;

public AnalyzerResultsPersistence(ProjectRepository projectRepository, EventBus eventBus) {
this.projectRepository = projectRepository;
this.eventBus = eventBus;
}

@ConsumeEvent(value = SERVICE_NAME, blocking = true)
void persistResults(StoreResults storeResults) {
Project project = storeResults.project();
CodeAnalyzerResult result = storeResults.result();
addOrUpdateCommitHash(project, result, SERVICE_NAME);
if (result instanceof CodeAnalyzerResult.Failure failure) {
logger.atInfo().log("Analyzer %s failed for project %s", SERVICE_NAME, project.name());

} else if (result instanceof CodeAnalyzerResult.Success success) {
logger.atInfo().log("Analyzer %s succeeded for project %s", SERVICE_NAME, project.name());
}
eventBus.publish("miner", new MineNextProject(storeResults.analyzerName()));
}

private AnalyzerStatus getAnalyzerStatus(CodeAnalyzerResult spoonResult, String name) {
AnalyzerStatus analyzerStatus = null;
if (spoonResult instanceof CodeAnalyzerResult.Success success) {
analyzerStatus = AnalyzerStatus.success(name, success.results().size());
} else if (spoonResult instanceof CodeAnalyzerResult.Failure failure) {
analyzerStatus = AnalyzerStatus.failure(name, 0);
}
return analyzerStatus;
}

private void addOrUpdateCommitHash(Project project, CodeAnalyzerResult spoonResult, String analyzerName) {
String name = project.name();
String commitHash = project.commitHash();
List<io.github.martinwitt.laughing_train.domain.entity.Project> list =
projectRepository.findByProjectUrl(project.url());
AnalyzerStatus analyzerStatus = getAnalyzerStatus(spoonResult, analyzerName);
if (list.isEmpty()) {
io.github.martinwitt.laughing_train.domain.entity.Project newProject =
new io.github.martinwitt.laughing_train.domain.entity.Project(name, project.url());
newProject.addCommitHash(commitHash);
var commits = newProject.getCommits();
commits.stream()
.filter(v -> v.getCommitHash().equals(commitHash))
.findFirst()
.ifPresent(v -> {
v.addAnalyzerStatus(analyzerStatus);
});
projectRepository.create(newProject);
} else {
logger.atInfo().log("Updating commit hash for %s", name);
var oldProject = list.get(0);
oldProject.addCommitHash(commitHash);
var commits = oldProject.getCommits();
GitHubCommit gitHubCommit = new GitHubCommit(commitHash, new ArrayList<>());
commits.add(gitHubCommit);
gitHubCommit.addAnalyzerStatus(analyzerStatus);
oldProject.addCommitHash(gitHubCommit);
projectRepository.save(oldProject);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package io.github.martinwitt.laughing_train.mining;

public interface CodeMiner {

String getAnalyzerName();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.github.martinwitt.laughing_train.mining;

import io.github.martinwitt.laughing_train.mining.requests.MineNextProject;
import io.quarkus.runtime.StartupEvent;
import io.vertx.mutiny.core.Vertx;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;

@ApplicationScoped
public class MiningStartup {

@Inject
Vertx vertx;

void startup(@Observes StartupEvent event) {
vertx.eventBus().send("miner", new MineNextProject(QodanaPeriodicMiner.ANALYZER_NAME));
vertx.eventBus().send("miner", new MineNextProject(SpoonPeriodicMiner.ANALYZER_NAME));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package io.github.martinwitt.laughing_train.mining;

import io.github.martinwitt.laughing_train.data.ProjectRequest;
import io.github.martinwitt.laughing_train.data.ProjectResult;
import io.github.martinwitt.laughing_train.domain.entity.Project;
import io.github.martinwitt.laughing_train.mining.requests.GetProject;
import io.github.martinwitt.laughing_train.persistence.repository.ProjectRepository;
import io.github.martinwitt.laughing_train.services.ProjectService;
import io.quarkus.vertx.ConsumeEvent;
import java.io.IOException;
import java.util.Random;

public class ProjectSupplier {

public static final String SERVICE_NAME = "projectSupplier";

final SearchProjectService searchProjectService;
final ProjectRepository projectRepository;
final ProjectService projectService;
private static final Random random = new Random();

ProjectSupplier(
SearchProjectService searchProjectService,
ProjectRepository projectRepository,
ProjectService projectService) {
this.searchProjectService = searchProjectService;
this.projectRepository = projectRepository;
this.projectService = projectService;
}

@ConsumeEvent(value = SERVICE_NAME, blocking = true)
ProjectResult supplyProject(GetProject getProject) {
try {
Project project = getRandomProject();
return checkoutProject(project);
} catch (IOException e) {
return new ProjectResult.Error(e.getMessage());
}
}

private ProjectResult checkoutProject(Project project) throws IOException {
return projectService.handleProjectRequest(new ProjectRequest.WithUrl(project.getProjectUrl()));
}

private Project getRandomProject() throws IOException {
if (random.nextBoolean()) {
return searchProjectService.searchProjectOnGithub();
} else {
return getKnownProject();
}
}

private Project getKnownProject() {
var list = projectRepository.getAll();
return list.get(random.nextInt(list.size()));
}
}
Loading