Merge branch 'master' into 18-statistics-page

This commit is contained in:
Anton Romanov 2021-04-08 11:26:32 +04:00
commit 26942c6e88
22 changed files with 452 additions and 270 deletions

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.config;
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.WebMvcConfigurer;
import static ru.ulstu.extractor.controller.Route.LIST_INDEXED_REPOSITORIES;
@Configuration
public class MvcConfiguration implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/{articlename:\\w+}");
registry.addRedirectViewController("/", "/newRepo");
registry.addRedirectViewController("/", LIST_INDEXED_REPOSITORIES);
registry.addRedirectViewController("/default", "/home");
}

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.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.RepositoryRepository;
import static ru.ulstu.extractor.controller.Route.LIST_REPOSITORY_BRANCHES;
@Controller
public class BranchController {
private final RepositoryRepository repositoryRepository;
@ -17,12 +24,12 @@ public class BranchController {
this.branchRepository = branchRepository;
}
@GetMapping("/details")
@GetMapping(LIST_REPOSITORY_BRANCHES)
public String indexBranch(
Model model,
@RequestParam int repositoryId) {
model.addAttribute("branches", branchRepository.findByRepositoryId(repositoryId));
model.addAttribute("repository", repositoryRepository.findById(repositoryId).get());
return "indexBranch";
return LIST_REPOSITORY_BRANCHES;
}
}

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.controller;
import org.springframework.data.domain.Page;
@ -11,36 +16,24 @@ import ru.ulstu.extractor.model.Commit;
import ru.ulstu.extractor.model.OffsetablePageRequest;
import ru.ulstu.extractor.model.mvc.FilterForm;
import ru.ulstu.extractor.service.FilteringService;
import ru.ulstu.extractor.service.IndexService;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import static ru.ulstu.extractor.controller.Route.FILTER_COMMITS;
@Controller
public class GitFilteringController {
private final static int DEFAULT_PAGE_SIZE = 20;
private final FilteringService filteringService;
private final IndexService indexService;
public GitFilteringController(FilteringService filteringService,
IndexService indexService) {
public GitFilteringController(FilteringService filteringService) {
this.filteringService = filteringService;
this.indexService = indexService;
}
/* @PostMapping("/sendFilter")
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)
@RequestMapping(value = FILTER_COMMITS, method = RequestMethod.GET)
public String listCommits(
Model model,
@ModelAttribute FilterForm filterForm,
@ -49,9 +42,11 @@ public class GitFilteringController {
@RequestParam String repositoryUrl,
@RequestParam String branchName) {
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));
Page<Commit> commitsPage = filteringService.getCommits(repositoryUrl,
branchName,
new OffsetablePageRequest(currentPage - 1, pageSize));
int totalPages = commitsPage.getTotalPages();
if (totalPages > 0) {
List<Integer> pageNumbers = IntStream.rangeClosed(1, totalPages)
@ -59,11 +54,11 @@ public class GitFilteringController {
.collect(Collectors.toList());
model.addAttribute("pageNumbers", pageNumbers);
}
filterForm = new FilterForm();
filterForm.setCommitsPage(commitsPage);
filterForm.setBranch(branchName);
filterForm.setUrl(repositoryUrl);
model.addAttribute("filterForm", filterForm);
return "filtering";
model.addAttribute("authors", filteringService.getRepositoryAuthors(repositoryUrl, branchName));
return FILTER_COMMITS;
}
}

View File

@ -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;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
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.IndexService;
import java.io.IOException;
import java.util.List;
import static ru.ulstu.extractor.controller.Route.FILTER_COMMITS;
import static ru.ulstu.extractor.controller.Route.INDEXING_NEW_REPOSITORY;
@Controller
public class GitIndexingController {
private final static Logger LOG = LoggerFactory.getLogger(GitIndexingController.class);
private final GitRepositoryService gitRepositoryService;
private final IndexService indexService;
@ -26,40 +39,39 @@ public class GitIndexingController {
this.indexService = indexService;
}
@GetMapping("/newRepo")
@GetMapping(INDEXING_NEW_REPOSITORY)
public String indexNewRepo(Model model) {
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) {
try {
gitRepositoryService.cloneOrUpdateRepo(repoForm.getRepo());
List<Branch> branches = gitRepositoryService.getBranches(repoForm.getRepo());
List<Branch> branches = gitRepositoryService.getRemoteBranches(repoForm.getRepo());
model.addAttribute("branches", branches);
return "newRepo";
} catch (Exception ex) {
model.addAttribute("error", ex.getMessage());
return "newRepo";
}
return INDEXING_NEW_REPOSITORY;
}
@RequestMapping(value = "/newRepo", method = RequestMethod.POST, params = "next")
public String setBranch(@ModelAttribute RepoForm repoForm, Model model, RedirectAttributes redirectAttributes) {
@RequestMapping(value = INDEXING_NEW_REPOSITORY, method = RequestMethod.POST, params = "next")
public String indexBranch(@ModelAttribute RepoForm repoForm, Model model, RedirectAttributes redirectAttributes) {
model.addAttribute("filterForm", new FilterForm(repoForm.getRepo()));
if (repoForm.getBranch() == null) {
return "newRepo";
return INDEXING_NEW_REPOSITORY;
} else {
try {
indexService.index(repoForm.getRepo(), repoForm.getBranch());
} catch (Exception ex) {
} catch (IOException | GitAPIException ex) {
ex.printStackTrace();
model.addAttribute("error", ex.getMessage());
return "newRepo";
return INDEXING_NEW_REPOSITORY;
}
redirectAttributes.addAttribute("repositoryUrl", repoForm.getRepo());
redirectAttributes.addAttribute("branchName", repoForm.getBranch());
return "redirect:/filtering";
return "redirect:/" + FILTER_COMMITS;
}
}
}

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.controller;
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 ru.ulstu.extractor.model.Commit;
import ru.ulstu.extractor.service.GitRepositoryService;
import ru.ulstu.extractor.service.IndexService;
import java.io.IOException;
import java.util.List;
@ -18,14 +24,12 @@ import static ru.ulstu.extractor.controller.RepoController.URL;
public class RepoController {
public static final String URL = "/";
private final GitRepositoryService gitRepositoryService;
private final IndexService indexService;
public RepoController(GitRepositoryService gitRepositoryService) {
public RepoController(GitRepositoryService gitRepositoryService,
IndexService indexService) {
this.gitRepositoryService = gitRepositoryService;
}
@GetMapping("clone")
public void cloneRepository(@RequestParam("url") String url) throws GitAPIException, IOException {
gitRepositoryService.cloneOrUpdateRepo(url);
this.indexService = indexService;
}
@GetMapping("commits")
@ -34,4 +38,11 @@ public class RepoController {
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;
}
}

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.controller;
import org.springframework.stereotype.Controller;
@ -5,17 +10,19 @@ import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import ru.ulstu.extractor.repository.RepositoryRepository;
import static ru.ulstu.extractor.controller.Route.LIST_INDEXED_REPOSITORIES;
@Controller
public class BaseIndexingController {
public class RepositoryController {
private final RepositoryRepository repositoryRepository;
public BaseIndexingController(RepositoryRepository repositoryRepository) {
public RepositoryController(RepositoryRepository repositoryRepository) {
this.repositoryRepository = repositoryRepository;
}
@GetMapping("/indexRepo")
@GetMapping(LIST_INDEXED_REPOSITORIES)
public String indexNewRepo(Model model) {
model.addAttribute("repositories", repositoryRepository.findAll());
return "indexRepo";
return LIST_INDEXED_REPOSITORIES;
}
}

View File

@ -0,0 +1,32 @@
/*
* 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 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;
}
}

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.model.mvc;
import org.springframework.data.domain.Page;
@ -7,11 +12,20 @@ public class FilterForm {
private String filter;
private String url;
private String branch;
private String author;
private Page<Commit> commitsPage;
public FilterForm() {
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public FilterForm(String url) {
this.url = url;
}

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.jpa.repository.JpaRepository;
@ -9,6 +14,6 @@ import ru.ulstu.extractor.model.Repository;
import java.util.List;
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")
List<Author> findByRepositoryAndBranch(@Param("repository") Repository repository, @Param("branchName") String 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<String> findByRepositoryAndBranch(@Param("repository") Repository repository, @Param("branchName") String branchName);
}

View File

@ -1,13 +1,61 @@
/*
* 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;
import com.sun.istack.NotNull;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
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
public class FilteringService {
private final AuthorRepository authorRepository;
private final CommitRepository commitRepository;
private final RepositoryRepository repositoryRepository;
private final IndexService indexService;
public FilteringService(IndexService indexService) {
this.indexService = indexService;
public FilteringService(AuthorRepository authorRepository,
CommitRepository commitRepository,
RepositoryRepository repositoryRepository) {
this.authorRepository = authorRepository;
this.commitRepository = commitRepository;
this.repositoryRepository = repositoryRepository;
}
public List<String> 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
);
}
/* @PostMapping("/sendFilter")
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";
}*/
}

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.service;
import org.apache.commons.io.FileUtils;
@ -7,7 +12,6 @@ import org.eclipse.jgit.api.ListBranchCommand;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.springframework.beans.factory.annotation.Value;
@ -21,6 +25,9 @@ import ru.ulstu.extractor.model.LineChange;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.time.Instant;
import java.util.ArrayList;
@ -37,7 +44,80 @@ public class GitRepositoryService {
@Value("${extractor.custom-projects-dir}")
private String customProjectsDir;
public void cloneOrUpdateRepo(String url) throws GitAPIException, IOException {
public List<Branch> getRemoteBranches(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 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;
}
public List<Commit> getCommits(String repositoryUrl, String branchName) throws GitAPIException, IOException {
cloneOrUpdateRepo(repositoryUrl);
Repository localRepo = new FileRepository(getProjectGitDirectory(repositoryUrl));
Git git = new Git(localRepo);
git.pull().call();
if (!localRepo.getBranch().equals(branchName)) {
if (getLocalBranches(repositoryUrl).stream().anyMatch(localBranch -> localBranch.getName().contains(branchName))) {
git.checkout()
.setName(branchName)
.call();
} else {
git.checkout()
.setCreateBranch(true)
.setName(branchName)
.setUpstreamMode(CreateBranchCommand.SetupUpstreamMode.TRACK)
.setStartPoint("origin/" + branchName)
.call();
}
}
List<RevCommit> commits = new ArrayList<>();
git.log().call().forEach(commits::add);
List<Commit> list = new ArrayList<>();
RevCommit prevCommit = null;
for (RevCommit revCommit : commits) {
Commit commit = new Commit(
revCommit.getFullMessage(),
new Author(revCommit.getAuthorIdent().getName()),
Date.from(Instant.ofEpochSecond(revCommit.getCommitTime())),
revCommit.getName());
if (prevCommit != null) {
commit.setFileChanges(findDiffBetweenTwoRevisions(revCommit, prevCommit, localRepo));
}
list.add(commit);
prevCommit = revCommit;
}
git.close();
localRepo.close();
return list;
}
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));
@ -64,50 +144,27 @@ public class GitRepositoryService {
}
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();
}
public List<Commit> getCommits(String repositoryUrl, String branchName) throws GitAPIException, IOException {
cloneOrUpdateRepo(repositoryUrl);
Repository localRepo = new FileRepository(getProjectGitDirectory(repositoryUrl));
Git git = new Git(localRepo);
git.pull().call();
if (!localRepo.getBranch().equals(branchName)) {
Ref ref = git.checkout().
setCreateBranch(true).
setName(branchName).
setUpstreamMode(CreateBranchCommand.SetupUpstreamMode.TRACK).
setStartPoint("origin/" + branchName).
call();
}
List<RevCommit> commits = new ArrayList<>();
git.log().call().forEach(commits::add);
List<Commit> list = new ArrayList<>();
RevCommit prevCommit = null;
for (RevCommit revCommit : commits) {
Commit commit = new Commit(
revCommit.getFullMessage(),
new Author(revCommit.getAuthorIdent().getName()),
Date.from(Instant.ofEpochSecond(revCommit.getCommitTime())),
revCommit.getName());
if (prevCommit != null) {
commit.setFileChanges(findDiffBetweenTwoRevisions(revCommit, prevCommit, localRepo));
}
list.add(commit);
prevCommit = revCommit;
}
git.close();
localRepo.close();
return list;
}
public List<FileChange> findDiffBetweenTwoRevisions(RevCommit laterCommit, RevCommit earlierCommit, Repository localRepo) {
private List<FileChange> findDiffBetweenTwoRevisions(RevCommit laterCommit, RevCommit earlierCommit, Repository localRepo) {
if (laterCommit == null || earlierCommit == null) {
return null;
}
@ -205,22 +262,4 @@ public class GitRepositoryService {
}
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));
}
}

View File

@ -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;
import com.sun.istack.NotNull;
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 ru.ulstu.extractor.model.Author;
import org.springframework.transaction.annotation.Transactional;
import ru.ulstu.extractor.model.Branch;
import ru.ulstu.extractor.model.Commit;
import ru.ulstu.extractor.model.Repository;
import ru.ulstu.extractor.repository.AuthorRepository;
import ru.ulstu.extractor.repository.BranchRepository;
import ru.ulstu.extractor.repository.CommitRepository;
import ru.ulstu.extractor.repository.RepositoryRepository;
@ -23,43 +25,32 @@ public class IndexService {
private final RepositoryRepository repositoryRepository;
private final BranchRepository branchRepository;
private final CommitRepository commitRepository;
private final AuthorRepository authorRepository;
public IndexService(GitRepositoryService gitRepositoryService,
RepositoryRepository repositoryRepository,
BranchRepository branchRepository,
CommitRepository commitRepository,
AuthorRepository authorRepository) {
CommitRepository commitRepository) {
this.gitRepositoryService = gitRepositoryService;
this.repositoryRepository = repositoryRepository;
this.branchRepository = branchRepository;
this.commitRepository = commitRepository;
this.authorRepository = authorRepository;
}
@Transactional
public void index(@NotNull String repositoryUrl, @NotNull String branchName) throws GitAPIException, IOException {
Repository repository = repositoryRepository.findByUrl(repositoryUrl);
if (repository == null) {
repositoryRepository.save(new Repository(repositoryUrl));
repository = repositoryRepository.save(new Repository(repositoryUrl));
}
Branch branch = branchRepository.findByRepositoryAndName(repository, branchName);
if (branch == null) {
branchRepository.save(new Branch(repository, branchName));
branch = branchRepository.save(new Branch(repository, branchName));
}
List<Commit> commits = gitRepositoryService.getCommits(repositoryUrl, branchName);
commitRepository.deleteAll(branch.getCommits());
List<Commit> commitsToRemove = branch.getCommits();
branch.getCommits().clear();
commitRepository.deleteAll(commitsToRemove);
branch.setCommits(commits);
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);
}
}

View File

@ -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
server.port=8080
server.jetty.connection-idle-timeout=1000s
# Available levels are: TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF
logging.level.ru.ulstu=DEBUG
extractor.custom-projects-dir=

View File

@ -27,10 +27,12 @@
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<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 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>
@ -49,6 +51,8 @@
</div>
<div class="container-fluid">
<ul id="messages" class="feedback-panel">
<div class="alert alert-danger" role="alert" th:if="${error}" th:text="${error}">
</div>
</ul>
</div>
<div layout:fragment="content">

View File

@ -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">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<!--<head th:substituteby="header :: copy"></head>-->
<div class="container" layout:fragment="content">
<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}">
<b>Страница:</b> <span th:text="${url}">Page URL</span>
</p>
@ -34,11 +33,13 @@
<div class="collapse" id="collapseExample">
<p class="card card-body">
<div th:utext="'Failed URL: ' + ${url}" th:remove="tag">${url}</div>
<p th:if="${exception}">
<div th:utext="'Exception: ' + ${exception.message}" th:remove="tag">${exception.message}</div>
</p>
<div th:if="${exception != null}" th:utext="'Exception: ' + ${exception.message}" th:remove="tag">
${exception.message}
</div>
<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>
</ul>
</div>

View File

@ -0,0 +1,105 @@
<!--
~ 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="post">
<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 th:each="author : ${authors}"
th:value="${author}"
th:utext="${author}">
</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 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="*{url}">
<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>
<p>
</p>
</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.url}, branchName=${filterForm.branch})}"
th:text=${pageNumber}
th:class="${pageNumber == filterForm.commitsPage.number} ? active"></a>
</div>
</div>
</html>

View File

@ -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>

View File

@ -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>

View File

@ -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">
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
<title>Индексировать новый репозиторий</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<div class="container" layout:fragment="content">
<form action="#" th:action="@{/newRepo}" th:object="${repoForm}" method="post">
<p style="color:red" th:text="${error}"></p>
<form action="#" th:action="${@route.INDEXING_NEW_REPOSITORY}" th:object="${repoForm}" method="post">
<button class="btn btn-outline-dark dropdown-toggle" type="button" data-toggle="collapse"
data-target="#collapseOne" aria-expanded="false" aria-controls="collapseExample"
th:if="${repoForm.repo != null}"
th:text="${repoForm.repo == null ? 'Репозиторий' : repoForm.repo}">
th:if="${repoForm.repo != '' && repoForm.repo != null && (error == '' || error == null)}"
th:text="${repoForm.repo == '' || repoForm.repo == null ? 'Репозиторий' : repoForm.repo}">
Button with data-target
</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">
<div class="card-body">
<div class="form-group">
@ -34,7 +35,8 @@
</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="form-group">
<label for="select-branch">Ветки:</label>
@ -44,7 +46,7 @@
data-width="90%">
<option th:each="branch : ${branches}"
th:value="${branch.name}"
th:utext="${branch.name}"/>
th:utext="${branch.name}">
</option>
</select>
</div>

View File

@ -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">
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
<title>Проиндексированные репозитории</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<div class="container" layout:fragment="content">
<table class="table table-striped">
<thead class="thead-dark">
@ -15,7 +16,8 @@
</thead>
<tbody>
<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>
</tr>
</tbody>

View File

@ -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">
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
<title>Проиндексированные репозитории</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<div class="container" layout:fragment="content">
<table class="table table-striped">
<thead class="thead-dark">
@ -15,7 +16,8 @@
</thead>
<tbody>
<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>
</tbody>
</table>

View File

@ -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>