diff --git a/build.gradle b/build.gradle index 93eb471..bd1edfe 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ buildscript { ext { - versionSpringBoot = '2.3.8.RELEASE' + versionSpringBoot = '2.3.9.RELEASE' } repositories { @@ -47,12 +47,13 @@ dependencies { 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-thymeleaf' + compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa' compile group: 'nz.net.ultraq.thymeleaf', name: 'thymeleaf-layout-dialect' compile group: 'com.fasterxml.jackson.module', name: 'jackson-module-afterburner' 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.liquibase', name: 'liquibase-core', version: '4.3.1' + implementation group: 'commons-io', name: 'commons-io', version: '2.6' compile group: 'net.sourceforge.htmlunit', name: 'htmlunit', version: '2.35.0' compile group: 'io.springfox', name: 'springfox-boot-starter', version: '3.0.0' diff --git a/src/main/java/ru/ulstu/extractor/mvc/GlobalDefaultExceptionHandler.java b/src/main/java/ru/ulstu/extractor/config/GlobalDefaultExceptionHandler.java similarity index 96% rename from src/main/java/ru/ulstu/extractor/mvc/GlobalDefaultExceptionHandler.java rename to src/main/java/ru/ulstu/extractor/config/GlobalDefaultExceptionHandler.java index 7a1ea5b..49f1501 100644 --- a/src/main/java/ru/ulstu/extractor/mvc/GlobalDefaultExceptionHandler.java +++ b/src/main/java/ru/ulstu/extractor/config/GlobalDefaultExceptionHandler.java @@ -1,4 +1,4 @@ -package ru.ulstu.extractor.mvc; +package ru.ulstu.extractor.config; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ControllerAdvice; diff --git a/src/main/java/ru/ulstu/extractor/mvc/MvcConfiguration.java b/src/main/java/ru/ulstu/extractor/config/MvcConfiguration.java similarity index 96% rename from src/main/java/ru/ulstu/extractor/mvc/MvcConfiguration.java rename to src/main/java/ru/ulstu/extractor/config/MvcConfiguration.java index c25a506..2355ca1 100644 --- a/src/main/java/ru/ulstu/extractor/mvc/MvcConfiguration.java +++ b/src/main/java/ru/ulstu/extractor/config/MvcConfiguration.java @@ -1,4 +1,4 @@ -package ru.ulstu.extractor.mvc; +package ru.ulstu.extractor.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; diff --git a/src/main/java/ru/ulstu/extractor/mvc/TemplateConfiguration.java b/src/main/java/ru/ulstu/extractor/config/TemplateConfiguration.java similarity index 97% rename from src/main/java/ru/ulstu/extractor/mvc/TemplateConfiguration.java rename to src/main/java/ru/ulstu/extractor/config/TemplateConfiguration.java index 7798224..1a638d2 100644 --- a/src/main/java/ru/ulstu/extractor/mvc/TemplateConfiguration.java +++ b/src/main/java/ru/ulstu/extractor/config/TemplateConfiguration.java @@ -1,4 +1,4 @@ -package ru.ulstu.extractor.mvc; +package ru.ulstu.extractor.config; import nz.net.ultraq.thymeleaf.LayoutDialect; import org.springframework.beans.factory.annotation.Value; diff --git a/src/main/java/ru/ulstu/extractor/controller/GitFilteringController.java b/src/main/java/ru/ulstu/extractor/controller/GitFilteringController.java new file mode 100644 index 0000000..85ef6aa --- /dev/null +++ b/src/main/java/ru/ulstu/extractor/controller/GitFilteringController.java @@ -0,0 +1,69 @@ +package ru.ulstu.extractor.controller; + +import org.springframework.data.domain.Page; +import org.springframework.stereotype.Controller; +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.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +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; + +@Controller +public class GitFilteringController { + private final FilteringService filteringService; + private final IndexService indexService; + + public GitFilteringController(FilteringService filteringService, + IndexService indexService) { + this.filteringService = filteringService; + this.indexService = indexService; + } + + /* @PostMapping("/sendFilter") + public String sendFilter(@ModelAttribute FilterForm filterForm, Model model) throws GitAPIException, IOException { + List 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( + Model model, + @ModelAttribute FilterForm filterForm, + @RequestParam("page") Optional page, + @RequestParam("size") Optional size, + @RequestParam String repositoryUrl, + @RequestParam String branchName) { + int currentPage = page.orElse(1); + int pageSize = size.orElse(5); + + Page commitsPage = indexService.getCommits(repositoryUrl, branchName, new OffsetablePageRequest(currentPage, pageSize)); + int totalPages = commitsPage.getTotalPages(); + if (totalPages > 0) { + List pageNumbers = IntStream.rangeClosed(1, totalPages) + .boxed() + .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"; + } +} diff --git a/src/main/java/ru/ulstu/extractor/mvc/GitExtractorController.java b/src/main/java/ru/ulstu/extractor/controller/GitIndexingController.java similarity index 52% rename from src/main/java/ru/ulstu/extractor/mvc/GitExtractorController.java rename to src/main/java/ru/ulstu/extractor/controller/GitIndexingController.java index 676e7f2..18ddb48 100644 --- a/src/main/java/ru/ulstu/extractor/mvc/GitExtractorController.java +++ b/src/main/java/ru/ulstu/extractor/controller/GitIndexingController.java @@ -1,58 +1,43 @@ -package ru.ulstu.extractor.mvc; +package ru.ulstu.extractor.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; 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.RequestMethod; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; import ru.ulstu.extractor.model.Branch; -import ru.ulstu.extractor.mvc.model.FilterForm; -import ru.ulstu.extractor.mvc.model.RepoForm; -import ru.ulstu.extractor.service.FilteringService; +import ru.ulstu.extractor.model.mvc.FilterForm; +import ru.ulstu.extractor.model.mvc.RepoForm; import ru.ulstu.extractor.service.GitRepositoryService; +import ru.ulstu.extractor.service.IndexService; import java.util.List; @Controller -public class GitExtractorController { - private final FilteringService filteringService; +public class GitIndexingController { private final GitRepositoryService gitRepositoryService; + private final IndexService indexService; - public GitExtractorController(FilteringService filteringService, - GitRepositoryService gitRepositoryService) { - this.filteringService = filteringService; + public GitIndexingController(GitRepositoryService gitRepositoryService, + IndexService indexService) { this.gitRepositoryService = gitRepositoryService; + this.indexService = indexService; } @GetMapping("/newRepo") public String indexNewRepo(Model model) { - model.addAttribute("repoForm", new RepoForm()); + model.addAttribute(new RepoForm()); return "newRepo"; } - @GetMapping("/filtering") - public String filter(Model model) { - model.addAttribute("filterForm", new FilterForm()); - return "filtering"; - } - - @PostMapping("/sendFilter") - public String sendFilter(@ModelAttribute FilterForm filterForm, Model model) { - if (filterForm.getFilter() == null || filterForm.getFilter().isEmpty()) { - model.addAttribute("error", "'Строка' не должно быть пустым"); - return "filtering"; - } - return "resultRepo"; - } - @RequestMapping(value = "/newRepo", method = RequestMethod.POST, params = "send") public String getBranch(@ModelAttribute RepoForm repoForm, Model model) { try { gitRepositoryService.cloneOrUpdateRepo(repoForm.getRepo()); - List list = gitRepositoryService.getBranches(repoForm.getRepo()); - model.addAttribute("branches", list); + List branches = gitRepositoryService.getBranches(repoForm.getRepo()); + model.addAttribute("branches", branches); return "newRepo"; } catch (Exception ex) { model.addAttribute("error", ex.getMessage()); @@ -61,12 +46,20 @@ public class GitExtractorController { } @RequestMapping(value = "/newRepo", method = RequestMethod.POST, params = "next") - public String setBranch(@ModelAttribute RepoForm repoForm, Model model) { + public String setBranch(@ModelAttribute RepoForm repoForm, Model model, RedirectAttributes redirectAttributes) { model.addAttribute("filterForm", new FilterForm(repoForm.getRepo())); if (repoForm.getBranch() == null) { return "newRepo"; } else { - return "filtering"; + try { + 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"; } } } diff --git a/src/main/java/ru/ulstu/extractor/controller/RepoController.java b/src/main/java/ru/ulstu/extractor/controller/RepoController.java index 2d30d9a..09ea5d5 100644 --- a/src/main/java/ru/ulstu/extractor/controller/RepoController.java +++ b/src/main/java/ru/ulstu/extractor/controller/RepoController.java @@ -29,8 +29,9 @@ public class RepoController { } @GetMapping("commits") - public List getCommits(@RequestParam("url") String url) throws GitAPIException, IOException { - return gitRepositoryService.getCommits(url); + public List getCommits(@RequestParam("repositoryUrl") String repositoryUrl, + @RequestParam("branchName") String branchName) throws GitAPIException, IOException { + return gitRepositoryService.getCommits(repositoryUrl, branchName); } } diff --git a/src/main/java/ru/ulstu/extractor/db/CommitRepository.java b/src/main/java/ru/ulstu/extractor/db/CommitRepository.java deleted file mode 100644 index 86a924e..0000000 --- a/src/main/java/ru/ulstu/extractor/db/CommitRepository.java +++ /dev/null @@ -1,42 +0,0 @@ -package ru.ulstu.extractor.db; - -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.stereotype.Repository; -import ru.ulstu.extractor.model.Commit; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.List; - -@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 { - - @Override - public Commit mapRow(ResultSet rs, int rowNum) throws SQLException { - return new Commit(rs.getString("message"), - rs.getString("author"), - rs.getDate("date")); - } - } - - public List 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()); - } -} diff --git a/src/main/java/ru/ulstu/extractor/model/Author.java b/src/main/java/ru/ulstu/extractor/model/Author.java new file mode 100644 index 0000000..2462d5b --- /dev/null +++ b/src/main/java/ru/ulstu/extractor/model/Author.java @@ -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; + } +} diff --git a/src/main/java/ru/ulstu/extractor/model/BaseEntity.java b/src/main/java/ru/ulstu/extractor/model/BaseEntity.java new file mode 100644 index 0000000..0859807 --- /dev/null +++ b/src/main/java/ru/ulstu/extractor/model/BaseEntity.java @@ -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; + } +} diff --git a/src/main/java/ru/ulstu/extractor/model/Branch.java b/src/main/java/ru/ulstu/extractor/model/Branch.java index 4f751d2..5c39ce9 100644 --- a/src/main/java/ru/ulstu/extractor/model/Branch.java +++ b/src/main/java/ru/ulstu/extractor/model/Branch.java @@ -1,14 +1,62 @@ 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.ArrayList; +import java.util.List; + +@Entity +public class Branch extends BaseEntity { 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 commits = new ArrayList<>(); + + public Branch() { + } + public Branch(String name) { this.name = name; } + public Branch(Repository repository, String branchName) { + this.repository = repository; + this.name = branchName; + } + public String getName() { 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 getCommits() { + return commits; + } + + public void setCommits(List commits) { + this.commits = commits; + } } diff --git a/src/main/java/ru/ulstu/extractor/model/Commit.java b/src/main/java/ru/ulstu/extractor/model/Commit.java index 9e8e6f4..1bbe22f 100644 --- a/src/main/java/ru/ulstu/extractor/model/Commit.java +++ b/src/main/java/ru/ulstu/extractor/model/Commit.java @@ -1,18 +1,40 @@ 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.List; -public class Commit { - private String message; +@Entity +public class Commit extends BaseEntity { + private String hash; private Date date; - private String author; - private Changes changes; + private String message; + @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 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.author = author; this.date = date; - + this.hash = hash; } public String getMessage() { @@ -23,15 +45,43 @@ public class Commit { 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 getFileChanges() { + return fileChanges; + } + + public void setFileChanges(List fileChanges) { + this.fileChanges = fileChanges; + } + + public Author getAuthor() { return author; } - public Changes getChanges() { - return changes; + public Branch getBranch() { + return branch; } - public void setChanges(Changes changes) { - this.changes = changes; + public void setBranch(Branch branch) { + this.branch = branch; } } diff --git a/src/main/java/ru/ulstu/extractor/model/FileChange.java b/src/main/java/ru/ulstu/extractor/model/FileChange.java index fb0ec6b..2493da6 100644 --- a/src/main/java/ru/ulstu/extractor/model/FileChange.java +++ b/src/main/java/ru/ulstu/extractor/model/FileChange.java @@ -1,12 +1,28 @@ 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.List; -public class FileChange { +@Entity +public class FileChange extends BaseEntity { private String file; + @Transient private boolean removed; + @Transient private boolean added; + + @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @JoinColumn(name = "file_change_id", unique = true) + @Fetch(FetchMode.SUBSELECT) private List lineChanges = new ArrayList<>(); public FileChange() { @@ -47,4 +63,12 @@ public class FileChange { public void setLineChanges(List lineChanges) { this.lineChanges = lineChanges; } + + public boolean isRemoved() { + return removed; + } + + public boolean isAdded() { + return added; + } } diff --git a/src/main/java/ru/ulstu/extractor/model/LineChange.java b/src/main/java/ru/ulstu/extractor/model/LineChange.java index 7f1bab3..7901322 100644 --- a/src/main/java/ru/ulstu/extractor/model/LineChange.java +++ b/src/main/java/ru/ulstu/extractor/model/LineChange.java @@ -1,7 +1,13 @@ 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; + @Transient private boolean removed; private String lineFrom; private String lineTo; @@ -42,4 +48,19 @@ public class LineChange { 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; + } } diff --git a/src/main/java/ru/ulstu/extractor/model/OffsetablePageRequest.java b/src/main/java/ru/ulstu/extractor/model/OffsetablePageRequest.java new file mode 100644 index 0000000..e96673b --- /dev/null +++ b/src/main/java/ru/ulstu/extractor/model/OffsetablePageRequest.java @@ -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; + } +} diff --git a/src/main/java/ru/ulstu/extractor/model/Repository.java b/src/main/java/ru/ulstu/extractor/model/Repository.java new file mode 100644 index 0000000..651bfca --- /dev/null +++ b/src/main/java/ru/ulstu/extractor/model/Repository.java @@ -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; + } +} diff --git a/src/main/java/ru/ulstu/extractor/mvc/model/FilterForm.java b/src/main/java/ru/ulstu/extractor/model/mvc/FilterForm.java similarity index 53% rename from src/main/java/ru/ulstu/extractor/mvc/model/FilterForm.java rename to src/main/java/ru/ulstu/extractor/model/mvc/FilterForm.java index 16e52b8..6180b13 100644 --- a/src/main/java/ru/ulstu/extractor/mvc/model/FilterForm.java +++ b/src/main/java/ru/ulstu/extractor/model/mvc/FilterForm.java @@ -1,8 +1,13 @@ -package ru.ulstu.extractor.mvc.model; +package ru.ulstu.extractor.model.mvc; + +import org.springframework.data.domain.Page; +import ru.ulstu.extractor.model.Commit; public class FilterForm { private String filter; private String url; + private String branch; + private Page commitsPage; public FilterForm() { } @@ -27,6 +32,22 @@ public class FilterForm { this.url = url; } + public String getBranch() { + return branch; + } + + public void setBranch(String branch) { + this.branch = branch; + } + + public Page getCommitsPage() { + return commitsPage; + } + + public void setCommitsPage(Page commitsPage) { + this.commitsPage = commitsPage; + } + @Override public String toString() { return "FilterForm{" + diff --git a/src/main/java/ru/ulstu/extractor/mvc/model/RepoForm.java b/src/main/java/ru/ulstu/extractor/model/mvc/RepoForm.java similarity index 78% rename from src/main/java/ru/ulstu/extractor/mvc/model/RepoForm.java rename to src/main/java/ru/ulstu/extractor/model/mvc/RepoForm.java index 72b2b11..e0ca0aa 100644 --- a/src/main/java/ru/ulstu/extractor/mvc/model/RepoForm.java +++ b/src/main/java/ru/ulstu/extractor/model/mvc/RepoForm.java @@ -1,8 +1,7 @@ -package ru.ulstu.extractor.mvc.model; +package ru.ulstu.extractor.model.mvc; public class RepoForm { private String repo; - private String branch; public String getRepo() { @@ -24,7 +23,8 @@ public class RepoForm { @Override public String toString() { return "RepoForm{" + - "subject='" + repo + + "repo='" + repo + '\'' + + ", branch='" + branch + '\'' + '}'; } } diff --git a/src/main/java/ru/ulstu/extractor/repository/AuthorRepository.java b/src/main/java/ru/ulstu/extractor/repository/AuthorRepository.java new file mode 100644 index 0000000..504aaf2 --- /dev/null +++ b/src/main/java/ru/ulstu/extractor/repository/AuthorRepository.java @@ -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 { + @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 findByRepositoryAndBranch(@Param("repository") Repository repository, @Param("branchName") String branchName); +} diff --git a/src/main/java/ru/ulstu/extractor/repository/BranchRepository.java b/src/main/java/ru/ulstu/extractor/repository/BranchRepository.java new file mode 100644 index 0000000..f893bb6 --- /dev/null +++ b/src/main/java/ru/ulstu/extractor/repository/BranchRepository.java @@ -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 findByRepositoryAndName(Repository repository, String name); +} diff --git a/src/main/java/ru/ulstu/extractor/repository/CommitRepository.java b/src/main/java/ru/ulstu/extractor/repository/CommitRepository.java new file mode 100644 index 0000000..3c32439 --- /dev/null +++ b/src/main/java/ru/ulstu/extractor/repository/CommitRepository.java @@ -0,0 +1,14 @@ +package ru.ulstu.extractor.repository; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +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.Repository; + +public interface CommitRepository extends JpaRepository { + @Query("SELECT c FROM Commit c, Repository r, Branch b WHERE c.branch = b AND r = b.repository AND r = :repository AND b.name = :branchName") + Page findByRepositoryAndBranch(Pageable pageable, @Param("repository") Repository repository, @Param("branchName") String branchName); +} diff --git a/src/main/java/ru/ulstu/extractor/repository/RepositoryRepository.java b/src/main/java/ru/ulstu/extractor/repository/RepositoryRepository.java new file mode 100644 index 0000000..21263f4 --- /dev/null +++ b/src/main/java/ru/ulstu/extractor/repository/RepositoryRepository.java @@ -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 findByUrl(String url); +} diff --git a/src/main/java/ru/ulstu/extractor/service/CommitService.java b/src/main/java/ru/ulstu/extractor/service/CommitService.java new file mode 100644 index 0000000..62073d6 --- /dev/null +++ b/src/main/java/ru/ulstu/extractor/service/CommitService.java @@ -0,0 +1,39 @@ +package ru.ulstu.extractor.service; + +import org.eclipse.jgit.api.errors.GitAPIException; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import ru.ulstu.extractor.model.Commit; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +@Service +public class CommitService { + private final GitRepositoryService gitRepositoryService; + + public CommitService(GitRepositoryService gitRepositoryService) { + this.gitRepositoryService = gitRepositoryService; + } + + public Page findPaginated(Pageable pageable, String repositoryUrl, String branchName) throws GitAPIException, IOException { + int pageSize = pageable.getPageSize(); + int currentPage = pageable.getPageNumber(); + int startItem = currentPage * pageSize; + List commits = gitRepositoryService.getCommits(repositoryUrl, branchName); + + if (commits.size() < startItem) { + commits = Collections.emptyList(); + } else { + int toIndex = Math.min(startItem + pageSize, commits.size()); + commits = commits.subList(startItem, toIndex); + } + return new PageImpl<>(commits, PageRequest.of(currentPage, pageSize), commits.size()); + } +} + + diff --git a/src/main/java/ru/ulstu/extractor/service/FilteringService.java b/src/main/java/ru/ulstu/extractor/service/FilteringService.java index 254437d..b6b7cf7 100644 --- a/src/main/java/ru/ulstu/extractor/service/FilteringService.java +++ b/src/main/java/ru/ulstu/extractor/service/FilteringService.java @@ -1,32 +1,13 @@ package ru.ulstu.extractor.service; import org.springframework.stereotype.Service; -import ru.ulstu.extractor.model.Commit; - -import java.util.List; -import java.util.stream.Collectors; @Service public class FilteringService { - private final GitRepositoryService gitRepositoryService; + private final IndexService indexService; - public FilteringService(GitRepositoryService gitRepositoryService) { - this.gitRepositoryService = gitRepositoryService; - } - - public List getCommits(String urlRepo) { - return getCommits(urlRepo, null); - } - - public List 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); - } + public FilteringService(IndexService indexService) { + this.indexService = indexService; } } diff --git a/src/main/java/ru/ulstu/extractor/service/GitRepositoryService.java b/src/main/java/ru/ulstu/extractor/service/GitRepositoryService.java index 1d20e44..558b179 100644 --- a/src/main/java/ru/ulstu/extractor/service/GitRepositoryService.java +++ b/src/main/java/ru/ulstu/extractor/service/GitRepositoryService.java @@ -1,16 +1,19 @@ package ru.ulstu.extractor.service; +import org.apache.commons.io.FileUtils; +import org.eclipse.jgit.api.CreateBranchCommand; import org.eclipse.jgit.api.Git; 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; import org.springframework.stereotype.Service; +import ru.ulstu.extractor.model.Author; import ru.ulstu.extractor.model.Branch; -import ru.ulstu.extractor.model.Changes; import ru.ulstu.extractor.model.Commit; import ru.ulstu.extractor.model.FileChange; import ru.ulstu.extractor.model.LineChange; @@ -30,6 +33,7 @@ import static org.apache.logging.log4j.util.Strings.isBlank; @Service public class GitRepositoryService { + private static final String BRANCH_PREFIX = "refs/remotes/origin/"; @Value("${extractor.custom-projects-dir}") private String customProjectsDir; @@ -39,14 +43,14 @@ public class GitRepositoryService { 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(); } - Iterable commits = git.log().call(); - //commits.forEach(c -> System.out.println(c.getFullMessage())); + git.close(); } private String getProjectDirectory(String url) { @@ -68,13 +72,20 @@ public class GitRepositoryService { return file.exists(); } - public List getCommits(String url) throws GitAPIException, IOException { - cloneOrUpdateRepo(url); - Repository localRepo = new FileRepository(getProjectGitDirectory(url)); + public List 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 commits = new ArrayList<>(); - //TODO: сделать преобразование в коллекцию "наших объектов" git.log().call().forEach(commits::add); List list = new ArrayList<>(); @@ -82,18 +93,21 @@ public class GitRepositoryService { for (RevCommit revCommit : commits) { Commit commit = new Commit( revCommit.getFullMessage(), - revCommit.getAuthorIdent().getName(), - Date.from(Instant.ofEpochSecond(revCommit.getCommitTime()))); + new Author(revCommit.getAuthorIdent().getName()), + Date.from(Instant.ofEpochSecond(revCommit.getCommitTime())), + revCommit.getName()); if (prevCommit != null) { - commit.setChanges(findDiffBetweenTwoRevisions(revCommit, prevCommit, localRepo)); + commit.setFileChanges(findDiffBetweenTwoRevisions(revCommit, prevCommit, localRepo)); } list.add(commit); prevCommit = revCommit; } + git.close(); + localRepo.close(); return list; } - public Changes findDiffBetweenTwoRevisions(RevCommit laterCommit, RevCommit earlierCommit, Repository localRepo) { + public List findDiffBetweenTwoRevisions(RevCommit laterCommit, RevCommit earlierCommit, Repository localRepo) { if (laterCommit == null || earlierCommit == null) { return null; } @@ -109,8 +123,8 @@ public class GitRepositoryService { return parseOutputDiff(output); } - private Changes parseOutputDiff(String output) { - Changes changes = new Changes(); + private List parseOutputDiff(String output) { + List changes = new ArrayList<>(); String[] strings = output.split("\n"); FileChange fileChange = new FileChange(); int stringsLength = strings.length - 1; @@ -121,7 +135,7 @@ public class GitRepositoryService { fileChange = new FileChange(); fileChange.setFile(maybeFileName.get()); /// вытащить другие изменения из коммита - changes.getFileChanges().add(fileChange); + changes.add(fileChange); } LineChange lineChange = new LineChange(); if (strings[i].startsWith("-")) { @@ -196,10 +210,17 @@ public class GitRepositoryService { cloneOrUpdateRepo(url); Repository localRepo = new FileRepository(getProjectGitDirectory(url)); Git git = new Git(localRepo); - return git.branchList().setListMode(ListBranchCommand.ListMode.REMOTE) + List branches = git.branchList().setListMode(ListBranchCommand.ListMode.REMOTE) .call() .stream() - .map(r -> new Branch(r.getName())) + .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)); } } diff --git a/src/main/java/ru/ulstu/extractor/service/IndexService.java b/src/main/java/ru/ulstu/extractor/service/IndexService.java new file mode 100644 index 0000000..332a3e1 --- /dev/null +++ b/src/main/java/ru/ulstu/extractor/service/IndexService.java @@ -0,0 +1,65 @@ +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 commits = gitRepositoryService.getCommits(repositoryUrl, branchName); + commitRepository.deleteAll(branch.getCommits()); + branch.getCommits().clear(); + branch.setCommits(commits); + branchRepository.save(branch); + gitRepositoryService.remove(repositoryUrl); + } + + public List getRepositoryAuthors(@NotNull String repositoryUrl, @NotNull String branchName) { + return authorRepository.findByRepositoryAndBranch(repositoryRepository.findByUrl(repositoryUrl), branchName); + } + + public Page getCommits(@NotNull String repositoryUrl, @NotNull String branchName, Pageable pageable) { + return commitRepository.findByRepositoryAndBranch(pageable, repositoryRepository.findByUrl(repositoryUrl), branchName); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index f061be5..938472e 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -11,6 +11,9 @@ spring.datasource.url=jdbc:postgresql://localhost:5432/repo spring.datasource.username=postgres spring.datasource.password=postgres 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 spring.liquibase.drop-first=false spring.liquibase.enabled=true diff --git a/src/main/resources/db/changelog-20210326_170000-schema.xml b/src/main/resources/db/changelog-20210326_170000-schema.xml new file mode 100644 index 0000000..08700ab --- /dev/null +++ b/src/main/resources/db/changelog-20210326_170000-schema.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/db/changelog-20210329_120000-schema.xml b/src/main/resources/db/changelog-20210329_120000-schema.xml new file mode 100644 index 0000000..78b1cc4 --- /dev/null +++ b/src/main/resources/db/changelog-20210329_120000-schema.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/db/changelog-master.xml b/src/main/resources/db/changelog-master.xml index b135ee0..0ddc390 100644 --- a/src/main/resources/db/changelog-master.xml +++ b/src/main/resources/db/changelog-master.xml @@ -4,4 +4,6 @@ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> + + diff --git a/src/main/resources/templates/default.html b/src/main/resources/templates/default.html index c6c1237..8497859 100644 --- a/src/main/resources/templates/default.html +++ b/src/main/resources/templates/default.html @@ -19,14 +19,10 @@ aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> -