Merge branch '16-indexing' into 'master'

Resolve "Индексировать репозиторий в БД"

Closes #16

See merge request romanov73/git-extractor!11
This commit is contained in:
Anton Romanov 2021-03-29 11:40:27 +00:00
commit c401ad3a20
25 changed files with 620 additions and 119 deletions

View File

@ -1,6 +1,6 @@
buildscript { buildscript {
ext { ext {
versionSpringBoot = '2.3.8.RELEASE' versionSpringBoot = '2.3.9.RELEASE'
} }
repositories { repositories {
@ -47,13 +47,13 @@ dependencies {
compile group: 'org.springframework.boot', name: 'spring-boot-starter-web' compile group: 'org.springframework.boot', name: 'spring-boot-starter-web'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-jetty' compile group: 'org.springframework.boot', name: 'spring-boot-starter-jetty'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf' compile group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa'
compile group: 'nz.net.ultraq.thymeleaf', name: 'thymeleaf-layout-dialect' compile group: 'nz.net.ultraq.thymeleaf', name: 'thymeleaf-layout-dialect'
compile group: 'org.springframework.data', name: 'spring-data-commons'
compile group: 'com.fasterxml.jackson.module', name: 'jackson-module-afterburner' compile group: 'com.fasterxml.jackson.module', name: 'jackson-module-afterburner'
compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-hibernate5' compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-hibernate5'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-jdbc'
compile group: 'org.postgresql', name: 'postgresql', version: '9.4.1212' compile group: 'org.postgresql', name: 'postgresql', version: '9.4.1212'
compile group: 'org.liquibase', name: 'liquibase-core', version: '4.3.1' compile group: 'org.liquibase', name: 'liquibase-core', version: '4.3.1'
implementation group: 'commons-io', name: 'commons-io', version: '2.6'
compile group: 'io.springfox', name: 'springfox-boot-starter', version: '3.0.0' compile group: 'io.springfox', name: 'springfox-boot-starter', version: '3.0.0'

View File

@ -1,22 +1,18 @@
package ru.ulstu.extractor.controller; package ru.ulstu.extractor.controller;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
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.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
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;
import ru.ulstu.extractor.model.Commit; import ru.ulstu.extractor.model.Commit;
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.CommitService;
import ru.ulstu.extractor.service.FilteringService; import ru.ulstu.extractor.service.FilteringService;
import ru.ulstu.extractor.service.GitRepositoryService; import ru.ulstu.extractor.service.IndexService;
import java.io.IOException;
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;
@ -25,27 +21,24 @@ import java.util.stream.IntStream;
@Controller @Controller
public class GitFilteringController { public class GitFilteringController {
private final FilteringService filteringService; private final FilteringService filteringService;
private final GitRepositoryService gitRepositoryService; private final IndexService indexService;
private final CommitService commitService;
public GitFilteringController(FilteringService filteringService, public GitFilteringController(FilteringService filteringService,
GitRepositoryService gitRepositoryService, IndexService indexService) {
CommitService commitService) {
this.filteringService = filteringService; this.filteringService = filteringService;
this.gitRepositoryService = gitRepositoryService; this.indexService = indexService;
this.commitService = commitService;
} }
@PostMapping("/sendFilter") /* @PostMapping("/sendFilter")
public String sendFilter(@ModelAttribute FilterForm filterForm, Model model) throws GitAPIException, IOException { public String sendFilter(@ModelAttribute FilterForm filterForm, Model model) throws GitAPIException, IOException {
List<Commit> list = gitRepositoryService.getCommits(filterForm.getUrl()); List<Commit> list = gitRepositoryService.getCommits(filterForm.getUrl(), filterForm.getBranch());
model.addAttribute("commits", list); model.addAttribute("commits", list);
if (filterForm.getFilter() == null || filterForm.getFilter().isEmpty()) { if (filterForm.getFilter() == null || filterForm.getFilter().isEmpty()) {
model.addAttribute("error", "'Строка' не должно быть пустым"); model.addAttribute("error", "'Строка' не должно быть пустым");
return "filtering"; return "filtering";
} }
return "resultRepo"; return "resultRepo";
} }*/
@RequestMapping(value = "/filtering", method = RequestMethod.GET) @RequestMapping(value = "/filtering", method = RequestMethod.GET)
public String listCommits( public String listCommits(
@ -53,19 +46,24 @@ public class GitFilteringController {
@ModelAttribute FilterForm filterForm, @ModelAttribute FilterForm filterForm,
@RequestParam("page") Optional<Integer> page, @RequestParam("page") Optional<Integer> page,
@RequestParam("size") Optional<Integer> size, @RequestParam("size") Optional<Integer> size,
@RequestParam String url, @RequestParam String repositoryUrl,
@RequestParam String branch) throws GitAPIException, IOException { @RequestParam String branchName) {
int currentPage = page.orElse(1); int currentPage = page.orElse(1);
int pageSize = size.orElse(5); int pageSize = size.orElse(5);
Page<Commit> commitPage = commitService.findPaginated(PageRequest.of(currentPage - 1, pageSize), url);
model.addAttribute("commitPage", commitPage); Page<Commit> commitsPage = indexService.getCommits(repositoryUrl, branchName, new OffsetablePageRequest(currentPage, pageSize));
int totalPages = commitPage.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)
.boxed() .boxed()
.collect(Collectors.toList()); .collect(Collectors.toList());
model.addAttribute("pageNumbers", pageNumbers); model.addAttribute("pageNumbers", pageNumbers);
} }
filterForm = new FilterForm();
filterForm.setCommitsPage(commitsPage);
filterForm.setBranch(branchName);
filterForm.setUrl(repositoryUrl);
model.addAttribute("filterForm", filterForm);
return "filtering"; return "filtering";
} }
} }

View File

@ -11,15 +11,19 @@ import ru.ulstu.extractor.model.Branch;
import ru.ulstu.extractor.model.mvc.FilterForm; import ru.ulstu.extractor.model.mvc.FilterForm;
import ru.ulstu.extractor.model.mvc.RepoForm; 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 java.util.List; import java.util.List;
@Controller @Controller
public class GitIndexingController { public class GitIndexingController {
private final GitRepositoryService gitRepositoryService; private final GitRepositoryService gitRepositoryService;
private final IndexService indexService;
public GitIndexingController(GitRepositoryService gitRepositoryService) { public GitIndexingController(GitRepositoryService gitRepositoryService,
IndexService indexService) {
this.gitRepositoryService = gitRepositoryService; this.gitRepositoryService = gitRepositoryService;
this.indexService = indexService;
} }
@GetMapping("/newRepo") @GetMapping("/newRepo")
@ -47,8 +51,14 @@ public class GitIndexingController {
if (repoForm.getBranch() == null) { if (repoForm.getBranch() == null) {
return "newRepo"; return "newRepo";
} else { } else {
redirectAttributes.addAttribute("url", repoForm.getRepo()); try {
redirectAttributes.addAttribute("branch", repoForm.getBranch()); indexService.index(repoForm.getRepo(), repoForm.getBranch());
} catch (Exception ex) {
model.addAttribute("error", ex.getMessage());
return "newRepo";
}
redirectAttributes.addAttribute("repositoryUrl", repoForm.getRepo());
redirectAttributes.addAttribute("branchName", repoForm.getBranch());
return "redirect:/filtering"; return "redirect:/filtering";
} }
} }

View File

@ -29,8 +29,9 @@ public class RepoController {
} }
@GetMapping("commits") @GetMapping("commits")
public List<Commit> getCommits(@RequestParam("url") String url) throws GitAPIException, IOException { public List<Commit> getCommits(@RequestParam("repositoryUrl") String repositoryUrl,
return gitRepositoryService.getCommits(url); @RequestParam("branchName") String branchName) throws GitAPIException, IOException {
return gitRepositoryService.getCommits(repositoryUrl, branchName);
} }
} }

View File

@ -0,0 +1,23 @@
package ru.ulstu.extractor.model;
import javax.persistence.Entity;
@Entity
public class Author extends BaseEntity {
private String name;
public Author() {
}
public Author(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,86 @@
package ru.ulstu.extractor.model;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Version;
import java.io.Serializable;
@MappedSuperclass
public abstract class BaseEntity implements Serializable, Comparable {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private Integer id;
@Version
private Integer version;
public BaseEntity() {
}
public BaseEntity(Integer id, Integer version) {
this.id = id;
this.version = version;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getVersion() {
return version;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!getClass().isAssignableFrom(obj.getClass())) {
return false;
}
BaseEntity other = (BaseEntity) obj;
if (id == null) {
if (other.id != null) {
return false;
}
} else if (!id.equals(other.id)) {
return false;
}
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (id == null ? 0 : id.hashCode());
return result;
}
@Override
public String toString() {
return getClass().getSimpleName() + "{" +
"id=" + id +
", version=" + version +
'}';
}
@Override
public int compareTo(Object o) {
return id != null ? id.compareTo(((BaseEntity) o).getId()) : -1;
}
public void reset() {
this.id = null;
this.version = null;
}
}

View File

@ -1,14 +1,61 @@
package ru.ulstu.extractor.model; package ru.ulstu.extractor.model;
public class Branch { import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import java.util.List;
@Entity
public class Branch extends BaseEntity {
private String name; private String name;
@ManyToOne
private Repository repository;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "branch_id", unique = true)
@Fetch(FetchMode.SUBSELECT)
private List<Commit> commits;
public Branch() {
}
public Branch(String name) { public Branch(String name) {
this.name = name; this.name = name;
} }
public Branch(Repository repository, String branchName) {
this.repository = repository;
this.name = branchName;
}
public String getName() { public String getName() {
return name; return name;
} }
public void setName(String name) {
this.name = name;
}
public Repository getRepository() {
return repository;
}
public void setRepository(Repository repository) {
this.repository = repository;
}
public List<Commit> getCommits() {
return commits;
}
public void setCommits(List<Commit> commits) {
this.commits = commits;
}
} }

View File

@ -1,18 +1,40 @@
package ru.ulstu.extractor.model; package ru.ulstu.extractor.model;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List;
public class Commit { @Entity
private String message; public class Commit extends BaseEntity {
private String hash;
private Date date; private Date date;
private String author; private String message;
private Changes changes; @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Author author;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "commit_id", unique = true)
@Fetch(FetchMode.SUBSELECT)
private List<FileChange> fileChanges = new ArrayList<>();
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Branch branch;
public Commit(String message, String author, Date date) { public Commit() {
}
public Commit(String message, Author author, Date date, String hash) {
this.message = message; this.message = message;
this.author = author; this.author = author;
this.date = date; this.date = date;
this.hash = hash;
} }
public String getMessage() { public String getMessage() {
@ -23,15 +45,43 @@ public class Commit {
return date; return date;
} }
public String getAuthor() { public String getHash() {
return hash;
}
public void setHash(String hash) {
this.hash = hash;
}
public void setDate(Date date) {
this.date = date;
}
public void setMessage(String message) {
this.message = message;
}
public void setAuthor(Author author) {
this.author = author;
}
public List<FileChange> getFileChanges() {
return fileChanges;
}
public void setFileChanges(List<FileChange> fileChanges) {
this.fileChanges = fileChanges;
}
public Author getAuthor() {
return author; return author;
} }
public Changes getChanges() { public Branch getBranch() {
return changes; return branch;
} }
public void setChanges(Changes changes) { public void setBranch(Branch branch) {
this.changes = changes; this.branch = branch;
} }
} }

View File

@ -1,12 +1,28 @@
package ru.ulstu.extractor.model; package ru.ulstu.extractor.model;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Transient;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class FileChange { @Entity
public class FileChange extends BaseEntity {
private String file; private String file;
@Transient
private boolean removed; private boolean removed;
@Transient
private boolean added; private boolean added;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "file_change_id", unique = true)
@Fetch(FetchMode.SUBSELECT)
private List<LineChange> lineChanges = new ArrayList<>(); private List<LineChange> lineChanges = new ArrayList<>();
public FileChange() { public FileChange() {
@ -47,4 +63,12 @@ public class FileChange {
public void setLineChanges(List<LineChange> lineChanges) { public void setLineChanges(List<LineChange> lineChanges) {
this.lineChanges = lineChanges; this.lineChanges = lineChanges;
} }
public boolean isRemoved() {
return removed;
}
public boolean isAdded() {
return added;
}
} }

View File

@ -1,7 +1,13 @@
package ru.ulstu.extractor.model; package ru.ulstu.extractor.model;
public class LineChange { import javax.persistence.Entity;
import javax.persistence.Transient;
@Entity
public class LineChange extends BaseEntity {
@Transient
private boolean added; private boolean added;
@Transient
private boolean removed; private boolean removed;
private String lineFrom; private String lineFrom;
private String lineTo; private String lineTo;
@ -42,4 +48,19 @@ public class LineChange {
return lineTo; return lineTo;
} }
public boolean isAdded() {
return added;
}
public void setAdded(boolean added) {
this.added = added;
}
public boolean isRemoved() {
return removed;
}
public void setRemoved(boolean removed) {
this.removed = removed;
}
} }

View File

@ -0,0 +1,93 @@
package ru.ulstu.extractor.model;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import java.io.Serializable;
public class OffsetablePageRequest implements Pageable, Serializable {
private final int offset;
private final int count;
private final Sort sort;
public OffsetablePageRequest(int page, long pageSize) {
this(pageSize * page, pageSize, Sort.by("id"));
}
public OffsetablePageRequest(long offset, long count, Sort sort) {
if (offset < 0) {
throw new IllegalArgumentException("Offset value must not be less than zero!");
}
if (count < 1) {
throw new IllegalArgumentException("Count value must not be less than one!");
}
this.offset = (int) offset;
this.count = (int) count;
this.sort = sort;
}
@Override
public Sort getSort() {
return sort;
}
@Override
public int getPageSize() {
return count;
}
@Override
public int getPageNumber() {
return offset / count;
}
@Override
public long getOffset() {
return offset;
}
@Override
public boolean hasPrevious() {
return offset > 0;
}
@Override
public Pageable next() {
return new OffsetablePageRequest(getOffset() + getPageSize(), getPageSize(), getSort());
}
@Override
public Pageable previousOrFirst() {
return hasPrevious() ? previous() : first();
}
public Pageable previous() {
return getOffset() == 0 ? this : new OffsetablePageRequest(getOffset() - getPageSize(), getPageSize(), getSort());
}
@Override
public Pageable first() {
return new OffsetablePageRequest(0, getPageSize(), getSort());
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final OffsetablePageRequest other = (OffsetablePageRequest) obj;
return this.offset == other.offset && this.count == other.count;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + offset;
result = prime * result + count;
return result;
}
}

View File

@ -0,0 +1,23 @@
package ru.ulstu.extractor.model;
import javax.persistence.Entity;
@Entity
public class Repository extends BaseEntity {
private String url;
public Repository() {
}
public Repository(String repositoryUrl) {
url = repositoryUrl;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}

View File

@ -1,8 +1,13 @@
package ru.ulstu.extractor.model.mvc; package ru.ulstu.extractor.model.mvc;
import org.springframework.data.domain.Page;
import ru.ulstu.extractor.model.Commit;
public class FilterForm { public class FilterForm {
private String filter; private String filter;
private String url; private String url;
private String branch;
private Page<Commit> commitsPage;
public FilterForm() { public FilterForm() {
} }
@ -27,6 +32,22 @@ public class FilterForm {
this.url = url; this.url = url;
} }
public String getBranch() {
return branch;
}
public void setBranch(String branch) {
this.branch = branch;
}
public Page<Commit> getCommitsPage() {
return commitsPage;
}
public void setCommitsPage(Page<Commit> commitsPage) {
this.commitsPage = commitsPage;
}
@Override @Override
public String toString() { public String toString() {
return "FilterForm{" + return "FilterForm{" +

View File

@ -0,0 +1,14 @@
package ru.ulstu.extractor.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import ru.ulstu.extractor.model.Author;
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);
}

View File

@ -0,0 +1,9 @@
package ru.ulstu.extractor.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import ru.ulstu.extractor.model.Branch;
import ru.ulstu.extractor.model.Repository;
public interface BranchRepository extends JpaRepository<Branch, Integer> {
Branch findByRepositoryAndName(Repository repository, String name);
}

View File

@ -1,42 +1,14 @@
package ru.ulstu.extractor.repository; package ru.ulstu.extractor.repository;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.data.domain.Page;
import org.springframework.jdbc.core.RowMapper; import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import ru.ulstu.extractor.model.Commit; import ru.ulstu.extractor.model.Commit;
import ru.ulstu.extractor.model.Repository;
import java.sql.ResultSet; public interface CommitRepository extends JpaRepository<Commit, Integer> {
import java.sql.SQLException; @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")
import java.util.List; Page<Commit> findByRepositoryAndBranch(Pageable pageable, @Param("repository") Repository repository, @Param("branchName") String branchName);
@Repository
public class CommitRepository {
private final static String SQL_SELECT_COMMITS = "SELECT * FROM commit";
private final static String SQL_INSERT_COMMITS = "INSERT INTO commit (hash, date, author, message) " +
"VALUES (?, ?, ?, ?)";
private final JdbcTemplate jdbcTemplate;
public CommitRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
private static class CommitRowMapper implements RowMapper<Commit> {
@Override
public Commit mapRow(ResultSet rs, int rowNum) throws SQLException {
return new Commit(rs.getString("message"),
rs.getString("author"),
rs.getDate("date"));
}
}
public List<Commit> getCommits() {
return jdbcTemplate.query(SQL_SELECT_COMMITS, new CommitRowMapper());
}
public void saveCommit(Commit commit) {
jdbcTemplate.update(SQL_INSERT_COMMITS, "", commit.getDate(),
commit.getAuthor(),
commit.getMessage());
}
} }

View File

@ -0,0 +1,8 @@
package ru.ulstu.extractor.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import ru.ulstu.extractor.model.Repository;
public interface RepositoryRepository extends JpaRepository<Repository, Integer> {
Repository findByUrl(String url);
}

View File

@ -20,11 +20,11 @@ public class CommitService {
this.gitRepositoryService = gitRepositoryService; this.gitRepositoryService = gitRepositoryService;
} }
public Page<Commit> findPaginated(Pageable pageable, String url) throws GitAPIException, IOException { public Page<Commit> findPaginated(Pageable pageable, String repositoryUrl, String branchName) throws GitAPIException, IOException {
int pageSize = pageable.getPageSize(); int pageSize = pageable.getPageSize();
int currentPage = pageable.getPageNumber(); int currentPage = pageable.getPageNumber();
int startItem = currentPage * pageSize; int startItem = currentPage * pageSize;
List<Commit> commits = gitRepositoryService.getCommits(url); List<Commit> commits = gitRepositoryService.getCommits(repositoryUrl, branchName);
if (commits.size() < startItem) { if (commits.size() < startItem) {
commits = Collections.emptyList(); commits = Collections.emptyList();

View File

@ -1,32 +1,13 @@
package ru.ulstu.extractor.service; package ru.ulstu.extractor.service;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.ulstu.extractor.model.Commit;
import java.util.List;
import java.util.stream.Collectors;
@Service @Service
public class FilteringService { public class FilteringService {
private final GitRepositoryService gitRepositoryService; private final IndexService indexService;
public FilteringService(GitRepositoryService gitRepositoryService) { public FilteringService(IndexService indexService) {
this.gitRepositoryService = gitRepositoryService; this.indexService = indexService;
}
public List<Commit> getCommits(String urlRepo) {
return getCommits(urlRepo, null);
}
public List<Commit> getCommits(String urlRepo, String filterCommitMessage) {
if (filterCommitMessage != null) {
return getCommits(urlRepo)
.stream()
.filter(commit -> commit.getMessage().contains(filterCommitMessage))
.collect(Collectors.toList());
} else {
return getCommits(urlRepo);
}
} }
} }

View File

@ -1,16 +1,18 @@
package ru.ulstu.extractor.service; package ru.ulstu.extractor.service;
import org.eclipse.jgit.api.CreateBranchCommand;
import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.ListBranchCommand; 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;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.ulstu.extractor.model.Author;
import ru.ulstu.extractor.model.Branch; import ru.ulstu.extractor.model.Branch;
import ru.ulstu.extractor.model.Changes;
import ru.ulstu.extractor.model.Commit; import ru.ulstu.extractor.model.Commit;
import ru.ulstu.extractor.model.FileChange; import ru.ulstu.extractor.model.FileChange;
import ru.ulstu.extractor.model.LineChange; import ru.ulstu.extractor.model.LineChange;
@ -30,6 +32,7 @@ import static org.apache.logging.log4j.util.Strings.isBlank;
@Service @Service
public class GitRepositoryService { public class GitRepositoryService {
private static final String BRANCH_PREFIX = "refs/remotes/origin/";
@Value("${extractor.custom-projects-dir}") @Value("${extractor.custom-projects-dir}")
private String customProjectsDir; private String customProjectsDir;
@ -68,13 +71,20 @@ public class GitRepositoryService {
return file.exists(); return file.exists();
} }
public List<Commit> getCommits(String url) throws GitAPIException, IOException { public List<Commit> getCommits(String repositoryUrl, String branchName) throws GitAPIException, IOException {
cloneOrUpdateRepo(url); cloneOrUpdateRepo(repositoryUrl);
Repository localRepo = new FileRepository(getProjectGitDirectory(url)); Repository localRepo = new FileRepository(getProjectGitDirectory(repositoryUrl));
Git git = new Git(localRepo); Git git = new Git(localRepo);
git.pull().call(); 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<>(); List<RevCommit> commits = new ArrayList<>();
//TODO: сделать преобразование в коллекцию "наших объектов"
git.log().call().forEach(commits::add); git.log().call().forEach(commits::add);
List<Commit> list = new ArrayList<>(); List<Commit> list = new ArrayList<>();
@ -82,10 +92,11 @@ public class GitRepositoryService {
for (RevCommit revCommit : commits) { for (RevCommit revCommit : commits) {
Commit commit = new Commit( Commit commit = new Commit(
revCommit.getFullMessage(), revCommit.getFullMessage(),
revCommit.getAuthorIdent().getName(), new Author(revCommit.getAuthorIdent().getName()),
Date.from(Instant.ofEpochSecond(revCommit.getCommitTime()))); Date.from(Instant.ofEpochSecond(revCommit.getCommitTime())),
revCommit.getName());
if (prevCommit != null) { if (prevCommit != null) {
commit.setChanges(findDiffBetweenTwoRevisions(revCommit, prevCommit, localRepo)); commit.setFileChanges(findDiffBetweenTwoRevisions(revCommit, prevCommit, localRepo));
} }
list.add(commit); list.add(commit);
prevCommit = revCommit; prevCommit = revCommit;
@ -93,7 +104,7 @@ public class GitRepositoryService {
return list; return list;
} }
public Changes findDiffBetweenTwoRevisions(RevCommit laterCommit, RevCommit earlierCommit, Repository localRepo) { public List<FileChange> findDiffBetweenTwoRevisions(RevCommit laterCommit, RevCommit earlierCommit, Repository localRepo) {
if (laterCommit == null || earlierCommit == null) { if (laterCommit == null || earlierCommit == null) {
return null; return null;
} }
@ -109,8 +120,8 @@ public class GitRepositoryService {
return parseOutputDiff(output); return parseOutputDiff(output);
} }
private Changes parseOutputDiff(String output) { private List<FileChange> parseOutputDiff(String output) {
Changes changes = new Changes(); List<FileChange> changes = new ArrayList<>();
String[] strings = output.split("\n"); String[] strings = output.split("\n");
FileChange fileChange = new FileChange(); FileChange fileChange = new FileChange();
int stringsLength = strings.length - 1; int stringsLength = strings.length - 1;
@ -121,7 +132,7 @@ public class GitRepositoryService {
fileChange = new FileChange(); fileChange = new FileChange();
fileChange.setFile(maybeFileName.get()); fileChange.setFile(maybeFileName.get());
/// вытащить другие изменения из коммита /// вытащить другие изменения из коммита
changes.getFileChanges().add(fileChange); changes.add(fileChange);
} }
LineChange lineChange = new LineChange(); LineChange lineChange = new LineChange();
if (strings[i].startsWith("-")) { if (strings[i].startsWith("-")) {
@ -199,7 +210,11 @@ public class GitRepositoryService {
return git.branchList().setListMode(ListBranchCommand.ListMode.REMOTE) return git.branchList().setListMode(ListBranchCommand.ListMode.REMOTE)
.call() .call()
.stream() .stream()
.map(r -> new Branch(r.getName())) .map(r -> new Branch(r.getName().replace(BRANCH_PREFIX, "")))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
public void remove(String repositoryUrl) throws IOException {
//FileUtils.deleteDirectory(getProjectDirectoryFile(repositoryUrl));
}
} }

View File

@ -0,0 +1,63 @@
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 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;
import java.io.IOException;
import java.util.List;
@Service
public class IndexService {
private final GitRepositoryService gitRepositoryService;
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) {
this.gitRepositoryService = gitRepositoryService;
this.repositoryRepository = repositoryRepository;
this.branchRepository = branchRepository;
this.commitRepository = commitRepository;
this.authorRepository = authorRepository;
}
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));
}
Branch branch = branchRepository.findByRepositoryAndName(repository, branchName);
if (branch == null) {
branchRepository.save(new Branch(repository, branchName));
}
List<Commit> commits = gitRepositoryService.getCommits(repositoryUrl, branchName);
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

@ -11,6 +11,9 @@ spring.datasource.url=jdbc:postgresql://localhost:5432/repo
spring.datasource.username=postgres spring.datasource.username=postgres
spring.datasource.password=postgres spring.datasource.password=postgres
spring.datasource.driverclassName=org.postgresql.Driver spring.datasource.driverclassName=org.postgresql.Driver
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false
# Liquibase Settings # Liquibase Settings
spring.liquibase.drop-first=false spring.liquibase.drop-first=false
spring.liquibase.enabled=true spring.liquibase.enabled=true

View File

@ -0,0 +1,38 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<changeSet author="orion" id="20210329-120000-1">
<addColumn tableName="repository">
<column name="version" type="integer"/>
</addColumn>
<addColumn tableName="branch">
<column name="version" type="integer"/>
</addColumn>
<addColumn tableName="commit">
<column name="version" type="integer"/>
</addColumn>
<addColumn tableName="author">
<column name="version" type="integer"/>
</addColumn>
</changeSet>
<changeSet author="orion" id="20210329-120000-2">
<addColumn tableName="file_change">
<column name="version" type="integer"/>
</addColumn>
<addColumn tableName="line_change">
<column name="version" type="integer"/>
</addColumn>
</changeSet>
<changeSet author="orion" id="20210329-120000-3" objectQuotingStrategy="QUOTE_ALL_OBJECTS">
<createTable tableName="hibernate_sequences">
<column name="sequence_name" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="sequence_next_hi_value" type="BIGINT"/>
<column name="next_val" type="bigint"/>
</createTable>
<addPrimaryKey columnNames="sequence_name" constraintName="hibernate_sequences_pkey"
tableName="hibernate_sequences"/>
</changeSet>
</databaseChangeLog>

View File

@ -5,4 +5,5 @@
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<include file="db/changelog-20210317_140000-schema.xml"/> <include file="db/changelog-20210317_140000-schema.xml"/>
<include file="db/changelog-20210326_170000-schema.xml"/> <include file="db/changelog-20210326_170000-schema.xml"/>
<include file="db/changelog-20210329_120000-schema.xml"/>
</databaseChangeLog> </databaseChangeLog>

View File

@ -38,8 +38,8 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr th:each="commit: ${commits}"> <tr th:each="commit: ${filterForm.commitsPage.content}">
<td th:text="${commit.author}"></td> <td th:text="${commit.author.name}"></td>
<td th:text="${commit.date}"></td> <td th:text="${commit.date}"></td>
<td th:text="${commit.message}"></td> <td th:text="${commit.message}"></td>
</tr> </tr>
@ -50,7 +50,7 @@
</p> </p>
</form> </form>
</div> </div>
<div th:if="${commitPage.totalPages > 0}" class="pagination" <div th:if="${filterForm.commitPage.totalPages > 0}" class="pagination"
th:each="pageNumber : ${pageNumbers}"> th:each="pageNumber : ${pageNumbers}">
<a th:href="@{/filtering.html(size=${commitPage.size}, page=${pageNumber})}" <a th:href="@{/filtering.html(size=${commitPage.size}, page=${pageNumber})}"
th:class="${pageNumber==commitPage.number + 1} ? active"></a> th:class="${pageNumber==commitPage.number + 1} ? active"></a>