From c4c4562ae8e701a106a77ceaae6a8db0f7c4e9b2 Mon Sep 17 00:00:00 2001 From: Martin Wittlinger Date: Fri, 8 Dec 2023 14:26:57 +0100 Subject: [PATCH] feat: Update project and analyzer run data models (#1316) --- frontend/src/ProjectData.tsx | 33 ++++---- frontend/src/component/ProjectList.tsx | 9 ++- frontend/src/component/ProjectTable.tsx | 6 +- frontend/src/data/AnalyzerRun.tsx | 11 +++ github-bot/build.gradle | 3 + .../graphql/dto/AnalyzerRunGraphQlDto.java | 76 +++++++++++++++++++ .../api/graphql/endpoints/ProjectGraphQL.java | 14 +++- .../persistence/dao/AnalyzerRunDao.java | 21 +---- .../persistence/dao/ProjectDao.java | 4 +- .../impl/SqlAnalyzerRunRepository.java | 9 ++- .../impl/SqlProjectRepository.java | 10 +-- .../src/main/resources/application.properties | 2 +- .../impl/SqlProjectRepositoryTest.java | 8 ++ 13 files changed, 147 insertions(+), 59 deletions(-) create mode 100644 frontend/src/data/AnalyzerRun.tsx create mode 100644 github-bot/src/main/java/io/github/martinwitt/laughing_train/api/graphql/dto/AnalyzerRunGraphQlDto.java diff --git a/frontend/src/ProjectData.tsx b/frontend/src/ProjectData.tsx index c606c70d1..9e5347fe6 100644 --- a/frontend/src/ProjectData.tsx +++ b/frontend/src/ProjectData.tsx @@ -1,6 +1,6 @@ -import {gql} from '@apollo/client'; -import {BadSmell} from './data/BadSmell'; -import {Project} from './data/Project'; +import { gql } from '@apollo/client'; +import { BadSmell } from './data/BadSmell'; +import { Project } from './data/Project'; export const fetchProjectQuery = gql` query getProjects { @@ -21,22 +21,17 @@ export const fetchProjectQuery = gql` } } `; -export const fetchRecentProjectQuery = gql` - query getRecentProjects { - getRecentProjects(size: 30) { - projectName - projectUrl - commitHashes - commits { - analyzerStatuses { - analyzerName - commitHash - localDateTime - numberOfIssues - status - } +export const recentAnalyzerRuns = gql` + query recentAnalyzerRuns { + recentAnalyzerRuns(size: 30) { + analyzerName commitHash - } + "ISO-8601" + localDateTime + numberOfIssues + projectName + projectUrl + status } } `; @@ -95,7 +90,7 @@ export function filterDuplicateBadSmells(params: BadSmell[]) { }); const ids = params.map((o) => o.snippet); return params.filter( - ({snippet}, index) => !ids.includes(snippet, index + 1) + ({ snippet }, index) => !ids.includes(snippet, index + 1) ); } diff --git a/frontend/src/component/ProjectList.tsx b/frontend/src/component/ProjectList.tsx index 0e296f046..486271e27 100644 --- a/frontend/src/component/ProjectList.tsx +++ b/frontend/src/component/ProjectList.tsx @@ -3,17 +3,18 @@ import { Project } from '../data/Project'; import React, { useMemo } from 'react'; import ProjectTable from './ProjectTable'; import { LinearProgress } from '@mui/material'; -import { fetchRecentProjectQuery } from '../ProjectData'; +import { recentAnalyzerRuns } from '../ProjectData'; +import { AnalyzerRun } from '../data/AnalyzerRun'; export function ProjectList({ filter }: { filter: string }) { - const { data, loading, error } = useQuery(fetchRecentProjectQuery); + const { data, loading, error } = useQuery(recentAnalyzerRuns); const filteredProjects = useMemo(() => { if (!data) { return []; } - return data.getRecentProjects.filter((project: Project) => { - return project.projectName.toLowerCase().match(filter.toLowerCase()); + return data.recentAnalyzerRuns.filter((analyzerRun: AnalyzerRun) => { + return analyzerRun.projectName.toLowerCase().match(filter.toLowerCase()); }); }, [data, filter]); if (error) { diff --git a/frontend/src/component/ProjectTable.tsx b/frontend/src/component/ProjectTable.tsx index 1a0e85fc2..61d0cbe85 100644 --- a/frontend/src/component/ProjectTable.tsx +++ b/frontend/src/component/ProjectTable.tsx @@ -49,7 +49,7 @@ function ProjectTable(props: ProjectTableProps) { } return 0; } - if (sortConfig.key === 'resultCount') { + if (sortConfig.key === 'numberOfIssues') { if (aStatus && bStatus) { return aStatus.numberOfIssues > bStatus.numberOfIssues ? 1 : -1; } @@ -66,7 +66,7 @@ function ProjectTable(props: ProjectTableProps) { } return 0; } - if (sortConfig.key === 'resultCount') { + if (sortConfig.key === 'numberOfIssues') { if (aStatus && bStatus) { return aStatus.numberOfIssues < bStatus.numberOfIssues ? 1 : -1; } @@ -105,7 +105,7 @@ function ProjectTable(props: ProjectTableProps) { label="Number of Results" sortConfig={sortConfig} requestSort={requestSort} - sortKey="resultCount" + sortKey="numberOfIssues" /> diff --git a/frontend/src/data/AnalyzerRun.tsx b/frontend/src/data/AnalyzerRun.tsx new file mode 100644 index 000000000..a0f31a20b --- /dev/null +++ b/frontend/src/data/AnalyzerRun.tsx @@ -0,0 +1,11 @@ +import { LocalDateTime } from '@js-joda/core'; + +export type AnalyzerRun = { + analyzerName: String; + commitHash: String; + localDateTime: LocalDateTime; + numberOfIssues: number; + projectName: String; + projectUrl: String; + status: String; +}; diff --git a/github-bot/build.gradle b/github-bot/build.gradle index bb7b0fc8a..8e6e00472 100644 --- a/github-bot/build.gradle +++ b/github-bot/build.gradle @@ -34,4 +34,7 @@ dependencies { quarkusDependenciesBuild { dependsOn("jandex") +} +compileJava { + dependsOn("compileQuarkusGeneratedSourcesJava") } \ No newline at end of file diff --git a/github-bot/src/main/java/io/github/martinwitt/laughing_train/api/graphql/dto/AnalyzerRunGraphQlDto.java b/github-bot/src/main/java/io/github/martinwitt/laughing_train/api/graphql/dto/AnalyzerRunGraphQlDto.java new file mode 100644 index 000000000..0e908aa5c --- /dev/null +++ b/github-bot/src/main/java/io/github/martinwitt/laughing_train/api/graphql/dto/AnalyzerRunGraphQlDto.java @@ -0,0 +1,76 @@ +package io.github.martinwitt.laughing_train.api.graphql.dto; + +import io.github.martinwitt.laughing_train.persistence.dao.AnalyzerRunDao; +import java.time.LocalDateTime; +import org.eclipse.microprofile.graphql.Name; + +@Name("AnalyzerRun") +public class AnalyzerRunGraphQlDto { + + private String projectName; + private String projectUrl; + private String analyzerName; + private String status; + private int numberOfIssues; + private String commitHash; + private LocalDateTime localDateTime; + + public AnalyzerRunGraphQlDto(AnalyzerRunDao dao) { + this.projectName = dao.projectDao.getProjectName(); + this.projectUrl = dao.projectDao.getProjectUrl(); + this.analyzerName = dao.analyzerName; + this.status = dao.status; + this.numberOfIssues = dao.numberOfIssues; + this.commitHash = dao.commitHash; + this.localDateTime = dao.localDateTime; + } + + /** + * @return the analyzerName + */ + public String getAnalyzerName() { + return analyzerName; + } + + /** + * @return the commitHash + */ + public String getCommitHash() { + return commitHash; + } + + /** + * @return the localDateTime + */ + public LocalDateTime getLocalDateTime() { + return localDateTime; + } + + /** + * @return the numberOfIssues + */ + public int getNumberOfIssues() { + return numberOfIssues; + } + + /** + * @return the projectName + */ + public String getProjectName() { + return projectName; + } + + /** + * @return the projectUrl + */ + public String getProjectUrl() { + return projectUrl; + } + + /** + * @return the status + */ + public String getStatus() { + return status; + } +} 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 f5b303af6..a792e3944 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 @@ -1,12 +1,14 @@ package io.github.martinwitt.laughing_train.api.graphql.endpoints; import com.google.common.flogger.FluentLogger; +import io.github.martinwitt.laughing_train.api.graphql.dto.AnalyzerRunGraphQlDto; import io.github.martinwitt.laughing_train.api.graphql.dto.ProjectConfigGraphQLDtoInput; import io.github.martinwitt.laughing_train.api.graphql.dto.ProjectGraphQLDto; import io.github.martinwitt.laughing_train.domain.entity.GitHubCommit; import io.github.martinwitt.laughing_train.domain.entity.ProjectConfig; import io.github.martinwitt.laughing_train.domain.entity.RemoteProject; import io.github.martinwitt.laughing_train.mining.QodanaPeriodicMiner; +import io.github.martinwitt.laughing_train.persistence.impl.SqlAnalyzerRunRepository; import io.github.martinwitt.laughing_train.persistence.repository.ProjectRepository; import io.quarkus.security.Authenticated; import jakarta.inject.Inject; @@ -26,16 +28,20 @@ public class ProjectGraphQL { @Inject QodanaPeriodicMiner periodicMiner; + @Inject SqlAnalyzerRunRepository sqlAnalyzerRunRepository; + @Query("getProjects") @Description("Gets all projects from the database") public List getAllProjects() { return projectRepository.getAll().stream().map(this::mapToDto).toList(); } - @Query("getRecentProjects") - @Description("Gets all projects from the database with a limit") - public List getRecentProjects(int size) { - return projectRepository.getRecent(size).stream().map(this::mapToDto).toList(); + @Query("recentAnalyzerRuns") + @Description("Returns a sorted by date list of recent analyzer runs") + public List recentAnalyzerRuns(int size) { + return sqlAnalyzerRunRepository.findRecent(size).stream() + .map(AnalyzerRunGraphQlDto::new) + .toList(); } @Query("getProjectWithName") diff --git a/github-bot/src/main/java/io/github/martinwitt/laughing_train/persistence/dao/AnalyzerRunDao.java b/github-bot/src/main/java/io/github/martinwitt/laughing_train/persistence/dao/AnalyzerRunDao.java index 4842b892d..cf2c942a9 100644 --- a/github-bot/src/main/java/io/github/martinwitt/laughing_train/persistence/dao/AnalyzerRunDao.java +++ b/github-bot/src/main/java/io/github/martinwitt/laughing_train/persistence/dao/AnalyzerRunDao.java @@ -2,6 +2,7 @@ import io.quarkus.hibernate.orm.panache.PanacheEntity; import jakarta.persistence.Entity; +import jakarta.persistence.ManyToOne; import java.time.LocalDateTime; @Entity @@ -12,27 +13,9 @@ public class AnalyzerRunDao extends PanacheEntity { public int numberOfIssues; public String commitHash; public LocalDateTime localDateTime; + @ManyToOne public ProjectDao projectDao; public AnalyzerRunDao() { // for JPA } - - private AnalyzerRunDao( - String analyzerName, - String status, - int numberOfIssues, - String commitHash, - LocalDateTime localDateTime) { - this.analyzerName = analyzerName; - this.status = status; - this.numberOfIssues = numberOfIssues; - this.commitHash = commitHash; - this.localDateTime = localDateTime; - } - - @Override - public String toString() { - return "AnalyzerRunDao{analyzerName='%s', status='%s', numberOfIssues=%d, commitHash='%s', localDateTime=%s}" - .formatted(analyzerName, status, numberOfIssues, commitHash, localDateTime); - } } diff --git a/github-bot/src/main/java/io/github/martinwitt/laughing_train/persistence/dao/ProjectDao.java b/github-bot/src/main/java/io/github/martinwitt/laughing_train/persistence/dao/ProjectDao.java index da390703d..ee371be33 100644 --- a/github-bot/src/main/java/io/github/martinwitt/laughing_train/persistence/dao/ProjectDao.java +++ b/github-bot/src/main/java/io/github/martinwitt/laughing_train/persistence/dao/ProjectDao.java @@ -1,6 +1,7 @@ package io.github.martinwitt.laughing_train.persistence.dao; import io.quarkus.hibernate.orm.panache.PanacheEntity; +import jakarta.persistence.CascadeType; import jakarta.persistence.Entity; import jakarta.persistence.OneToMany; import java.time.LocalDateTime; @@ -15,7 +16,8 @@ public class ProjectDao extends PanacheEntity { private String projectUrl; private LocalDateTime latestRun; - @OneToMany private List commits = new ArrayList<>(); + @OneToMany(cascade = CascadeType.ALL) + private List commits = new ArrayList<>(); public ProjectDao() { diff --git a/github-bot/src/main/java/io/github/martinwitt/laughing_train/persistence/impl/SqlAnalyzerRunRepository.java b/github-bot/src/main/java/io/github/martinwitt/laughing_train/persistence/impl/SqlAnalyzerRunRepository.java index a1d70bcc3..c07055790 100644 --- a/github-bot/src/main/java/io/github/martinwitt/laughing_train/persistence/impl/SqlAnalyzerRunRepository.java +++ b/github-bot/src/main/java/io/github/martinwitt/laughing_train/persistence/impl/SqlAnalyzerRunRepository.java @@ -2,9 +2,16 @@ import io.github.martinwitt.laughing_train.persistence.dao.AnalyzerRunDao; import io.quarkus.hibernate.orm.panache.PanacheRepository; +import io.quarkus.panache.common.Sort; import jakarta.enterprise.context.ApplicationScoped; import jakarta.transaction.Transactional; +import java.util.List; @ApplicationScoped @Transactional -public class SqlAnalyzerRunRepository implements PanacheRepository {} +public class SqlAnalyzerRunRepository implements PanacheRepository { + + public List findRecent(int limit) { + return findAll(Sort.ascending("localDateTime")).page(0, limit).list(); + } +} diff --git a/github-bot/src/main/java/io/github/martinwitt/laughing_train/persistence/impl/SqlProjectRepository.java b/github-bot/src/main/java/io/github/martinwitt/laughing_train/persistence/impl/SqlProjectRepository.java index 38597851b..fbdfd49c2 100644 --- a/github-bot/src/main/java/io/github/martinwitt/laughing_train/persistence/impl/SqlProjectRepository.java +++ b/github-bot/src/main/java/io/github/martinwitt/laughing_train/persistence/impl/SqlProjectRepository.java @@ -15,11 +15,8 @@ public class SqlProjectRepository implements ProjectRepository, PanacheRepository { private static final ProjectDaoConverter projectDaoConverter = new ProjectDaoConverter(); - private SqlAnalyzerRunRepository sqlAnalyzerRunRepository; - public SqlProjectRepository(SqlAnalyzerRunRepository sqlAnalyzerRunRepository) { - this.sqlAnalyzerRunRepository = sqlAnalyzerRunRepository; - } + public SqlProjectRepository() {} @Override public List getAll() { @@ -76,7 +73,7 @@ public RemoteProject save(RemoteProject project) { ProjectDao projectDao = projectDaoConverter.convertToDao(project); if (find("projectUrl", projectDao.getProjectUrl()).stream().findFirst().isEmpty()) { ProjectDao dao = projectDaoConverter.convertToDao(project); - sqlAnalyzerRunRepository.persist(dao.getCommits()); + // sqlAnalyzerRunRepository.persist(dao.getCommits()); persist(dao); } else { var dao = projectDaoConverter.convertToDao(project); @@ -84,8 +81,7 @@ public RemoteProject save(RemoteProject project) { databaseEntry.setProjectName(dao.getProjectName()); databaseEntry.setProjectUrl(dao.getProjectUrl()); databaseEntry.setCommits(dao.getCommits()); - databaseEntry.setCommits(dao.getCommits()); - sqlAnalyzerRunRepository.persist(databaseEntry.getCommits()); + // sqlAnalyzerRunRepository.persist(databaseEntry.getCommits()); persist(databaseEntry); } return project; diff --git a/github-bot/src/main/resources/application.properties b/github-bot/src/main/resources/application.properties index 87068ab81..e6974e30b 100644 --- a/github-bot/src/main/resources/application.properties +++ b/github-bot/src/main/resources/application.properties @@ -57,5 +57,5 @@ quarkus.http.cors.origins=* quarkus.vertx.max-worker-execute-time=30m %test.quarkus.scheduler.enabled=false quarkus.datasource.db-kind = mariadb -quarkus.hibernate-orm.database.generation = update +quarkus.hibernate-orm.database.generation = drop-and-create %dev.quarkus.quinoa=false \ No newline at end of file diff --git a/github-bot/src/test/java/io/github/martinwitt/laughing_train/persistence/impl/SqlProjectRepositoryTest.java b/github-bot/src/test/java/io/github/martinwitt/laughing_train/persistence/impl/SqlProjectRepositoryTest.java index 610ad5309..9ab0a5adc 100644 --- a/github-bot/src/test/java/io/github/martinwitt/laughing_train/persistence/impl/SqlProjectRepositoryTest.java +++ b/github-bot/src/test/java/io/github/martinwitt/laughing_train/persistence/impl/SqlProjectRepositoryTest.java @@ -7,6 +7,7 @@ import io.quarkus.test.junit.QuarkusTest; import jakarta.inject.Inject; import java.util.List; +import java.util.stream.Collectors; import org.instancio.Instancio; import org.junit.jupiter.api.Test; @@ -15,6 +16,8 @@ class SqlProjectRepositoryTest { @Inject SqlProjectRepository sqlProjectRepository; + @Inject SqlAnalyzerRunRepository sqlAnalyzerRunRepository; + @Test void insertProject() { RemoteProject remoteProject = Instancio.create(RemoteProject.class); @@ -23,6 +26,11 @@ void insertProject() { List byProjectName = sqlProjectRepository.findByProjectName(remoteProject.getProjectName()); assertThat(byProjectName).isNotEmpty(); + Integer expectedSize = + remoteProject.getCommits().stream() + .map(v -> v.getAnalyzerStatuses()) + .collect(Collectors.summingInt(v -> v.size())); + assertThat(sqlAnalyzerRunRepository.findRecent(expectedSize)).hasSize(expectedSize); } @Test