Merge branch '18-statistics-page' into 'master'

Resolve "Страница со статистикой"

Closes #18

See merge request romanov73/git-extractor!14
This commit is contained in:
Anton Romanov 2021-04-08 07:36:44 +00:00
commit 7c59b3630c
12 changed files with 348 additions and 3 deletions

View File

@ -64,6 +64,7 @@ dependencies {
compile group: 'org.webjars', name: 'bootstrap', version: '4.6.0'
compile group: 'org.webjars', name: 'bootstrap-select', version: '1.13.8'
compile group: 'org.webjars', name: 'font-awesome', version: '4.7.0'
compile group: 'org.webjars', name: 'highcharts', version: '7.0.0'
testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-test'
}

View File

@ -13,6 +13,7 @@ public class Route {
public static final String LIST_REPOSITORY_BRANCHES = "listBranches";
public static final String INDEXING_NEW_REPOSITORY = "indexNewRepository";
public static final String FILTER_COMMITS = "filterCommits";
public static final String STATISTIC = "statistic";
public static String getLIST_INDEXED_REPOSITORIES() {
return LIST_INDEXED_REPOSITORIES;
@ -29,4 +30,8 @@ public class Route {
public static String getFILTER_COMMITS() {
return FILTER_COMMITS;
}
public static String getSTATISTIC() {
return STATISTIC;
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2021 Anton Romanov - All Rights Reserved
* You may use, distribute and modify this code, please write to: romanov73@gmail.com.
*/
package ru.ulstu.extractor.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import ru.ulstu.extractor.repository.CommitRepository;
import java.util.List;
import java.util.stream.Collectors;
import static ru.ulstu.extractor.controller.Route.STATISTIC;
@Controller
public class StatisticController {
private final CommitRepository commitRepository;
public StatisticController(CommitRepository commitRepository) {
this.commitRepository = commitRepository;
}
@GetMapping(STATISTIC)
public String indexBranch(Model model) {
List<Object[]> authorCommits = commitRepository.getCommitAuthorStatistic().stream()
.map(stat -> new Object[]{stat.getAuthor(), stat.getCountCommit()})
.collect(Collectors.toList());
model.addAttribute("commitAuthorData", authorCommits);
List<Object[]> urlCommits = commitRepository.getCommitUrlStatistic().stream()
.map(stat -> new Object[]{stat.getUrl(), stat.getCountCommit()})
.collect(Collectors.toList());
model.addAttribute("commitUrlData", urlCommits);
List<Object[]> timeCommits = commitRepository.getCommitTimeStatistic().stream()
.map(stat -> new Object[]{stat.getDate(), stat.getCountCommit()})
.collect(Collectors.toList());
model.addAttribute("commitTimeData", timeCommits);
String[] date = new String[timeCommits.size()];
for (int i = 0; i < timeCommits.size(); i++) {
date[i] = timeCommits.get(i)[0].toString();
}
model.addAttribute("dates", date);
String[] url = new String[urlCommits.size()];
for (int i = 0; i < urlCommits.size(); i++) {
url[i] = urlCommits.get(i)[0].toString().substring(urlCommits.get(i)[0].toString().lastIndexOf("/") + 1);
}
model.addAttribute("urls", url);
return STATISTIC;
}
}

View File

@ -0,0 +1,20 @@
package ru.ulstu.extractor.model;
public class CommitAuthorStatistic {
private String author;
private Long countCommit;
public CommitAuthorStatistic(String author, Long countCommit) {
this.author = author;
this.countCommit = countCommit;
}
public String getAuthor() {
return author;
}
public Long getCountCommit() {
return countCommit;
}
}

View File

@ -0,0 +1,22 @@
package ru.ulstu.extractor.model;
import java.util.Date;
public class CommitTimeStatistic {
private Date date;
private Long countCommit;
public CommitTimeStatistic(Date date, Long countCommit) {
this.date = date;
this.countCommit = countCommit;
}
public Date getDate() {
return date;
}
public Long getCountCommit() {
return countCommit;
}
}

View File

@ -0,0 +1,20 @@
package ru.ulstu.extractor.model;
public class CommitUrlStatistic {
private String url;
private Long countCommit;
public CommitUrlStatistic(String url, Long countCommit) {
this.url = url;
this.countCommit = countCommit;
}
public String getUrl() {
return url;
}
public Long getCountCommit() {
return countCommit;
}
}

View File

@ -1,3 +1,8 @@
/*
* Copyright (C) 2021 Anton Romanov - All Rights Reserved
* You may use, distribute and modify this code, please write to: romanov73@gmail.com.
*/
package ru.ulstu.extractor.repository;
import org.springframework.data.domain.Page;
@ -6,9 +11,24 @@ import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import ru.ulstu.extractor.model.Commit;
import ru.ulstu.extractor.model.CommitAuthorStatistic;
import ru.ulstu.extractor.model.CommitTimeStatistic;
import ru.ulstu.extractor.model.CommitUrlStatistic;
import ru.ulstu.extractor.model.Repository;
import java.util.List;
public interface CommitRepository extends JpaRepository<Commit, Integer> {
@Query("SELECT c FROM Commit c, Repository r, Branch b WHERE c.branch = b AND r = b.repository AND r = :repository AND b.name = :branchName")
Page<Commit> findByRepositoryAndBranch(Pageable pageable, @Param("repository") Repository repository, @Param("branchName") String branchName);
@Query("SELECT new ru.ulstu.extractor.model.CommitAuthorStatistic(c.author.name, COUNT(DISTINCT c.hash)) FROM Commit c GROUP by c.author.name")
List<CommitAuthorStatistic> getCommitAuthorStatistic();
@Query("SELECT new ru.ulstu.extractor.model.CommitUrlStatistic(c.branch.repository.url, COUNT(DISTINCT c.hash)) FROM Commit c GROUP by c.branch.repository.url")
List<CommitUrlStatistic> getCommitUrlStatistic();
@Query("SELECT new ru.ulstu.extractor.model.CommitTimeStatistic(cast(c.date as date), COUNT(DISTINCT c.hash)) FROM Commit c GROUP by cast(c.date as date) ORDER by cast(c.date as date)")
List<CommitTimeStatistic> getCommitTimeStatistic();
}

View File

@ -1,4 +1,10 @@
#
# Copyright (C) 2021 Anton Romanov - All Rights Reserved
# You may use, distribute and modify this code, please write to: romanov73@gmail.com.
#
messages.app-name=GitExtractor v0.1.0
messages.menu.home=Main
messages.menu.indexed-repos=List of indexed repos
messages.menu.new-repo=Analyse new repo
messages.menu.new-repo=Analyse new repo
messages.menu.statistic=Statistic

View File

@ -1,4 +1,10 @@
#
# Copyright (C) 2021 Anton Romanov - All Rights Reserved
# You may use, distribute and modify this code, please write to: romanov73@gmail.com.
#
messages.app-name=GitExtractor v0.1.0
messages.menu.home=Main
messages.menu.indexed-repos=List of indexed repos
messages.menu.new-repo=Analyse new repo
messages.menu.new-repo=Analyse new repo
messages.menu.statistic=Statistic

View File

@ -1,4 +1,10 @@
#
# Copyright (C) 2021 Anton Romanov - All Rights Reserved
# You may use, distribute and modify this code, please write to: romanov73@gmail.com.
#
messages.app-name=GitЁxtractor v0.1.0
messages.menu.home=На главную
messages.menu.indexed-repos=Список проиндексированных репозиториев
messages.menu.new-repo=Анализ нового репозитория
messages.menu.new-repo=Анализ нового репозитория
messages.menu.statistic=Статистика

View File

@ -34,6 +34,9 @@
<a class="nav-link" th:href="${@route.LIST_INDEXED_REPOSITORIES}"
th:text="#{messages.menu.indexed-repos}">Link</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/statistic" th:text="#{messages.menu.statistic}">Link</a>
</li>
</ul>
</div>
</nav>

View File

@ -0,0 +1,183 @@
<!--
~ Copyright (C) 2021 Anton Romanov - All Rights Reserved
~ You may use, distribute and modify this code, please write to: romanov73@gmail.com.
-->
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
<html
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.w3.org/1999/xhtml"
layout:decorate="~{default}">
<head>
<title>Простая обработка формы на Spring MVC</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<div class="container" layout:fragment="content">
<script src="/webjars/highcharts/7.0.0/highcharts.js"></script>
<script th:inline="javascript">
$(document).ready(function () {
var chart = {
type: 'scatter',
zoomType: 'xy'
};
var title = {
text: 'Количество коммитов во времени'
};
var xAxis = {
categories: [[${dates}]],
title: {
enabled: true,
text: 'Дата'
},
startOnTick: true,
endOnTick: true,
showLastLabel: true
};
var yAxis = {
title: {
text: 'Кол-во коммитов'
}
};
var plotOptions = {
scatter: {
marker: {
radius: 5,
states: {
hover: {
enabled: true,
lineColor: 'rgb(100,100,100)'
}
}
},
states: {
hover: {
marker: {
enabled: false
}
}
},
tooltip: {
headerFormat: '<b>{series.name}</b><br>',
pointFormat: '{point.y} commits'
}
}
};
var series = [
{
name: 'Коммиты',
color: 'rgba(119,152,191,0.5)',
data: [[${commitTimeData}]]
}
];
var json = {};
json.chart = chart;
json.title = title;
json.xAxis = xAxis;
json.yAxis = yAxis;
json.series = series;
json.plotOptions = plotOptions;
$('#container').highcharts(json);
});
</script>
<script th:inline="javascript">
$(document).ready(function () {
var chart = {
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false
};
var title = {
text: '% коммитов авторов'
};
var tooltip = {
pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
};
var plotOptions = {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: false
},
showInLegend: true
}
};
var series = [{
type: 'pie',
name: 'Browser share',
data: [[${commitAuthorData}]]
}];
var json = {};
json.chart = chart;
json.title = title;
json.tooltip = tooltip;
json.series = series;
json.plotOptions = plotOptions;
$('#containerPie').highcharts(json);
});
</script>
<script th:inline="javascript">
$(document).ready(function () {
var chart = {
type: 'column'
};
var title = {
text: 'Количество коммитов'
};
var xAxis = {
categories: [[${urls}]],
crosshair: true,
title: {
text: 'Репозиторий'
}
};
var yAxis = {
min: 0,
title: {
text: 'Кол-во'
}
};
var tooltip = {
headerFormat: '<span style="font-size:10px">{point.key}</span><table>',
pointFormat: '<tr><td style="color:{series.color};padding:0">{series.name}: </td>' +
'<td style="padding:0"><b>{point.y:.1f}</b></td></tr>',
footerFormat: '</table>',
shared: true,
useHTML: true
};
var plotOptions = {
column: {
pointPadding: 0.2,
borderWidth: 0
}
};
var credits = {
enabled: false
};
var series = [{
name: 'Коммиты',
data: [[${commitUrlData}]]
}];
var json = {};
json.chart = chart;
json.title = title;
json.tooltip = tooltip;
json.xAxis = xAxis;
json.yAxis = yAxis;
json.series = series;
json.plotOptions = plotOptions;
json.credits = credits;
$('#containerColumn').highcharts(json);
});
</script>
<div class="row">
<div id="container" style="width: 550px; height: 400px; margin: 0 auto"></div>
<div id="containerPie" style="width: 550px; height: 400px; margin: 0 auto"></div>
<div id="containerColumn" style="width: 550px; height: 400px; margin: 0 auto"></div>
</div>
</div>
</html>