Merge branch 'master' into 12-heuristic
# Conflicts: # src/main/java/ru/ulstu/extractor/service/GitRepositoryService.java # src/main/resources/templates/error.html
This commit is contained in:
commit
387226f26e
@ -71,6 +71,7 @@ dependencies {
|
|||||||
compile group: 'org.webjars', name: 'bootstrap', version: '4.6.0'
|
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: 'bootstrap-select', version: '1.13.8'
|
||||||
compile group: 'org.webjars', name: 'font-awesome', version: '4.7.0'
|
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'
|
testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-test'
|
||||||
}
|
}
|
||||||
|
@ -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.config;
|
package ru.ulstu.extractor.config;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@ -5,12 +10,14 @@ import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry
|
|||||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
import static ru.ulstu.extractor.controller.Route.LIST_INDEXED_REPOSITORIES;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public class MvcConfiguration implements WebMvcConfigurer {
|
public class MvcConfiguration implements WebMvcConfigurer {
|
||||||
@Override
|
@Override
|
||||||
public void addViewControllers(ViewControllerRegistry registry) {
|
public void addViewControllers(ViewControllerRegistry registry) {
|
||||||
registry.addViewController("/{articlename:\\w+}");
|
registry.addViewController("/{articlename:\\w+}");
|
||||||
registry.addRedirectViewController("/", "/newRepo");
|
registry.addRedirectViewController("/", LIST_INDEXED_REPOSITORIES);
|
||||||
registry.addRedirectViewController("/default", "/home");
|
registry.addRedirectViewController("/default", "/home");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.controller;
|
package ru.ulstu.extractor.controller;
|
||||||
|
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
@ -7,6 +12,8 @@ import org.springframework.web.bind.annotation.RequestParam;
|
|||||||
import ru.ulstu.extractor.repository.BranchRepository;
|
import ru.ulstu.extractor.repository.BranchRepository;
|
||||||
import ru.ulstu.extractor.repository.RepositoryRepository;
|
import ru.ulstu.extractor.repository.RepositoryRepository;
|
||||||
|
|
||||||
|
import static ru.ulstu.extractor.controller.Route.LIST_REPOSITORY_BRANCHES;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
public class BranchController {
|
public class BranchController {
|
||||||
private final RepositoryRepository repositoryRepository;
|
private final RepositoryRepository repositoryRepository;
|
||||||
@ -17,12 +24,12 @@ public class BranchController {
|
|||||||
this.branchRepository = branchRepository;
|
this.branchRepository = branchRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/details")
|
@GetMapping(LIST_REPOSITORY_BRANCHES)
|
||||||
public String indexBranch(
|
public String indexBranch(
|
||||||
Model model,
|
Model model,
|
||||||
@RequestParam int repositoryId) {
|
@RequestParam int repositoryId) {
|
||||||
model.addAttribute("branches", branchRepository.findByRepositoryId(repositoryId));
|
model.addAttribute("branches", branchRepository.findByRepositoryId(repositoryId));
|
||||||
model.addAttribute("repository", repositoryRepository.findById(repositoryId).get());
|
model.addAttribute("repository", repositoryRepository.findById(repositoryId).get());
|
||||||
return "indexBranch";
|
return LIST_REPOSITORY_BRANCHES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
package ru.ulstu.extractor.controller;
|
||||||
|
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
@ -11,47 +15,43 @@ import ru.ulstu.extractor.model.Commit;
|
|||||||
import ru.ulstu.extractor.model.OffsetablePageRequest;
|
import ru.ulstu.extractor.model.OffsetablePageRequest;
|
||||||
import ru.ulstu.extractor.model.mvc.FilterForm;
|
import ru.ulstu.extractor.model.mvc.FilterForm;
|
||||||
import ru.ulstu.extractor.service.FilteringService;
|
import ru.ulstu.extractor.service.FilteringService;
|
||||||
import ru.ulstu.extractor.service.IndexService;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
import static ru.ulstu.extractor.controller.Route.FILTER_COMMITS;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
public class GitFilteringController {
|
public class GitFilteringController {
|
||||||
|
private final static int DEFAULT_PAGE_SIZE = 20;
|
||||||
private final FilteringService filteringService;
|
private final FilteringService filteringService;
|
||||||
private final IndexService indexService;
|
|
||||||
|
|
||||||
public GitFilteringController(FilteringService filteringService,
|
public GitFilteringController(FilteringService filteringService) {
|
||||||
IndexService indexService) {
|
|
||||||
this.filteringService = filteringService;
|
this.filteringService = filteringService;
|
||||||
this.indexService = indexService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @PostMapping("/sendFilter")
|
@RequestMapping(value = FILTER_COMMITS, method = RequestMethod.GET)
|
||||||
public String sendFilter(@ModelAttribute FilterForm filterForm, Model model) throws GitAPIException, IOException {
|
|
||||||
List<Commit> list = gitRepositoryService.getCommits(filterForm.getUrl(), filterForm.getBranch());
|
|
||||||
model.addAttribute("commits", list);
|
|
||||||
if (filterForm.getFilter() == null || filterForm.getFilter().isEmpty()) {
|
|
||||||
model.addAttribute("error", "'Строка' не должно быть пустым");
|
|
||||||
return "filtering";
|
|
||||||
}
|
|
||||||
return "resultRepo";
|
|
||||||
}*/
|
|
||||||
|
|
||||||
@RequestMapping(value = "/filtering", method = RequestMethod.GET)
|
|
||||||
public String listCommits(
|
public String listCommits(
|
||||||
Model model,
|
Model model,
|
||||||
@ModelAttribute FilterForm filterForm,
|
@RequestParam Optional<Integer> page,
|
||||||
@RequestParam("page") Optional<Integer> page,
|
@RequestParam Optional<Integer> size,
|
||||||
@RequestParam("size") Optional<Integer> size,
|
@RequestParam Optional<String> repositoryUrl,
|
||||||
@RequestParam String repositoryUrl,
|
@RequestParam Optional<String> branchName,
|
||||||
@RequestParam String branchName) {
|
@RequestParam Optional<String> author,
|
||||||
|
@RequestParam Optional<String> filter) {
|
||||||
int currentPage = page.orElse(1);
|
int currentPage = page.orElse(1);
|
||||||
int pageSize = size.orElse(5);
|
int pageSize = size.orElse(DEFAULT_PAGE_SIZE);
|
||||||
|
|
||||||
Page<Commit> commitsPage = indexService.getCommits(repositoryUrl, branchName, new OffsetablePageRequest(currentPage, pageSize));
|
String notEmptyRepositoryUrl = repositoryUrl.orElseThrow(() -> new RuntimeException("Url repository not present"));
|
||||||
|
String notEmptyBranchName = branchName.orElseThrow(() -> new RuntimeException("Branch name not present"));
|
||||||
|
|
||||||
|
Page<Commit> commitsPage = filteringService.getCommits(notEmptyRepositoryUrl,
|
||||||
|
notEmptyBranchName,
|
||||||
|
author.orElse(null),
|
||||||
|
filter.orElse(null),
|
||||||
|
new OffsetablePageRequest(currentPage - 1, pageSize));
|
||||||
int totalPages = commitsPage.getTotalPages();
|
int totalPages = commitsPage.getTotalPages();
|
||||||
if (totalPages > 0) {
|
if (totalPages > 0) {
|
||||||
List<Integer> pageNumbers = IntStream.rangeClosed(1, totalPages)
|
List<Integer> pageNumbers = IntStream.rangeClosed(1, totalPages)
|
||||||
@ -59,11 +59,17 @@ public class GitFilteringController {
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
model.addAttribute("pageNumbers", pageNumbers);
|
model.addAttribute("pageNumbers", pageNumbers);
|
||||||
}
|
}
|
||||||
filterForm = new FilterForm();
|
FilterForm filterForm = new FilterForm();
|
||||||
filterForm.setCommitsPage(commitsPage);
|
filterForm.setCommitsPage(commitsPage);
|
||||||
filterForm.setBranch(branchName);
|
filterForm.setBranchName(notEmptyBranchName);
|
||||||
filterForm.setUrl(repositoryUrl);
|
filterForm.setRepositoryUrl(notEmptyRepositoryUrl);
|
||||||
|
filterForm.setAuthor(author.orElse(null));
|
||||||
|
filterForm.setFilter(filter.orElse(null));
|
||||||
model.addAttribute("filterForm", filterForm);
|
model.addAttribute("filterForm", filterForm);
|
||||||
return "filtering";
|
model.addAttribute("authors", filteringService.getRepositoryAuthors(
|
||||||
|
notEmptyRepositoryUrl,
|
||||||
|
notEmptyBranchName
|
||||||
|
));
|
||||||
|
return FILTER_COMMITS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
package ru.ulstu.extractor.controller;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
@ -13,10 +21,15 @@ import ru.ulstu.extractor.model.mvc.RepoForm;
|
|||||||
import ru.ulstu.extractor.service.GitRepositoryService;
|
import ru.ulstu.extractor.service.GitRepositoryService;
|
||||||
import ru.ulstu.extractor.service.IndexService;
|
import ru.ulstu.extractor.service.IndexService;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static ru.ulstu.extractor.controller.Route.FILTER_COMMITS;
|
||||||
|
import static ru.ulstu.extractor.controller.Route.INDEXING_NEW_REPOSITORY;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
public class GitIndexingController {
|
public class GitIndexingController {
|
||||||
|
private final static Logger LOG = LoggerFactory.getLogger(GitIndexingController.class);
|
||||||
private final GitRepositoryService gitRepositoryService;
|
private final GitRepositoryService gitRepositoryService;
|
||||||
private final IndexService indexService;
|
private final IndexService indexService;
|
||||||
|
|
||||||
@ -26,40 +39,39 @@ public class GitIndexingController {
|
|||||||
this.indexService = indexService;
|
this.indexService = indexService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/newRepo")
|
@GetMapping(INDEXING_NEW_REPOSITORY)
|
||||||
public String indexNewRepo(Model model) {
|
public String indexNewRepo(Model model) {
|
||||||
model.addAttribute(new RepoForm());
|
model.addAttribute(new RepoForm());
|
||||||
return "newRepo";
|
return INDEXING_NEW_REPOSITORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/newRepo", method = RequestMethod.POST, params = "send")
|
@RequestMapping(value = INDEXING_NEW_REPOSITORY, method = RequestMethod.POST, params = "send")
|
||||||
public String getBranch(@ModelAttribute RepoForm repoForm, Model model) {
|
public String getBranch(@ModelAttribute RepoForm repoForm, Model model) {
|
||||||
try {
|
try {
|
||||||
gitRepositoryService.cloneOrUpdateRepo(repoForm.getRepo());
|
List<Branch> branches = gitRepositoryService.getRemoteBranches(repoForm.getRepo());
|
||||||
List<Branch> branches = gitRepositoryService.getBranches(repoForm.getRepo());
|
|
||||||
model.addAttribute("branches", branches);
|
model.addAttribute("branches", branches);
|
||||||
return "newRepo";
|
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
model.addAttribute("error", ex.getMessage());
|
model.addAttribute("error", ex.getMessage());
|
||||||
return "newRepo";
|
|
||||||
}
|
}
|
||||||
|
return INDEXING_NEW_REPOSITORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "/newRepo", method = RequestMethod.POST, params = "next")
|
@RequestMapping(value = INDEXING_NEW_REPOSITORY, method = RequestMethod.POST, params = "next")
|
||||||
public String setBranch(@ModelAttribute RepoForm repoForm, Model model, RedirectAttributes redirectAttributes) {
|
public String indexBranch(@ModelAttribute RepoForm repoForm, Model model, RedirectAttributes redirectAttributes) {
|
||||||
model.addAttribute("filterForm", new FilterForm(repoForm.getRepo()));
|
model.addAttribute("filterForm", new FilterForm(repoForm.getRepo()));
|
||||||
if (repoForm.getBranch() == null) {
|
if (repoForm.getBranch() == null) {
|
||||||
return "newRepo";
|
return INDEXING_NEW_REPOSITORY;
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
indexService.index(repoForm.getRepo(), repoForm.getBranch());
|
indexService.index(repoForm.getRepo(), repoForm.getBranch());
|
||||||
} catch (Exception ex) {
|
} catch (IOException | GitAPIException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
model.addAttribute("error", ex.getMessage());
|
model.addAttribute("error", ex.getMessage());
|
||||||
return "newRepo";
|
return INDEXING_NEW_REPOSITORY;
|
||||||
}
|
}
|
||||||
redirectAttributes.addAttribute("repositoryUrl", repoForm.getRepo());
|
redirectAttributes.addAttribute("repositoryUrl", repoForm.getRepo());
|
||||||
redirectAttributes.addAttribute("branchName", repoForm.getBranch());
|
redirectAttributes.addAttribute("branchName", repoForm.getBranch());
|
||||||
return "redirect:/filtering";
|
return "redirect:/" + FILTER_COMMITS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.controller;
|
package ru.ulstu.extractor.controller;
|
||||||
|
|
||||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||||
@ -7,6 +12,7 @@ import org.springframework.web.bind.annotation.RequestParam;
|
|||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import ru.ulstu.extractor.model.Commit;
|
import ru.ulstu.extractor.model.Commit;
|
||||||
import ru.ulstu.extractor.service.GitRepositoryService;
|
import ru.ulstu.extractor.service.GitRepositoryService;
|
||||||
|
import ru.ulstu.extractor.service.IndexService;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -18,14 +24,12 @@ import static ru.ulstu.extractor.controller.RepoController.URL;
|
|||||||
public class RepoController {
|
public class RepoController {
|
||||||
public static final String URL = "/";
|
public static final String URL = "/";
|
||||||
private final GitRepositoryService gitRepositoryService;
|
private final GitRepositoryService gitRepositoryService;
|
||||||
|
private final IndexService indexService;
|
||||||
|
|
||||||
public RepoController(GitRepositoryService gitRepositoryService) {
|
public RepoController(GitRepositoryService gitRepositoryService,
|
||||||
|
IndexService indexService) {
|
||||||
this.gitRepositoryService = gitRepositoryService;
|
this.gitRepositoryService = gitRepositoryService;
|
||||||
}
|
this.indexService = indexService;
|
||||||
|
|
||||||
@GetMapping("clone")
|
|
||||||
public void cloneRepository(@RequestParam("url") String url) throws GitAPIException, IOException {
|
|
||||||
gitRepositoryService.cloneOrUpdateRepo(url);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("commits")
|
@GetMapping("commits")
|
||||||
@ -34,4 +38,11 @@ public class RepoController {
|
|||||||
return gitRepositoryService.getCommits(repositoryUrl, branchName);
|
return gitRepositoryService.getCommits(repositoryUrl, branchName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("index")
|
||||||
|
public Boolean indexRepository(@RequestParam("repositoryUrl") String repositoryUrl,
|
||||||
|
@RequestParam("branchName") String branchName) throws GitAPIException, IOException {
|
||||||
|
indexService.index(repositoryUrl, branchName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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.controller;
|
package ru.ulstu.extractor.controller;
|
||||||
|
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
@ -5,17 +10,19 @@ import org.springframework.ui.Model;
|
|||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import ru.ulstu.extractor.repository.RepositoryRepository;
|
import ru.ulstu.extractor.repository.RepositoryRepository;
|
||||||
|
|
||||||
|
import static ru.ulstu.extractor.controller.Route.LIST_INDEXED_REPOSITORIES;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
public class BaseIndexingController {
|
public class RepositoryController {
|
||||||
private final RepositoryRepository repositoryRepository;
|
private final RepositoryRepository repositoryRepository;
|
||||||
|
|
||||||
public BaseIndexingController(RepositoryRepository repositoryRepository) {
|
public RepositoryController(RepositoryRepository repositoryRepository) {
|
||||||
this.repositoryRepository = repositoryRepository;
|
this.repositoryRepository = repositoryRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/indexRepo")
|
@GetMapping(LIST_INDEXED_REPOSITORIES)
|
||||||
public String indexNewRepo(Model model) {
|
public String indexNewRepo(Model model) {
|
||||||
model.addAttribute("repositories", repositoryRepository.findAll());
|
model.addAttribute("repositories", repositoryRepository.findAll());
|
||||||
return "indexRepo";
|
return LIST_INDEXED_REPOSITORIES;
|
||||||
}
|
}
|
||||||
}
|
}
|
37
src/main/java/ru/ulstu/extractor/controller/Route.java
Normal file
37
src/main/java/ru/ulstu/extractor/controller/Route.java
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class Route {
|
||||||
|
public static final String LIST_INDEXED_REPOSITORIES = "listRepositories";
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getLIST_REPOSITORY_BRANCHES() {
|
||||||
|
return LIST_REPOSITORY_BRANCHES;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getINDEXING_NEW_REPOSITORY() {
|
||||||
|
return INDEXING_NEW_REPOSITORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getFILTER_COMMITS() {
|
||||||
|
return FILTER_COMMITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getSTATISTIC() {
|
||||||
|
return STATISTIC;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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.model.mvc;
|
package ru.ulstu.extractor.model.mvc;
|
||||||
|
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
@ -5,15 +10,24 @@ import ru.ulstu.extractor.model.Commit;
|
|||||||
|
|
||||||
public class FilterForm {
|
public class FilterForm {
|
||||||
private String filter;
|
private String filter;
|
||||||
private String url;
|
private String repositoryUrl;
|
||||||
private String branch;
|
private String branchName;
|
||||||
|
private String author;
|
||||||
private Page<Commit> commitsPage;
|
private Page<Commit> commitsPage;
|
||||||
|
|
||||||
public FilterForm() {
|
public FilterForm() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getAuthor() {
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthor(String author) {
|
||||||
|
this.author = author;
|
||||||
|
}
|
||||||
|
|
||||||
public FilterForm(String url) {
|
public FilterForm(String url) {
|
||||||
this.url = url;
|
this.repositoryUrl = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFilter() {
|
public String getFilter() {
|
||||||
@ -24,22 +38,6 @@ public class FilterForm {
|
|||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUrl() {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUrl(String url) {
|
|
||||||
this.url = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getBranch() {
|
|
||||||
return branch;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBranch(String branch) {
|
|
||||||
this.branch = branch;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Page<Commit> getCommitsPage() {
|
public Page<Commit> getCommitsPage() {
|
||||||
return commitsPage;
|
return commitsPage;
|
||||||
}
|
}
|
||||||
@ -48,10 +46,30 @@ public class FilterForm {
|
|||||||
this.commitsPage = commitsPage;
|
this.commitsPage = commitsPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getRepositoryUrl() {
|
||||||
|
return repositoryUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRepositoryUrl(String repositoryUrl) {
|
||||||
|
this.repositoryUrl = repositoryUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBranchName() {
|
||||||
|
return branchName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBranchName(String branchName) {
|
||||||
|
this.branchName = branchName;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "FilterForm{" +
|
return "FilterForm{" +
|
||||||
"subject='" + filter +
|
"filter='" + filter + '\'' +
|
||||||
|
", repositoryUrl='" + repositoryUrl + '\'' +
|
||||||
|
", branchName='" + branchName + '\'' +
|
||||||
|
", author='" + author + '\'' +
|
||||||
|
", commitsPage=" + commitsPage +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
package ru.ulstu.extractor.repository;
|
||||||
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
@ -9,6 +14,6 @@ import ru.ulstu.extractor.model.Repository;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface AuthorRepository extends JpaRepository<Author, Integer> {
|
public interface AuthorRepository extends JpaRepository<Author, Integer> {
|
||||||
@Query("SELECT a FROM Commit c, Repository r, Branch b, Author a WHERE c.author = a AND c.branch = b AND r = b.repository AND r = :repository AND b.name = :branchName")
|
@Query("SELECT DISTINCT a.name FROM Commit c, Repository r, Branch b, Author a WHERE c.author = a AND c.branch = b AND r = b.repository AND r = :repository AND b.name = :branchName AND a.name IS NOT NULL AND a.name <> '' ORDER BY a.name")
|
||||||
List<Author> findByRepositoryAndBranch(@Param("repository") Repository repository, @Param("branchName") String branchName);
|
List<String> findByRepositoryAndBranch(@Param("repository") Repository repository, @Param("branchName") String branchName);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
package ru.ulstu.extractor.repository;
|
||||||
|
|
||||||
import org.springframework.data.domain.Page;
|
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.jpa.repository.Query;
|
||||||
import org.springframework.data.repository.query.Param;
|
import org.springframework.data.repository.query.Param;
|
||||||
import ru.ulstu.extractor.model.Commit;
|
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 ru.ulstu.extractor.model.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public interface CommitRepository extends JpaRepository<Commit, Integer> {
|
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")
|
@Query("SELECT c FROM Commit c, Repository r, Branch b, Author a WHERE c.branch = b AND r = b.repository AND a = c.author AND r = :repository AND b.name = :branchName AND (:author IS NULL OR :author = '' OR a.name = :author) AND (:filter IS NULL OR :filter = '' OR lower(c.message) LIKE lower(concat('%', :filter,'%')))")
|
||||||
Page<Commit> findByRepositoryAndBranch(Pageable pageable, @Param("repository") Repository repository, @Param("branchName") String branchName);
|
Page<Commit> findByRepositoryAndBranch(Pageable pageable, @Param("repository") Repository repository, @Param("branchName") String branchName, @Param("author") String author, @Param("filter") String filter);
|
||||||
|
|
||||||
|
@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();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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.service;
|
package ru.ulstu.extractor.service;
|
||||||
|
|
||||||
|
import com.sun.istack.NotNull;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.ulstu.extractor.model.Commit;
|
||||||
|
import ru.ulstu.extractor.repository.AuthorRepository;
|
||||||
|
import ru.ulstu.extractor.repository.CommitRepository;
|
||||||
|
import ru.ulstu.extractor.repository.RepositoryRepository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class FilteringService {
|
public class FilteringService {
|
||||||
|
private final AuthorRepository authorRepository;
|
||||||
|
private final CommitRepository commitRepository;
|
||||||
|
private final RepositoryRepository repositoryRepository;
|
||||||
|
|
||||||
private final IndexService indexService;
|
public FilteringService(AuthorRepository authorRepository,
|
||||||
|
CommitRepository commitRepository,
|
||||||
|
RepositoryRepository repositoryRepository) {
|
||||||
|
this.authorRepository = authorRepository;
|
||||||
|
this.commitRepository = commitRepository;
|
||||||
|
this.repositoryRepository = repositoryRepository;
|
||||||
|
}
|
||||||
|
|
||||||
public FilteringService(IndexService indexService) {
|
public List<String> getRepositoryAuthors(@NotNull String repositoryUrl,
|
||||||
this.indexService = indexService;
|
@NotNull String branchName) {
|
||||||
|
return authorRepository.findByRepositoryAndBranch(
|
||||||
|
repositoryRepository.findByUrl(repositoryUrl),
|
||||||
|
branchName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Page<Commit> getCommits(@NotNull String repositoryUrl,
|
||||||
|
@NotNull String branchName,
|
||||||
|
String author,
|
||||||
|
String filter,
|
||||||
|
Pageable pageable) {
|
||||||
|
return commitRepository.findByRepositoryAndBranch(
|
||||||
|
pageable,
|
||||||
|
repositoryRepository.findByUrl(repositoryUrl),
|
||||||
|
branchName,
|
||||||
|
author,
|
||||||
|
filter
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ import org.eclipse.jgit.api.ListBranchCommand;
|
|||||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||||
import org.eclipse.jgit.diff.DiffFormatter;
|
import org.eclipse.jgit.diff.DiffFormatter;
|
||||||
import org.eclipse.jgit.internal.storage.file.FileRepository;
|
import org.eclipse.jgit.internal.storage.file.FileRepository;
|
||||||
import org.eclipse.jgit.lib.Ref;
|
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
import org.eclipse.jgit.revwalk.RevCommit;
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
@ -26,6 +25,9 @@ import ru.ulstu.extractor.model.LineChange;
|
|||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -42,20 +44,32 @@ public class GitRepositoryService {
|
|||||||
@Value("${extractor.custom-projects-dir}")
|
@Value("${extractor.custom-projects-dir}")
|
||||||
private String customProjectsDir;
|
private String customProjectsDir;
|
||||||
|
|
||||||
public void cloneOrUpdateRepo(String url) throws GitAPIException, IOException {
|
public List<Branch> getRemoteBranches(String url) throws GitAPIException, IOException {
|
||||||
Git git;
|
cloneOrUpdateRepo(url);
|
||||||
if (projectDirExists(getProjectDirectoryFile(url))) {
|
|
||||||
Repository localRepo = new FileRepository(getProjectGitDirectory(url));
|
Repository localRepo = new FileRepository(getProjectGitDirectory(url));
|
||||||
git = new Git(localRepo);
|
Git git = new Git(localRepo);
|
||||||
git.pull().call();
|
List<Branch> branches = git.branchList().setListMode(ListBranchCommand.ListMode.REMOTE)
|
||||||
localRepo.close();
|
.call()
|
||||||
} else {
|
.stream()
|
||||||
git = Git.cloneRepository()
|
.map(r -> new Branch(r.getName().replace(BRANCH_PREFIX, "")))
|
||||||
.setURI(url)
|
.collect(Collectors.toList());
|
||||||
.setDirectory(getProjectDirectoryFile(url))
|
|
||||||
.call();
|
|
||||||
}
|
|
||||||
git.close();
|
git.close();
|
||||||
|
localRepo.close();
|
||||||
|
return branches;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Branch> getLocalBranches(String url) throws GitAPIException, IOException {
|
||||||
|
cloneOrUpdateRepo(url);
|
||||||
|
Repository localRepo = new FileRepository(getProjectGitDirectory(url));
|
||||||
|
Git git = new Git(localRepo);
|
||||||
|
List<Branch> branches = git.branchList()
|
||||||
|
.call()
|
||||||
|
.stream()
|
||||||
|
.map(r -> new Branch(r.getName().replace(BRANCH_PREFIX, "")))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
git.close();
|
||||||
|
localRepo.close();
|
||||||
|
return branches;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getProjectDirectory(String url) {
|
private String getProjectDirectory(String url) {
|
||||||
@ -83,12 +97,18 @@ public class GitRepositoryService {
|
|||||||
Git git = new Git(localRepo);
|
Git git = new Git(localRepo);
|
||||||
git.pull().call();
|
git.pull().call();
|
||||||
if (!localRepo.getBranch().equals(branchName)) {
|
if (!localRepo.getBranch().equals(branchName)) {
|
||||||
Ref ref = git.checkout().
|
if (getLocalBranches(repositoryUrl).stream().anyMatch(localBranch -> localBranch.getName().contains(branchName))) {
|
||||||
setCreateBranch(true).
|
git.checkout()
|
||||||
setName(branchName).
|
.setName(branchName)
|
||||||
setUpstreamMode(CreateBranchCommand.SetupUpstreamMode.TRACK).
|
.call();
|
||||||
setStartPoint("origin/" + branchName).
|
} else {
|
||||||
call();
|
git.checkout()
|
||||||
|
.setCreateBranch(true)
|
||||||
|
.setName(branchName)
|
||||||
|
.setUpstreamMode(CreateBranchCommand.SetupUpstreamMode.TRACK)
|
||||||
|
.setStartPoint("origin/" + branchName)
|
||||||
|
.call();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
List<RevCommit> commits = new ArrayList<>();
|
List<RevCommit> commits = new ArrayList<>();
|
||||||
git.log().call().forEach(commits::add);
|
git.log().call().forEach(commits::add);
|
||||||
@ -112,7 +132,58 @@ public class GitRepositoryService {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FileChange> findDiffBetweenTwoRevisions(RevCommit laterCommit, RevCommit earlierCommit, Repository localRepo) {
|
public void remove(String repositoryUrl) throws IOException {
|
||||||
|
FileUtils.deleteDirectory(getProjectDirectoryFile(repositoryUrl));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cloneOrUpdateRepo(String url) throws GitAPIException, IOException {
|
||||||
|
Git git;
|
||||||
|
if (projectDirExists(getProjectDirectoryFile(url))) {
|
||||||
|
Repository localRepo = new FileRepository(getProjectGitDirectory(url));
|
||||||
|
git = new Git(localRepo);
|
||||||
|
git.pull().call();
|
||||||
|
localRepo.close();
|
||||||
|
} else {
|
||||||
|
git = Git.cloneRepository()
|
||||||
|
.setURI(url)
|
||||||
|
.setDirectory(getProjectDirectoryFile(url))
|
||||||
|
.call();
|
||||||
|
}
|
||||||
|
git.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getProjectDirectory(String url) {
|
||||||
|
return (isBlank(customProjectsDir)
|
||||||
|
? System.getProperty("java.io.tmpdir")
|
||||||
|
: customProjectsDir) + url.substring(url.lastIndexOf('/'));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getProjectGitDirectory(String url) {
|
||||||
|
return getProjectDirectory(url) + "/.git";
|
||||||
|
}
|
||||||
|
|
||||||
|
private File getProjectDirectoryFile(String url) {
|
||||||
|
validateUrl(url);
|
||||||
|
return Path.of(getProjectDirectory(url))
|
||||||
|
.toFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateUrl(String url) {
|
||||||
|
if (url == null || url.isEmpty()) {
|
||||||
|
throw new RuntimeException("Repository url must not empty");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
new URL(url).toURI();
|
||||||
|
} catch (MalformedURLException | URISyntaxException e) {
|
||||||
|
throw new RuntimeException("Repository url not valid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean projectDirExists(File file) {
|
||||||
|
return file.exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<FileChange> findDiffBetweenTwoRevisions(RevCommit laterCommit, RevCommit earlierCommit, Repository localRepo) {
|
||||||
if (laterCommit == null || earlierCommit == null) {
|
if (laterCommit == null || earlierCommit == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -210,22 +281,4 @@ public class GitRepositoryService {
|
|||||||
}
|
}
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Branch> getBranches(String url) throws GitAPIException, IOException {
|
|
||||||
cloneOrUpdateRepo(url);
|
|
||||||
Repository localRepo = new FileRepository(getProjectGitDirectory(url));
|
|
||||||
Git git = new Git(localRepo);
|
|
||||||
List<Branch> branches = git.branchList().setListMode(ListBranchCommand.ListMode.REMOTE)
|
|
||||||
.call()
|
|
||||||
.stream()
|
|
||||||
.map(r -> new Branch(r.getName().replace(BRANCH_PREFIX, "")))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
git.close();
|
|
||||||
localRepo.close();
|
|
||||||
return branches;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove(String repositoryUrl) throws IOException {
|
|
||||||
FileUtils.deleteDirectory(getProjectDirectoryFile(repositoryUrl));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* 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.service;
|
package ru.ulstu.extractor.service;
|
||||||
|
|
||||||
import com.sun.istack.NotNull;
|
import com.sun.istack.NotNull;
|
||||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||||
import org.springframework.data.domain.Page;
|
|
||||||
import org.springframework.data.domain.Pageable;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import ru.ulstu.extractor.model.Author;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import ru.ulstu.extractor.model.Branch;
|
import ru.ulstu.extractor.model.Branch;
|
||||||
import ru.ulstu.extractor.model.Commit;
|
import ru.ulstu.extractor.model.Commit;
|
||||||
import ru.ulstu.extractor.model.Repository;
|
import ru.ulstu.extractor.model.Repository;
|
||||||
import ru.ulstu.extractor.repository.AuthorRepository;
|
|
||||||
import ru.ulstu.extractor.repository.BranchRepository;
|
import ru.ulstu.extractor.repository.BranchRepository;
|
||||||
import ru.ulstu.extractor.repository.CommitRepository;
|
import ru.ulstu.extractor.repository.CommitRepository;
|
||||||
import ru.ulstu.extractor.repository.RepositoryRepository;
|
import ru.ulstu.extractor.repository.RepositoryRepository;
|
||||||
@ -23,43 +25,32 @@ public class IndexService {
|
|||||||
private final RepositoryRepository repositoryRepository;
|
private final RepositoryRepository repositoryRepository;
|
||||||
private final BranchRepository branchRepository;
|
private final BranchRepository branchRepository;
|
||||||
private final CommitRepository commitRepository;
|
private final CommitRepository commitRepository;
|
||||||
private final AuthorRepository authorRepository;
|
|
||||||
|
|
||||||
|
|
||||||
public IndexService(GitRepositoryService gitRepositoryService,
|
public IndexService(GitRepositoryService gitRepositoryService,
|
||||||
RepositoryRepository repositoryRepository,
|
RepositoryRepository repositoryRepository,
|
||||||
BranchRepository branchRepository,
|
BranchRepository branchRepository,
|
||||||
CommitRepository commitRepository,
|
CommitRepository commitRepository) {
|
||||||
AuthorRepository authorRepository) {
|
|
||||||
this.gitRepositoryService = gitRepositoryService;
|
this.gitRepositoryService = gitRepositoryService;
|
||||||
this.repositoryRepository = repositoryRepository;
|
this.repositoryRepository = repositoryRepository;
|
||||||
this.branchRepository = branchRepository;
|
this.branchRepository = branchRepository;
|
||||||
this.commitRepository = commitRepository;
|
this.commitRepository = commitRepository;
|
||||||
this.authorRepository = authorRepository;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
public void index(@NotNull String repositoryUrl, @NotNull String branchName) throws GitAPIException, IOException {
|
public void index(@NotNull String repositoryUrl, @NotNull String branchName) throws GitAPIException, IOException {
|
||||||
Repository repository = repositoryRepository.findByUrl(repositoryUrl);
|
Repository repository = repositoryRepository.findByUrl(repositoryUrl);
|
||||||
if (repository == null) {
|
if (repository == null) {
|
||||||
repositoryRepository.save(new Repository(repositoryUrl));
|
repository = repositoryRepository.save(new Repository(repositoryUrl));
|
||||||
}
|
}
|
||||||
Branch branch = branchRepository.findByRepositoryAndName(repository, branchName);
|
Branch branch = branchRepository.findByRepositoryAndName(repository, branchName);
|
||||||
if (branch == null) {
|
if (branch == null) {
|
||||||
branchRepository.save(new Branch(repository, branchName));
|
branch = branchRepository.save(new Branch(repository, branchName));
|
||||||
}
|
}
|
||||||
List<Commit> commits = gitRepositoryService.getCommits(repositoryUrl, branchName);
|
List<Commit> commits = gitRepositoryService.getCommits(repositoryUrl, branchName);
|
||||||
commitRepository.deleteAll(branch.getCommits());
|
List<Commit> commitsToRemove = branch.getCommits();
|
||||||
branch.getCommits().clear();
|
branch.getCommits().clear();
|
||||||
|
commitRepository.deleteAll(commitsToRemove);
|
||||||
branch.setCommits(commits);
|
branch.setCommits(commits);
|
||||||
branchRepository.save(branch);
|
branchRepository.save(branch);
|
||||||
gitRepositoryService.remove(repositoryUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Author> getRepositoryAuthors(@NotNull String repositoryUrl, @NotNull String branchName) {
|
|
||||||
return authorRepository.findByRepositoryAndBranch(repositoryRepository.findByUrl(repositoryUrl), branchName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Page<Commit> getCommits(@NotNull String repositoryUrl, @NotNull String branchName, Pageable pageable) {
|
|
||||||
return commitRepository.findByRepositoryAndBranch(pageable, repositoryRepository.findByUrl(repositoryUrl), branchName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
|
#
|
||||||
|
# Copyright (C) 2021 Anton Romanov - All Rights Reserved
|
||||||
|
# You may use, distribute and modify this code, please write to: romanov73@gmail.com.
|
||||||
|
#
|
||||||
|
|
||||||
spring.main.banner-mode=off
|
spring.main.banner-mode=off
|
||||||
server.port=8080
|
server.port=8080
|
||||||
|
server.jetty.connection-idle-timeout=1000s
|
||||||
# Available levels are: TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF
|
# Available levels are: TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF
|
||||||
logging.level.ru.ulstu=DEBUG
|
logging.level.ru.ulstu=DEBUG
|
||||||
extractor.custom-projects-dir=
|
extractor.custom-projects-dir=
|
||||||
|
@ -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.app-name=GitExtractor v0.1.0
|
||||||
messages.menu.home=Main
|
messages.menu.home=Main
|
||||||
messages.menu.indexed-repos=List of indexed repos
|
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
|
@ -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.app-name=GitExtractor v0.1.0
|
||||||
messages.menu.home=Main
|
messages.menu.home=Main
|
||||||
messages.menu.indexed-repos=List of indexed repos
|
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
|
@ -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.app-name=GitЁxtractor v0.1.0
|
||||||
messages.menu.home=На главную
|
messages.menu.home=На главную
|
||||||
messages.menu.indexed-repos=Список проиндексированных репозиториев
|
messages.menu.indexed-repos=Список проиндексированных репозиториев
|
||||||
messages.menu.new-repo=Анализ нового репозитория
|
messages.menu.new-repo=Анализ нового репозитория
|
||||||
|
messages.menu.statistic=Статистика
|
@ -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.
|
||||||
|
-->
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="ru"
|
<html lang="ru"
|
||||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.w3.org/1999/xhtml">
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:th="http://www.w3.org/1999/xhtml">
|
||||||
@ -22,10 +27,15 @@
|
|||||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||||
<ul class="navbar-nav mr-auto">
|
<ul class="navbar-nav mr-auto">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/" th:text="#{messages.menu.new-repo}">Link</a>
|
<a class="nav-link" th:href="${@route.INDEXING_NEW_REPOSITORY}"
|
||||||
|
th:text="#{messages.menu.new-repo}">Link</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/indexRepo" th:text="#{messages.menu.indexed-repos}">Link</a>
|
<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>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -41,6 +51,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<ul id="messages" class="feedback-panel">
|
<ul id="messages" class="feedback-panel">
|
||||||
|
<div class="alert alert-danger" role="alert" th:if="${error}" th:text="${error}">
|
||||||
|
</div>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div layout:fragment="content">
|
<div layout:fragment="content">
|
||||||
|
@ -1,18 +1,17 @@
|
|||||||
|
<!--
|
||||||
|
~ 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">
|
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||||
xmlns:th="http://www.thymeleaf.org"
|
xmlns:th="http://www.thymeleaf.org"
|
||||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
layout:decorate="~{default}">
|
layout:decorate="~{default}">
|
||||||
|
|
||||||
<!--<head th:substituteby="header :: copy"></head>-->
|
|
||||||
|
|
||||||
<div class="container" layout:fragment="content">
|
<div class="container" layout:fragment="content">
|
||||||
<h1>Ошибка</h1>
|
<h1>Ошибка</h1>
|
||||||
|
|
||||||
<!-- As we are using Thymeleaf, you might consider using
|
|
||||||
${#httpServletRequest.requestURL}. But that returns the path
|
|
||||||
to this error page. Hence we explicitly add the url to the
|
|
||||||
Model in some of the example code. -->
|
|
||||||
<p th:if="${url}">
|
<p th:if="${url}">
|
||||||
<b>Страница:</b> <span th:text="${url}">Page URL</span>
|
<b>Страница:</b> <span th:text="${url}">Page URL</span>
|
||||||
</p>
|
</p>
|
||||||
@ -34,14 +33,16 @@
|
|||||||
<div class="collapse" id="collapseExample">
|
<div class="collapse" id="collapseExample">
|
||||||
<p class="card card-body">
|
<p class="card card-body">
|
||||||
<div th:utext="'Failed URL: ' + ${url}" th:remove="tag">${url}</div>
|
<div th:utext="'Failed URL: ' + ${url}" th:remove="tag">${url}</div>
|
||||||
<div th:if="${exception}">
|
</p>
|
||||||
<div th:utext="'Exception: ' + ${exception.message}" th:remove="tag">${exception.message}</div>
|
<div th:if="${exception != null}" th:utext="'Exception: ' + ${exception.message}" th:remove="tag">
|
||||||
|
${exception.message}
|
||||||
|
</div>
|
||||||
<ul th:remove="tag">
|
<ul th:remove="tag">
|
||||||
<li th:each="ste : ${exception.stackTrace}" th:remove="tag"><span
|
<li th:if="${exception != null && exception.stackTrace != null}" th:each="ste : ${exception.stackTrace}"
|
||||||
|
th:remove="tag"><span
|
||||||
th:utext="${ste}" th:remove="tag">${ste}</span></li>
|
th:utext="${ste}" th:remove="tag">${ste}</span></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</html>
|
</html>
|
112
src/main/resources/templates/filterCommits.html
Normal file
112
src/main/resources/templates/filterCommits.html
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
<!--
|
||||||
|
~ 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:th="http://www.thymeleaf.org"
|
||||||
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
|
layout:decorate="~{default}">
|
||||||
|
<div class="container" layout:fragment="content">
|
||||||
|
<style>
|
||||||
|
.pagination {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination a {
|
||||||
|
color: black;
|
||||||
|
float: left;
|
||||||
|
padding: 5px 5px;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination a.active {
|
||||||
|
background-color: gray;
|
||||||
|
color: white;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<form action="#" th:action="${@route.FILTER_COMMITS}" th:object="${filterForm}" method="get">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-1 col-sm-12">
|
||||||
|
Автор
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3 col-sm-12">
|
||||||
|
<select id="select-author" class="selectpicker" data-live-search="true" th:field="*{author}"
|
||||||
|
data-width="90%">
|
||||||
|
<option value="">Все авторы</option>
|
||||||
|
<option th:each="author : ${authors}"
|
||||||
|
th:value="${author}"
|
||||||
|
th:utext="${author}">
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<script th:inline="javascript">
|
||||||
|
$('select[name=selValue]').val([[*{author}]]);
|
||||||
|
$('#select-author').selectpicker('refresh');
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1 col-sm-12">
|
||||||
|
Дата:
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3 col-sm-12">
|
||||||
|
<select class="selectpicker" data-live-search="true">
|
||||||
|
<option data-tokens="day">день</option>
|
||||||
|
<option data-tokens="month">месяц</option>
|
||||||
|
<option data-tokens="age">год</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1 col-sm-12">
|
||||||
|
-
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3 col-sm-12">
|
||||||
|
<select class="selectpicker" data-live-search="true">
|
||||||
|
<option data-tokens="day">день</option>
|
||||||
|
<option data-tokens="month">месяц</option>
|
||||||
|
<option data-tokens="age">год</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-2 col-sm-12">
|
||||||
|
Искать по тексту:
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 col-sm-12">
|
||||||
|
<input type="text" class="form-control" size="40" th:field="*{filter}">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4 col-sm-12">
|
||||||
|
<input type="submit" class="btn btn-outline-success w-100" value="Применить фильтр"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input type="hidden" th:field="*{repositoryUrl}">
|
||||||
|
<input type="hidden" th:field="*{branchName}">
|
||||||
|
<table class="table table-striped">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th scope="col">Автор</th>
|
||||||
|
<th scope="col" style="width: 30%">Дата</th>
|
||||||
|
<th scope="col">Сообщение</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr th:each="commit: ${filterForm.commitsPage.content}">
|
||||||
|
<td th:text="${commit.author.name}"></td>
|
||||||
|
<td th:text="${commit.date}"></td>
|
||||||
|
<td th:text="${commit.message}"></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
Страницы:
|
||||||
|
<div th:if="${filterForm.commitsPage.totalPages > 0}" class="pagination"
|
||||||
|
th:each="pageNumber : ${pageNumbers}">
|
||||||
|
<a th:href="@{/filterCommits(size=${filterForm.commitsPage.size}, page=${pageNumber},
|
||||||
|
repositoryUrl=${filterForm.repositoryUrl},
|
||||||
|
branchName=${filterForm.branchName},
|
||||||
|
author=${filterForm.author},
|
||||||
|
filter=${filterForm.filter})}"
|
||||||
|
th:text=${pageNumber}
|
||||||
|
th:class="${pageNumber == filterForm.commitsPage.number} ? active"></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</html>
|
@ -1,58 +0,0 @@
|
|||||||
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
|
|
||||||
<html xmlns:th="http://www.thymeleaf.org"
|
|
||||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
|
||||||
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">
|
|
||||||
<form action="#" th:action="@{/sendFilter}" th:object="${filterForm}" method="post">
|
|
||||||
<p><b>Фильтровать данные:</b><Br></p>
|
|
||||||
По автору
|
|
||||||
<select class="selectpicker" data-live-search="true">
|
|
||||||
</select>
|
|
||||||
Дата с
|
|
||||||
<select class="selectpicker" data-live-search="true">
|
|
||||||
<option data-tokens="day">день</option>
|
|
||||||
<option data-tokens="month">месяц</option>
|
|
||||||
<option data-tokens="age">год</option>
|
|
||||||
</select>
|
|
||||||
по
|
|
||||||
<select class="selectpicker" data-live-search="true">
|
|
||||||
<option data-tokens="day">день</option>
|
|
||||||
<option data-tokens="month">месяц</option>
|
|
||||||
<option data-tokens="age">год</option>
|
|
||||||
</select>
|
|
||||||
<p>Строки:<br>
|
|
||||||
<input type="text" size="40" th:field="*{filter}">
|
|
||||||
<input type="hidden" th:field="*{url}">
|
|
||||||
</p>
|
|
||||||
<p style="color:red" th:text="${error}"></p>
|
|
||||||
<table class="table table-striped">
|
|
||||||
<thead class="thead-dark">
|
|
||||||
<tr>
|
|
||||||
<th scope="col">Author</th>
|
|
||||||
<th scope="col" style="width: 30%">Date</th>
|
|
||||||
<th scope="col">Commit</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr th:each="commit: ${filterForm.commitsPage.content}">
|
|
||||||
<td th:text="${commit.author.name}"></td>
|
|
||||||
<td th:text="${commit.date}"></td>
|
|
||||||
<td th:text="${commit.message}"></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<p>
|
|
||||||
<input type="submit" value="Отправить"/>
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div th:if="${filterForm.commitPage.totalPages > 0}" class="pagination"
|
|
||||||
th:each="pageNumber : ${pageNumbers}">
|
|
||||||
<a th:href="@{/filtering.html(size=${commitPage.size}, page=${pageNumber})}"
|
|
||||||
th:class="${pageNumber==commitPage.number + 1} ? active"></a>
|
|
||||||
</div>
|
|
||||||
</html>
|
|
@ -1,32 +0,0 @@
|
|||||||
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
|
|
||||||
<html xmlns:th="http://www.thymeleaf.org"
|
|
||||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
|
||||||
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">
|
|
||||||
<h1>Форма</h1>
|
|
||||||
<form action="#" th:action="@{/sendEmail}" th:object="${emailForm}" method="post">
|
|
||||||
<p style="color:red" th:text="${error}"></p>
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td>Тема:</td>
|
|
||||||
<td><input type="text" th:field="*{subject}"/></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Кому:</td>
|
|
||||||
<td><input type="text" th:field="*{to}"/></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Сообщение:</td>
|
|
||||||
<td><textarea th:field="*{message}"/></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td colspan="2"><input type="submit" value="Отправить"/></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</html>
|
|
@ -1,21 +1,22 @@
|
|||||||
|
<!--
|
||||||
|
~ 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">
|
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
|
||||||
<html xmlns:th="http://www.thymeleaf.org"
|
<html xmlns:th="http://www.thymeleaf.org"
|
||||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
layout:decorate="~{default}">
|
layout:decorate="~{default}">
|
||||||
<head>
|
|
||||||
<title>Индексировать новый репозиторий</title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
|
||||||
</head>
|
|
||||||
<div class="container" layout:fragment="content">
|
<div class="container" layout:fragment="content">
|
||||||
<form action="#" th:action="@{/newRepo}" th:object="${repoForm}" method="post">
|
<form action="#" th:action="${@route.INDEXING_NEW_REPOSITORY}" th:object="${repoForm}" method="post">
|
||||||
<p style="color:red" th:text="${error}"></p>
|
|
||||||
<button class="btn btn-outline-dark dropdown-toggle" type="button" data-toggle="collapse"
|
<button class="btn btn-outline-dark dropdown-toggle" type="button" data-toggle="collapse"
|
||||||
data-target="#collapseOne" aria-expanded="false" aria-controls="collapseExample"
|
data-target="#collapseOne" aria-expanded="false" aria-controls="collapseExample"
|
||||||
th:if="${repoForm.repo != null}"
|
th:if="${repoForm.repo != '' && repoForm.repo != null && (error == '' || error == null)}"
|
||||||
th:text="${repoForm.repo == null ? 'Репозиторий' : repoForm.repo}">
|
th:text="${repoForm.repo == '' || repoForm.repo == null ? 'Репозиторий' : repoForm.repo}">
|
||||||
Button with data-target
|
Button with data-target
|
||||||
</button>
|
</button>
|
||||||
<div id="collapseOne" th:class="${repoForm.repo == null ? 'collapse show' : 'collapse'}"
|
<div id="collapseOne"
|
||||||
|
th:class="${repoForm.repo == '' || repoForm.repo == null || (error != '' && error != null) ? 'collapse show' : 'collapse'}"
|
||||||
aria-labelledby="headingOne">
|
aria-labelledby="headingOne">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -34,7 +35,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="collapseTwo" class="collapse show" aria-labelledby="headingOne" th:if="${repoForm.repo != null}">
|
<div id="collapseTwo" class="collapse show" aria-labelledby="headingOne"
|
||||||
|
th:if="${repoForm.repo != '' && repoForm.repo != null && (error == '' || error == null) }">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="select-branch">Ветки:</label>
|
<label for="select-branch">Ветки:</label>
|
||||||
@ -44,7 +46,7 @@
|
|||||||
data-width="90%">
|
data-width="90%">
|
||||||
<option th:each="branch : ${branches}"
|
<option th:each="branch : ${branches}"
|
||||||
th:value="${branch.name}"
|
th:value="${branch.name}"
|
||||||
th:utext="${branch.name}"/>
|
th:utext="${branch.name}">
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
@ -1,11 +1,12 @@
|
|||||||
|
<!--
|
||||||
|
~ 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">
|
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
|
||||||
<html xmlns:th="http://www.thymeleaf.org"
|
<html xmlns:th="http://www.thymeleaf.org"
|
||||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
layout:decorate="~{default}">
|
layout:decorate="~{default}">
|
||||||
<head>
|
|
||||||
<title>Проиндексированные репозитории</title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
|
||||||
</head>
|
|
||||||
<div class="container" layout:fragment="content">
|
<div class="container" layout:fragment="content">
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<thead class="thead-dark">
|
<thead class="thead-dark">
|
||||||
@ -15,7 +16,8 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr th:each="branch: ${branches}">
|
<tr th:each="branch: ${branches}">
|
||||||
<td><a th:href="@{'/filtering?branchName='+${branch.name}+'&repositoryUrl='+${repository.url}}"
|
<td>
|
||||||
|
<a th:href="@{${@route.FILTER_COMMITS} + '?branchName='+${branch.name}+'&repositoryUrl='+${repository.url}}"
|
||||||
th:text="${branch.name}"/></td>
|
th:text="${branch.name}"/></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
@ -1,11 +1,12 @@
|
|||||||
|
<!--
|
||||||
|
~ 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">
|
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
|
||||||
<html xmlns:th="http://www.thymeleaf.org"
|
<html xmlns:th="http://www.thymeleaf.org"
|
||||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
layout:decorate="~{default}">
|
layout:decorate="~{default}">
|
||||||
<head>
|
|
||||||
<title>Проиндексированные репозитории</title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
|
||||||
</head>
|
|
||||||
<div class="container" layout:fragment="content">
|
<div class="container" layout:fragment="content">
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<thead class="thead-dark">
|
<thead class="thead-dark">
|
||||||
@ -15,7 +16,8 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr th:each="repo: ${repositories}">
|
<tr th:each="repo: ${repositories}">
|
||||||
<td><a th:href="@{'/details?repositoryId='+${repo.id}}" th:text="${repo.url}"></td>
|
<td><a th:href="@{${@route.LIST_REPOSITORY_BRANCHES} + '?repositoryId=' + ${repo.id}}"
|
||||||
|
th:text="${repo.url}"></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
@ -1,18 +0,0 @@
|
|||||||
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
|
|
||||||
<html
|
|
||||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
|
||||||
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">
|
|
||||||
<body>
|
|
||||||
<form oninput="result">
|
|
||||||
<p>Данные репозитория:</p>
|
|
||||||
<p>
|
|
||||||
<output name="result"></output>
|
|
||||||
</form>
|
|
||||||
</body>
|
|
||||||
</div>
|
|
||||||
</html>
|
|
183
src/main/resources/templates/statistic.html
Normal file
183
src/main/resources/templates/statistic.html
Normal 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>
|
Loading…
Reference in New Issue
Block a user