Работа уведомление о новых ПР

This commit is contained in:
upagge 2020-09-06 13:28:17 +03:00
parent 3a90e04363
commit 2f1e929422
No known key found for this signature in database
GPG Key ID: 15CD012E46F6BA34
44 changed files with 994 additions and 1045 deletions

View File

@ -45,7 +45,7 @@ public class Comment {
@Column(name = "message") @Column(name = "message")
private String message; private String message;
@Column(name = "createDate") @Column(name = "create_date")
private LocalDateTime createDate; private LocalDateTime createDate;
/** /**

View File

@ -6,8 +6,6 @@ import lombok.Setter;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.Table; import javax.persistence.Table;
@ -27,14 +25,7 @@ public class Person {
* Логин * Логин
*/ */
@Id @Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
@EqualsAndHashCode.Include @EqualsAndHashCode.Include
private Long id;
/**
* Логин
*/
@Column(name = "login") @Column(name = "login")
private String login; private String login;

View File

@ -44,7 +44,7 @@ public class PullRequest {
/** /**
* Идентификатор на стороне битбакета * Идентификатор на стороне битбакета
*/ */
@Column(name = "bitbucket_pr_id") @Column(name = "bitbucket_id")
private Long bitbucketId; private Long bitbucketId;
/** /**
@ -65,12 +65,6 @@ public class PullRequest {
@Column(name = "repository_slug") @Column(name = "repository_slug")
private String repositorySlug; private String repositorySlug;
/**
* Версия объекта для блокировок
*/
@Column(name = "version")
private Integer version;
/** /**
* Описание пулреквеста * Описание пулреквеста
*/ */
@ -133,4 +127,9 @@ public class PullRequest {
@JoinColumn(name = "pull_request_id") @JoinColumn(name = "pull_request_id")
private List<Reviewer> reviewers; private List<Reviewer> reviewers;
public void setReviewers(List<Reviewer> reviewers) {
reviewers.forEach(reviewer -> reviewer.setPullRequest(this));
this.reviewers = reviewers;
}
} }

View File

@ -9,9 +9,11 @@ import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.EnumType; import javax.persistence.EnumType;
import javax.persistence.Enumerated; import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType; import javax.persistence.GenerationType;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table; import javax.persistence.Table;
/** /**
@ -48,4 +50,7 @@ public class Reviewer {
@Column(name = "status") @Column(name = "status")
private ReviewerStatus status; private ReviewerStatus status;
@ManyToOne(fetch = FetchType.LAZY)
private PullRequest pullRequest;
} }

View File

@ -12,8 +12,6 @@ import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType; import javax.persistence.GenerationType;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table; import javax.persistence.Table;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@ -46,7 +44,6 @@ public class Task {
@Column(name = "create_date") @Column(name = "create_date")
private LocalDateTime createDate; private LocalDateTime createDate;
@OneToMany
@Column(name = "pull_request_id") @Column(name = "pull_request_id")
private Long pullRequestId; private Long pullRequestId;
@ -62,8 +59,7 @@ public class Task {
@Column(name = "bitbucket_version") @Column(name = "bitbucket_version")
private Integer bitbucketVersion; private Integer bitbucketVersion;
@OneToMany @Column(name = "author_login")
@JoinColumn(name = "author_login") private String author;
private Person author;
} }

View File

@ -7,7 +7,7 @@ import java.util.List;
public interface ChangeRepository { public interface ChangeRepository {
void add(@NonNull Change change); <T extends Change> T add(@NonNull T change);
List<Change> getAll(); List<Change> getAll();

View File

@ -0,0 +1,31 @@
package org.sadtech.bot.bitbucketbot.repository;
import lombok.NonNull;
import org.sadtech.bot.bitbucketbot.domain.entity.Person;
import java.util.List;
import java.util.Optional;
import java.util.Set;
/**
* // TODO: 06.09.2020 Добавить описание.
*
* @author upagge 06.09.2020
*/
public interface PersonRepository {
Person save(@NonNull Person person);
boolean existsByTelegramId(Long chatId);
boolean existsByLogin(String login);
List<Person> findAllByTelegramIdNotNullAndTokenNotNull();
Long findTelegramIdByLogin(String login);
Set<Long> findAllTelegramIdByLogin(Set<String> logins);
Optional<Person> findByLogin(@NonNull String login);
}

View File

@ -1,6 +1,7 @@
package org.sadtech.bot.bitbucketbot.repository; package org.sadtech.bot.bitbucketbot.repository;
import org.sadtech.basic.context.repository.BusinessLogicRepository; import org.sadtech.basic.context.repository.SimpleManagerRepository;
import org.sadtech.basic.context.repository.simple.FilterOperation;
import org.sadtech.bot.bitbucketbot.domain.IdAndStatusPr; import org.sadtech.bot.bitbucketbot.domain.IdAndStatusPr;
import org.sadtech.bot.bitbucketbot.domain.PullRequestStatus; import org.sadtech.bot.bitbucketbot.domain.PullRequestStatus;
import org.sadtech.bot.bitbucketbot.domain.ReviewerStatus; import org.sadtech.bot.bitbucketbot.domain.ReviewerStatus;
@ -9,7 +10,7 @@ import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
public interface PullRequestsRepository extends BusinessLogicRepository<PullRequest, Long> { public interface PullRequestsRepository extends SimpleManagerRepository<PullRequest, Long>, FilterOperation<PullRequest> {
List<PullRequest> findAllByReviewerAndStatuses(String login, ReviewerStatus reviewerStatus, Set<PullRequestStatus> statuses); List<PullRequest> findAllByReviewerAndStatuses(String login, ReviewerStatus reviewerStatus, Set<PullRequestStatus> statuses);

View File

@ -15,9 +15,10 @@ public class ChangeRepositoryImpl implements ChangeRepository {
private long count = 0; private long count = 0;
@Override @Override
public void add(@NonNull Change change) { public <T extends Change> T add(@NonNull T change) {
change.setId(count++); change.setId(count++);
list.add(change); list.add(change);
return change;
} }
@Override @Override

View File

@ -0,0 +1,74 @@
package org.sadtech.bot.bitbucketbot.repository.impl;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.sadtech.bot.bitbucketbot.domain.entity.Person;
import org.sadtech.bot.bitbucketbot.repository.PersonRepository;
import org.sadtech.bot.bitbucketbot.repository.jpa.PersonJpaRepository;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.stereotype.Repository;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
/**
* // TODO: 06.09.2020 Добавить описание.
*
* @author upagge 06.09.2020
*/
@Slf4j
@Repository
@RequiredArgsConstructor
public class PersonRepositoryImpl implements PersonRepository {
private final PersonJpaRepository jpaRepository;
@Override
public Person save(@NonNull Person person) {
return jpaRepository.save(person);
}
@Override
public boolean existsByTelegramId(Long chatId) {
return jpaRepository.existsByTelegramId(chatId);
}
@Override
public boolean existsByLogin(String login) {
try {
return jpaRepository.existsByLogin(login);
} catch (InvalidDataAccessResourceUsageException e) {
log.error(e.getMessage());
}
return false;
}
@Override
public List<Person> findAllByTelegramIdNotNullAndTokenNotNull() {
try {
return jpaRepository.findAllByTelegramIdNotNullAndTokenNotNull();
} catch (InvalidDataAccessResourceUsageException e) {
log.error(e.getMessage());
}
return Collections.emptyList();
}
@Override
public Long findTelegramIdByLogin(String login) {
return jpaRepository.findTelegramIdByLogin(login);
}
@Override
public Set<Long> findAllTelegramIdByLogin(Set<String> logins) {
return jpaRepository.findAllTelegramIdByLogin(logins);
}
@Override
public Optional<Person> findByLogin(@NonNull String login) {
return jpaRepository.findById(login);
}
}

View File

@ -1,6 +1,6 @@
package org.sadtech.bot.bitbucketbot.repository.impl; package org.sadtech.bot.bitbucketbot.repository.impl;
import org.sadtech.basic.database.repository.AbstractBusinessLogicJpaRepository; import org.sadtech.basic.database.repository.manager.FilterManagerRepository;
import org.sadtech.bot.bitbucketbot.domain.IdAndStatusPr; import org.sadtech.bot.bitbucketbot.domain.IdAndStatusPr;
import org.sadtech.bot.bitbucketbot.domain.PullRequestStatus; import org.sadtech.bot.bitbucketbot.domain.PullRequestStatus;
import org.sadtech.bot.bitbucketbot.domain.ReviewerStatus; import org.sadtech.bot.bitbucketbot.domain.ReviewerStatus;
@ -13,28 +13,28 @@ import java.util.List;
import java.util.Set; import java.util.Set;
@Repository @Repository
public class PullRequestsRepositoryImpl extends AbstractBusinessLogicJpaRepository<PullRequest, Long> implements PullRequestsRepository { public class PullRequestsRepositoryImpl extends FilterManagerRepository<PullRequest, Long> implements PullRequestsRepository {
private final PullRequestsRepositoryJpa pullRequestsRepositoryJpa; private final PullRequestsRepositoryJpa repositoryJpa;
protected PullRequestsRepositoryImpl(PullRequestsRepositoryJpa pullRequestsRepositoryJpa) { public PullRequestsRepositoryImpl(PullRequestsRepositoryJpa jpaRepository) {
super(pullRequestsRepositoryJpa); super(jpaRepository);
this.pullRequestsRepositoryJpa = pullRequestsRepositoryJpa; repositoryJpa = jpaRepository;
} }
@Override @Override
public List<PullRequest> findAllByReviewerAndStatuses(String login, ReviewerStatus reviewerStatus, Set<PullRequestStatus> statuses) { public List<PullRequest> findAllByReviewerAndStatuses(String login, ReviewerStatus reviewerStatus, Set<PullRequestStatus> statuses) {
return pullRequestsRepositoryJpa.findAllByReviewerAndStatuses(login, reviewerStatus, statuses); return repositoryJpa.findAllByReviewerAndStatuses(login, reviewerStatus, statuses);
} }
@Override @Override
public List<PullRequest> findAllByAuthorAndReviewerStatus(String login, ReviewerStatus status) { public List<PullRequest> findAllByAuthorAndReviewerStatus(String login, ReviewerStatus status) {
return pullRequestsRepositoryJpa.findAllByAuthorAndReviewerStatus(login, status); return repositoryJpa.findAllByAuthorAndReviewerStatus(login, status);
} }
@Override @Override
public Set<IdAndStatusPr> findAllIdByStatusIn(Set<PullRequestStatus> statuses) { public Set<IdAndStatusPr> findAllIdByStatusIn(Set<PullRequestStatus> statuses) {
return pullRequestsRepositoryJpa.findAllIdByStatusIn(statuses); return repositoryJpa.findAllIdByStatusIn(statuses);
} }
} }

View File

@ -30,4 +30,9 @@ public class TaskRepositoryImpl implements TaskRepository {
return taskRepositoryJpa.findById(id); return taskRepositoryJpa.findById(id);
} }
@Override
public Optional<Task> findFirstByOrderByIdDesc() {
return Optional.empty();
}
} }

View File

@ -11,6 +11,6 @@ public interface CommentRepository extends JpaRepository<Comment, Long> {
Optional<Comment> findFirstByOrderByIdDesc(); Optional<Comment> findFirstByOrderByIdDesc();
List<Comment> findByDateBetween(LocalDateTime dateFrom, LocalDateTime dateTo); List<Comment> findByCreateDateBetween(LocalDateTime dateFrom, LocalDateTime dateTo);
} }

View File

@ -6,7 +6,6 @@ import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.Set; import java.util.Set;
/** /**
@ -15,7 +14,7 @@ import java.util.Set;
* @author upagge [30.01.2020] * @author upagge [30.01.2020]
*/ */
@Repository @Repository
public interface PersonRepository extends JpaRepository<Person, String> { public interface PersonJpaRepository extends JpaRepository<Person, String> {
boolean existsByTelegramId(Long chatId); boolean existsByTelegramId(Long chatId);
@ -29,8 +28,4 @@ public interface PersonRepository extends JpaRepository<Person, String> {
@Query("SELECT u.telegramId FROM Person u WHERE u.login IN :logins AND u.telegramId IS NOT NULL") @Query("SELECT u.telegramId FROM Person u WHERE u.login IN :logins AND u.telegramId IS NOT NULL")
Set<Long> findAllTelegramIdByLogin(Set<String> logins); Set<Long> findAllTelegramIdByLogin(Set<String> logins);
Optional<Person> findByLogin(String login);
Person getByLogin(String login);
} }

View File

@ -8,7 +8,6 @@ import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.support.JpaRepositoryImplementation; import org.springframework.data.jpa.repository.support.JpaRepositoryImplementation;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
import java.time.LocalDateTime;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -28,10 +27,10 @@ public interface PullRequestsRepositoryJpa extends JpaRepositoryImplementation<P
void deleteAllByIdIn(Collection<Long> id); void deleteAllByIdIn(Collection<Long> id);
@Query("SELECT p FROM PullRequest p LEFT JOIN p.reviewers r WHERE r.user=:reviewer AND r.status =:reviewerStatus AND p.status IN :pullRequestStatus") @Query("SELECT p FROM PullRequest p LEFT JOIN p.reviewers r WHERE r.userLogin=:reviewer AND r.status =:reviewerStatus AND p.status IN :pullRequestStatus")
List<PullRequest> findAllByReviewerAndStatuses(@Param("reviewer") String reviewer, @Param("reviewerStatus") ReviewerStatus reviewerStatus, @Param("pullRequestStatus") Set<PullRequestStatus> pullRequestStatus); List<PullRequest> findAllByReviewerAndStatuses(@Param("reviewer") String reviewer, @Param("reviewerStatus") ReviewerStatus reviewerStatus, @Param("pullRequestStatus") Set<PullRequestStatus> pullRequestStatus);
@Query("SELECT p FROM PullRequest p LEFT JOIN p.reviewers r WHERE p.author.login=:author AND r.status=:reviewerStatus") @Query("SELECT p FROM PullRequest p LEFT JOIN p.reviewers r WHERE p.authorLogin=:author AND r.status=:reviewerStatus")
List<PullRequest> findAllByAuthorAndReviewerStatus(@Param("author") String author, @Param("reviewerStatus") ReviewerStatus reviewerStatus); List<PullRequest> findAllByAuthorAndReviewerStatus(@Param("author") String author, @Param("reviewerStatus") ReviewerStatus reviewerStatus);
// @Query("SELECT new org.sadtech.bot.bitbucketbot.domain.IdAndStatusPr(p.id, p.status) FROM PullRequest p WHERE p.status IN :statuses") // @Query("SELECT new org.sadtech.bot.bitbucketbot.domain.IdAndStatusPr(p.id, p.status) FROM PullRequest p WHERE p.status IN :statuses")
@ -40,7 +39,7 @@ public interface PullRequestsRepositoryJpa extends JpaRepositoryImplementation<P
@Query("SELECT p.id from PullRequest p") @Query("SELECT p.id from PullRequest p")
Set<Long> findAllIds(); Set<Long> findAllIds();
@Query("SELECT p FROM PullRequest p WHERE p.author.login = :login AND p.createDate BETWEEN :dateFrom AND :dateTo") // @Query("SELECT p FROM PullRequest p WHERE p.authorLogin = :login AND p.createDate BETWEEN :dateFrom AND :dateTo")
List<PullRequest> findAllByAuthorAndDateBetween(@Param("login") String login, @Param("dateFrom") LocalDateTime dateFrom, @Param("dateTo") LocalDateTime dateTo); // List<PullRequest> findAllByAuthorAndDateBetween(@Param("login") String login, @Param("dateFrom") LocalDateTime dateFrom, @Param("dateTo") LocalDateTime dateTo);
} }

View File

@ -1,49 +1,9 @@
package org.sadtech.bot.bitbucketbot.scheduler; package org.sadtech.bot.bitbucketbot.scheduler;
import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.sadtech.bot.bitbucketbot.config.properties.BitbucketProperty;
import org.sadtech.bot.bitbucketbot.config.properties.CommentSchedulerProperty;
import org.sadtech.bot.bitbucketbot.domain.Answer;
import org.sadtech.bot.bitbucketbot.domain.Pagination;
import org.sadtech.bot.bitbucketbot.domain.TaskStatus;
import org.sadtech.bot.bitbucketbot.domain.change.ChangeType;
import org.sadtech.bot.bitbucketbot.domain.change.comment.AnswerCommentChange;
import org.sadtech.bot.bitbucketbot.domain.change.comment.CommentChange;
import org.sadtech.bot.bitbucketbot.domain.change.task.TaskChange;
import org.sadtech.bot.bitbucketbot.domain.entity.Comment;
import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest;
import org.sadtech.bot.bitbucketbot.domain.entity.Task;
import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentJson;
import org.sadtech.bot.bitbucketbot.dto.bitbucket.Severity;
import org.sadtech.bot.bitbucketbot.exception.NotFoundException;
import org.sadtech.bot.bitbucketbot.service.ChangeService;
import org.sadtech.bot.bitbucketbot.service.CommentService;
import org.sadtech.bot.bitbucketbot.service.PersonService;
import org.sadtech.bot.bitbucketbot.service.PullRequestsService;
import org.sadtech.bot.bitbucketbot.service.TaskService;
import org.sadtech.bot.bitbucketbot.service.Utils;
import org.sadtech.bot.bitbucketbot.service.executor.DataScan;
import org.sadtech.bot.bitbucketbot.service.executor.ResultScan;
import org.sadtech.bot.bitbucketbot.service.impl.ExecutorScanner;
import org.sadtech.bot.bitbucketbot.utils.Converter;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.domain.Page;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/** /**
* Шедулер отвечает за работу с комментариями. Поиск новых комментариев, проверка старых. Так как таски в * Шедулер отвечает за работу с комментариями. Поиск новых комментариев, проверка старых. Так как таски в
* битбакете реализуются через комментарии, то <b>этот шедулер так же работает с тасками</b>. * битбакете реализуются через комментарии, то <b>этот шедулер так же работает с тасками</b>.
@ -55,210 +15,210 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor @RequiredArgsConstructor
public class SchedulerComments { public class SchedulerComments {
private static final Pattern PATTERN = Pattern.compile("@[\\w]+"); // private static final Pattern PATTERN = Pattern.compile("@[\\w]+");
//
private final CommentService commentService; // private final CommentService commentService;
private final PullRequestsService pullRequestsService; // private final PullRequestsService pullRequestsService;
private final PersonService personService; // private final PersonService personService;
private final ChangeService changeService; // private final ChangeService changeService;
private final ExecutorScanner executorScanner; // private final ExecutorScanner executorScanner;
private final TaskService taskService; // private final TaskService taskService;
private final ConversionService conversionService; // private final ConversionService conversionService;
//
private final BitbucketProperty bitbucketProperty; // private final BitbucketProperty bitbucketProperty;
private final CommentSchedulerProperty commentSchedulerProperty; // private final CommentSchedulerProperty commentSchedulerProperty;
//
/** // /**
* Сканирует появление новых комментариев // * Сканирует появление новых комментариев
*/ // */
@Scheduled(cron = "0 */3 * * * *") // @Scheduled(cron = "0 */3 * * * *")
public void newComments() { // public void newComments() {
long commentId = commentService.getLastCommentId() + 1; // long commentId = commentService.getLastCommentId() + 1;
int count = 0; // int count = 0;
do { // do {
final List<DataScan> dataScans = generatingLinksToPossibleComments(commentId); // final List<DataScan> dataScans = generatingLinksToPossibleComments(commentId);
executorScanner.registration(dataScans); // executorScanner.registration(dataScans);
final List<ResultScan> resultScans = executorScanner.getResult(); // final List<ResultScan> resultScans = executorScanner.getResult();
if (!resultScans.isEmpty()) { // if (!resultScans.isEmpty()) {
final List<Comment> comments = getCommentsByResultScan(resultScans); // final List<Comment> comments = getCommentsByResultScan(resultScans);
final List<Comment> newComments = commentService.createAll(comments); // final List<Comment> newComments = commentService.createAll(comments);
checkNewTask(newComments); // checkNewTask(newComments);
notificationPersonal(newComments); // notificationPersonal(newComments);
count = 0; // count = 0;
} // }
} while (count++ < commentSchedulerProperty.getNoCommentCount()); // } while (count++ < commentSchedulerProperty.getNoCommentCount());
} // }
//
private List<Comment> getCommentsByResultScan(List<ResultScan> resultScans) { // private List<Comment> getCommentsByResultScan(List<ResultScan> resultScans) {
return resultScans.stream() // return resultScans.stream()
.map(result -> conversionService.convert(result, Comment.class)) // .map(result -> conversionService.convert(result, Comment.class))
.collect(Collectors.toList()); // .collect(Collectors.toList());
} // }
//
private List<DataScan> generatingLinksToPossibleComments(@NonNull Long commentId) { // private List<DataScan> generatingLinksToPossibleComments(@NonNull Long commentId) {
List<DataScan> commentUrls = new ArrayList<>(); // List<DataScan> commentUrls = new ArrayList<>();
for (int i = 0; i < 5; i++) { // for (int i = 0; i < 5; i++) {
int page = 0; // int page = 0;
Page<PullRequest> pullRequestPage = pullRequestsService.getAll( // Page<PullRequest> pullRequestPage = pullRequestsService.getAll(
Pagination.of(page, commentSchedulerProperty.getCommentCount()) // Pagination.of(page, commentSchedulerProperty.getCommentCount())
); // );
while (pullRequestPage.hasContent()) { // while (pullRequestPage.hasContent()) {
long finalCommentId = commentId; // long finalCommentId = commentId;
commentUrls.addAll(pullRequestPage.getContent().stream() // commentUrls.addAll(pullRequestPage.getContent().stream()
.map( // .map(
pullRequest -> new DataScan( // pullRequest -> new DataScan(
getCommentUrl(finalCommentId, pullRequest), // getCommentUrl(finalCommentId, pullRequest),
pullRequest.getId() // pullRequest.getId()
) // )
) // )
.collect(Collectors.toList())); // .collect(Collectors.toList()));
pullRequestPage = pullRequestsService.getAll( // pullRequestPage = pullRequestsService.getAll(
Pagination.of(++page, commentSchedulerProperty.getCommentCount()) // Pagination.of(++page, commentSchedulerProperty.getCommentCount())
); // );
} // }
commentId++; // commentId++;
} // }
return commentUrls; // return commentUrls;
} // }
//
//
private void checkNewTask(CommentJson commentJson, String urlPr, String authorLoginPr) { // private void checkNewTask(CommentJson commentJson, String urlPr, String authorLoginPr) {
if (Severity.BLOCKER.equals(commentJson.getSeverity())) { // if (Severity.BLOCKER.equals(commentJson.getSeverity())) {
final Task task = new Task(); // final Task task = new Task();
task.setStatus(Converter.taskStatus(commentJson.getState())); // task.setStatus(Converter.taskStatus(commentJson.getState()));
task.setComment(commentService.getProxyById(commentJson.getId()).orElseThrow(() -> new NotFoundException("Неожиданная ошибка"))); // task.setComment(commentService.getProxyById(commentJson.getId()).orElseThrow(() -> new NotFoundException("Неожиданная ошибка")));
//
taskService.create(task); // taskService.create(task);
//
if (TaskStatus.OPEN.equals(task.getStatus())) { // if (TaskStatus.OPEN.equals(task.getStatus())) {
changeService.add( // changeService.add(
TaskChange.builder() // TaskChange.builder()
.type(ChangeType.NEW_TASK) // .type(ChangeType.NEW_TASK)
.authorName(commentJson.getAuthor().getDisplayName()) // .authorName(commentJson.getAuthor().getDisplayName())
.messageTask(commentJson.getText()) // .messageTask(commentJson.getText())
.telegramIds(personService.getAllTelegramIdByLogin(Collections.singleton(authorLoginPr))) // .telegramIds(personService.getAllTelegramIdByLogin(Collections.singleton(authorLoginPr)))
.url(urlPr) // .url(urlPr)
.build() // .build()
); // );
} // }
} // }
} // }
//
//
/** // /**
* Проверяет состояние старых комментариев // * Проверяет состояние старых комментариев
*/ // */
@Scheduled(cron = "0 */1 * * * *") // @Scheduled(cron = "0 */1 * * * *")
public void oldComments() { // public void oldComments() {
@NonNull final List<Comment> comments = commentService.getAllBetweenDate( // @NonNull final List<Comment> comments = commentService.getAllBetweenDate(
LocalDateTime.now().minusDays(10), LocalDateTime.now() // LocalDateTime.now().minusDays(10), LocalDateTime.now()
); // );
for (Comment comment : comments) { // for (Comment comment : comments) {
final Optional<CommentJson> optCommentJson = Utils.urlToJson( // final Optional<CommentJson> optCommentJson = Utils.urlToJson(
comment.getUrl(), // comment.getUrl(),
bitbucketProperty.getToken(), // bitbucketProperty.getToken(),
CommentJson.class // CommentJson.class
); // );
if (optCommentJson.isPresent()) { // if (optCommentJson.isPresent()) {
final CommentJson commentJson = optCommentJson.get(); // final CommentJson commentJson = optCommentJson.get();
checkNewAnswers(comment, commentJson); // checkNewAnswers(comment, commentJson);
checkOldTask(comment, commentJson); // checkOldTask(comment, commentJson);
} // }
} // }
} // }
//
private void checkOldTask(Comment comment, CommentJson commentJson) { // private void checkOldTask(Comment comment, CommentJson commentJson) {
final Task task = comment.getTask(); // final Task task = comment.getTask();
if (task == null) { // if (task == null) {
checkNewTask(commentJson, comment.getPrUrl(), commentJson.getAuthor().getName()); // checkNewTask(commentJson, comment.getPrUrl(), commentJson.getAuthor().getName());
} else { // } else {
if (Severity.NORMAL.equals(commentJson.getSeverity())) { // if (Severity.NORMAL.equals(commentJson.getSeverity())) {
taskService.deleteById(comment.getId()); // taskService.deleteById(comment.getId());
//
changeService.add( // changeService.add(
TaskChange.builder() // TaskChange.builder()
.type(ChangeType.DELETED_TASK) // .type(ChangeType.DELETED_TASK)
.telegramIds(personService.getAllTelegramIdByLogin(Collections.singleton(commentJson.getAuthor().getName()))) // .telegramIds(personService.getAllTelegramIdByLogin(Collections.singleton(commentJson.getAuthor().getName())))
.authorName(commentJson.getAuthor().getDisplayName()) // .authorName(commentJson.getAuthor().getDisplayName())
.url(comment.getPrUrl()) // .url(comment.getPrUrl())
.messageTask(commentJson.getText()) // .messageTask(commentJson.getText())
.build() // .build()
); // );
} else { // } else {
final TaskStatus taskStatus = task.getStatus(); // final TaskStatus taskStatus = task.getStatus();
final TaskStatus newTaskStatus = Converter.taskStatus(commentJson.getState()); // final TaskStatus newTaskStatus = Converter.taskStatus(commentJson.getState());
task.setStatus(newTaskStatus); // task.setStatus(newTaskStatus);
taskService.update(task); // taskService.update(task);
if (!taskStatus.equals(newTaskStatus)) { // if (!taskStatus.equals(newTaskStatus)) {
changeService.add( // changeService.add(
TaskChange.builder() // TaskChange.builder()
.type(TaskStatus.RESOLVED.equals(newTaskStatus) ? ChangeType.RESOLVED_TASK : ChangeType.OPEN_TASK) // .type(TaskStatus.RESOLVED.equals(newTaskStatus) ? ChangeType.RESOLVED_TASK : ChangeType.OPEN_TASK)
.authorName(commentJson.getAuthor().getDisplayName()) // .authorName(commentJson.getAuthor().getDisplayName())
.url(comment.getPrUrl()) // .url(comment.getPrUrl())
.messageTask(commentJson.getText()) // .messageTask(commentJson.getText())
.telegramIds( // .telegramIds(
TaskStatus.RESOLVED.equals(newTaskStatus) // TaskStatus.RESOLVED.equals(newTaskStatus)
? personService.getAllTelegramIdByLogin(Collections.singleton(commentJson.getAuthor().getName())) // ? personService.getAllTelegramIdByLogin(Collections.singleton(commentJson.getAuthor().getName()))
: personService.getAllTelegramIdByLogin(Collections.singleton(commentJson.getAuthor().getName())) // : personService.getAllTelegramIdByLogin(Collections.singleton(commentJson.getAuthor().getName()))
) // )
.build() // .build()
); // );
} // }
} // }
} // }
} // }
//
private void checkNewAnswers(Comment comment, CommentJson commentJson) { // private void checkNewAnswers(Comment comment, CommentJson commentJson) {
final Set<Long> oldAnswerIds = comment.getAnswers(); // final Set<Long> oldAnswerIds = comment.getAnswers();
final List<CommentJson> newAnswers = commentJson.getComments().stream() // final List<CommentJson> newAnswers = commentJson.getComments().stream()
.filter(answerJson -> !oldAnswerIds.contains(answerJson.getId())) // .filter(answerJson -> !oldAnswerIds.contains(answerJson.getId()))
.collect(Collectors.toList()); // .collect(Collectors.toList());
if (!newAnswers.isEmpty()) { // if (!newAnswers.isEmpty()) {
changeService.add( // changeService.add(
AnswerCommentChange.builder() // AnswerCommentChange.builder()
.telegramIds( // .telegramIds(
personService.getTelegramIdByLogin(commentJson.getAuthor().getName()) // personService.getTelegramIdByLogin(commentJson.getAuthor().getName())
.map(Collections::singleton) // .map(Collections::singleton)
.orElse(Collections.emptySet()) // .orElse(Collections.emptySet())
) // )
.url(comment.getPrUrl()) // .url(comment.getPrUrl())
.youMessage(commentJson.getText()) // .youMessage(commentJson.getText())
.answers( // .answers(
newAnswers.stream() // newAnswers.stream()
.map(json -> Answer.of(json.getAuthor().getName(), json.getText())) // .map(json -> Answer.of(json.getAuthor().getName(), json.getText()))
.collect(Collectors.toList()) // .collect(Collectors.toList())
) // )
.build() // .build()
); // );
comment.getAnswers().addAll(newAnswers.stream().map(CommentJson::getId).collect(Collectors.toList())); // comment.getAnswers().addAll(newAnswers.stream().map(CommentJson::getId).collect(Collectors.toList()));
commentService.save(comment); // commentService.save(comment);
} // }
} // }
//
private String getCommentUrl(long commentId, PullRequest pullRequest) { // private String getCommentUrl(long commentId, PullRequest pullRequest) {
return bitbucketProperty.getUrlPullRequestComment() // return bitbucketProperty.getUrlPullRequestComment()
.replace("{projectKey}", pullRequest.getProjectKey()) // .replace("{projectKey}", pullRequest.getProjectKey())
.replace("{repositorySlug}", pullRequest.getRepositorySlug()) // .replace("{repositorySlug}", pullRequest.getRepositorySlug())
.replace("{pullRequestId}", pullRequest.getBitbucketId().toString()) // .replace("{pullRequestId}", pullRequest.getBitbucketId().toString())
.replace("{commentId}", String.valueOf(commentId)); // .replace("{commentId}", String.valueOf(commentId));
} // }
//
private void notificationPersonal(@NonNull Comment comment) { // private void notificationPersonal(@NonNull Comment comment) {
Matcher matcher = PATTERN.matcher(comment.getMessage()); // Matcher matcher = PATTERN.matcher(comment.getMessage());
Set<String> recipientsLogins = new HashSet<>(); // Set<String> recipientsLogins = new HashSet<>();
while (matcher.find()) { // while (matcher.find()) {
final String login = matcher.group(0).replace("@", ""); // final String login = matcher.group(0).replace("@", "");
recipientsLogins.add(login); // recipientsLogins.add(login);
} // }
final Set<Long> recipientsIds = personService.getAllTelegramIdByLogin(recipientsLogins); // final Set<Long> recipientsIds = personService.getAllTelegramIdByLogin(recipientsLogins);
changeService.add( // changeService.add(
CommentChange.builder() // CommentChange.builder()
.authorName(comment.getAuthor().getLogin()) // .authorName(comment.getAuthor().getLogin())
.url(comment.getPullRequest()) // .url(comment.getPullRequest())
.telegramIds(recipientsIds) // .telegramIds(recipientsIds)
.message(comment.getMessage()) // .message(comment.getMessage())
.build() // .build()
); // );
} // }
} }

View File

@ -9,25 +9,30 @@ import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest;
import org.sadtech.bot.bitbucketbot.service.MessageSendService; import org.sadtech.bot.bitbucketbot.service.MessageSendService;
import org.sadtech.bot.bitbucketbot.service.PersonService; import org.sadtech.bot.bitbucketbot.service.PersonService;
import org.sadtech.bot.bitbucketbot.service.PullRequestsService; import org.sadtech.bot.bitbucketbot.service.PullRequestsService;
import org.sadtech.bot.bitbucketbot.service.ReportService;
import org.sadtech.bot.bitbucketbot.utils.Message; import org.sadtech.bot.bitbucketbot.utils.Message;
import org.sadtech.bot.bitbucketbot.utils.Smile;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class SchedulerNotification { public class SchedulerNotification {
private static final Set<String> tksLoginNotify = new HashSet<>(Arrays.asList(
"mstruchkov", "drasskazov", "dganin", "emukhin", "ktorgaeva", "imescheryakov", "kkeglev"
));
private static final Set<PullRequestStatus> statuses = Collections.singleton(PullRequestStatus.OPEN); private static final Set<PullRequestStatus> statuses = Collections.singleton(PullRequestStatus.OPEN);
private final PersonService personService; private final PersonService personService;
private final PullRequestsService pullRequestsService; private final PullRequestsService pullRequestsService;
private final MessageSendService messageSendService; private final MessageSendService messageSendService;
private final ReportService reportService;
// Утреннее сообщение // Утреннее сообщение
@Scheduled(cron = "0 15 8 * * MON-FRI") @Scheduled(cron = "0 15 8 * * MON-FRI")
@ -49,6 +54,21 @@ public class SchedulerNotification {
} }
} }
@Scheduled(cron = "0 25 10 * * MON-FRI")
public void tks() {
List<Person> usersTks = personService.getAllRegister().stream()
.filter(user -> tksLoginNotify.contains(user.getLogin()))
.collect(Collectors.toList());
for (Person person : usersTks) {
messageSendService.add(
MessageSend.builder()
.telegramId(person.getTelegramId())
.message("☎️ Скоро созвон" + Smile.HR + "https://meet.google.com/czs-vigu-mte")
.build()
);
}
}
@Scheduled(cron = "0 0 18 * * FRI") @Scheduled(cron = "0 0 18 * * FRI")
public void goodWeekEnd() { public void goodWeekEnd() {
List<Person> allRegister = personService.getAllRegister(); List<Person> allRegister = personService.getAllRegister();
@ -59,7 +79,6 @@ public class SchedulerNotification {
.message(Message.goodWeekEnd()) .message(Message.goodWeekEnd())
.build() .build()
); );
reportService.generateReport(user.getLogin());
} }
} }

View File

@ -1,24 +1,22 @@
package org.sadtech.bot.bitbucketbot.scheduler.parser; package org.sadtech.bot.bitbucketbot.scheduler.parser;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.sadtech.bot.bitbucketbot.service.parser.CommentAndTaskParser;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Component @Component
@RequiredArgsConstructor @RequiredArgsConstructor
public class CommentAndTaskScheduler { public class CommentAndTaskScheduler {
private final CommentAndTaskParser commentAndTaskParser; // private final CommentAndTaskParser commentAndTaskParser;
//
@Scheduled(cron = "") // @Scheduled(cron = "")
public void scanNewCommentAndTask() { // public void scanNewCommentAndTask() {
commentAndTaskParser.scanNewCommentAndTask(); // commentAndTaskParser.scanNewCommentAndTask();
} // }
//
@Scheduled(cron = "") // @Scheduled(cron = "")
public void scanOldComment() { // public void scanOldComment() {
commentAndTaskParser.scanOldComment(); // commentAndTaskParser.scanOldComment();
} // }
} }

View File

@ -1,7 +1,7 @@
package org.sadtech.bot.bitbucketbot.scheduler.parser; package org.sadtech.bot.bitbucketbot.scheduler.parser;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.sadtech.bot.bitbucketbot.service.parser.PersonParser; import org.sadtech.bot.bitbucketbot.service.impl.parser.PersonBitbucketParser;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -9,12 +9,12 @@ import org.springframework.stereotype.Component;
@RequiredArgsConstructor @RequiredArgsConstructor
public class PersonScheduler { public class PersonScheduler {
private final PersonParser personParser; private final PersonBitbucketParser personParser;
@Scheduled(cron = "") // @Scheduled(cron = "0 0 0 */1 * *")
@Scheduled(cron = "0 */1 * * * *")
public void scanPersons() { public void scanPersons() {
personParser.scanNewPerson(); personParser.scanNewPerson();
} }
} }

View File

@ -6,6 +6,11 @@ import org.sadtech.bot.bitbucketbot.service.parser.PullRequestParser;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
/**
* Позволяет задать время парсинга для ПРов.
*
* @author upagge 06.09.2020
*/
@Slf4j @Slf4j
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@ -13,12 +18,12 @@ public class PullRequestParserScheduler {
private final PullRequestParser pullRequestParser; private final PullRequestParser pullRequestParser;
@Scheduled(cron = "") @Scheduled(cron = "0 */1 * * * *")
public void parsingOldPullRequest() { public void parsingOldPullRequest() {
pullRequestParser.parsingOldPullRequest(); pullRequestParser.parsingOldPullRequest();
} }
@Scheduled(cron = "") @Scheduled(cron = "0 */1 * * * *")
public void parsingNewPullRequest() { public void parsingNewPullRequest() {
pullRequestParser.parsingNewPullRequest(); pullRequestParser.parsingNewPullRequest();
} }

View File

@ -2,6 +2,9 @@ package org.sadtech.bot.bitbucketbot.service;
import lombok.NonNull; import lombok.NonNull;
import org.sadtech.bot.bitbucketbot.domain.change.Change; import org.sadtech.bot.bitbucketbot.domain.change.Change;
import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.NewPrChange;
import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.UpdatePrChange;
import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest;
import java.util.List; import java.util.List;
@ -13,12 +16,11 @@ import java.util.List;
*/ */
public interface ChangeService { public interface ChangeService {
/** NewPrChange create(@NonNull PullRequest newPullRequest);
* Позволяет добавить новое изменение в хранилище
* UpdatePrChange createUpdatePr(@NonNull PullRequest oldPullRequest, @NonNull PullRequest newPullRequest);
* @param change Объект, который содержит изменения
*/ Change createReviewersPr(@NonNull PullRequest oldPullRequest, @NonNull PullRequest newPullRequest);
void add(@NonNull Change change);
/** /**
* Позволяет получить новые изменения. * Позволяет получить новые изменения.

View File

@ -24,8 +24,6 @@ public interface PersonService {
Set<Long> getAllTelegramIdByLogin(Set<String> logins); Set<Long> getAllTelegramIdByLogin(Set<String> logins);
Optional<Person> getProxyByLogin(@NonNull String login);
Person create(@NonNull Person person); Person create(@NonNull Person person);
List<Person> createAll(Collection<Person> newUsers); List<Person> createAll(Collection<Person> newUsers);

View File

@ -1,7 +1,7 @@
package org.sadtech.bot.bitbucketbot.service; package org.sadtech.bot.bitbucketbot.service;
import lombok.NonNull; import lombok.NonNull;
import org.sadtech.basic.context.service.BusinessLogicService; import org.sadtech.basic.context.service.SimpleManagerService;
import org.sadtech.basic.context.service.simple.FilterService; import org.sadtech.basic.context.service.simple.FilterService;
import org.sadtech.bot.bitbucketbot.domain.IdAndStatusPr; import org.sadtech.bot.bitbucketbot.domain.IdAndStatusPr;
import org.sadtech.bot.bitbucketbot.domain.PullRequestStatus; import org.sadtech.bot.bitbucketbot.domain.PullRequestStatus;
@ -12,13 +12,19 @@ import org.sadtech.bot.bitbucketbot.domain.filter.PullRequestFilter;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
public interface PullRequestsService extends BusinessLogicService<PullRequest, Long>, FilterService<PullRequest, PullRequestFilter> { public interface PullRequestsService extends SimpleManagerService<PullRequest, Long>, FilterService<PullRequest, PullRequestFilter> {
@NonNull @NonNull
List<PullRequest> getAllByReviewerAndStatuses(@NonNull String login, @NonNull ReviewerStatus reviewerStatus, @NonNull Set<PullRequestStatus> pullRequestStatuses); List<PullRequest> getAllByReviewerAndStatuses(@NonNull String login, @NonNull ReviewerStatus reviewerStatus, @NonNull Set<PullRequestStatus> pullRequestStatuses);
List<PullRequest> getAllByAuthorAndReviewerStatus(@NonNull String login, @NonNull ReviewerStatus status); List<PullRequest> getAllByAuthorAndReviewerStatus(@NonNull String login, @NonNull ReviewerStatus status);
/**
* Получить все идентификаторы вместе со статусами.
*
* @param statuses Статусы ПРов
* @return Объект, содержащий идентификатор и статус ПР
*/
Set<IdAndStatusPr> getAllId(Set<PullRequestStatus> statuses); Set<IdAndStatusPr> getAllId(Set<PullRequestStatus> statuses);
} }

View File

@ -38,7 +38,7 @@ public class PullRequestJsonConverter implements Converter<PullRequestJson, Pull
pullRequest.setRepositorySlug(json.getFromRef().getRepository().getSlug()); pullRequest.setRepositorySlug(json.getFromRef().getRepository().getSlug());
pullRequest.setReviewers(convertReviewers(json.getReviewers())); pullRequest.setReviewers(convertReviewers(json.getReviewers()));
pullRequest.setBitbucketVersion(json.getVersion()); pullRequest.setBitbucketVersion(json.getVersion());
pullRequest.setRepositoryId(json.getFromRef().getRepository().getId());
return pullRequest; return pullRequest;
} }

View File

@ -1,8 +1,6 @@
package org.sadtech.bot.bitbucketbot.service.converter; package org.sadtech.bot.bitbucketbot.service.converter;
import org.sadtech.bot.bitbucketbot.domain.entity.Comment; import org.sadtech.bot.bitbucketbot.domain.entity.Comment;
import org.sadtech.bot.bitbucketbot.domain.entity.Person;
import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest;
import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentJson; import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentJson;
import org.sadtech.bot.bitbucketbot.dto.bitbucket.Severity; import org.sadtech.bot.bitbucketbot.dto.bitbucket.Severity;
import org.sadtech.bot.bitbucketbot.service.executor.ResultScan; import org.sadtech.bot.bitbucketbot.service.executor.ResultScan;
@ -20,7 +18,7 @@ public class ResultScanToComment implements Converter<ResultScan, Comment> {
final Comment comment = new Comment(); final Comment comment = new Comment();
comment.setCreateDate(commentJson.getCreatedDate()); comment.setCreateDate(commentJson.getCreatedDate());
comment.setAuthor(commentJson.getAuthor().getName()); comment.setAuthor(commentJson.getAuthor().getName());
comment.setPullRequestId(getPullRequest(resultScan.getPullRequestId())); comment.setPullRequestId(resultScan.getPullRequestId());
comment.setMessage(commentJson.getText()); comment.setMessage(commentJson.getText());
comment.setUrl(resultScan.getUrlComment()); comment.setUrl(resultScan.getUrlComment());
comment.setBitbucketVersion(commentJson.getVersion()); comment.setBitbucketVersion(commentJson.getVersion());
@ -34,16 +32,4 @@ public class ResultScanToComment implements Converter<ResultScan, Comment> {
} }
private PullRequest getPullRequest(Long pullRequestId) {
final PullRequest pullRequest = new PullRequest();
pullRequest.setId(pullRequestId);
return pullRequest;
}
private Person getAuthor(String name) {
final Person user = new Person();
user.setLogin(name);
return user;
}
} }

View File

@ -1,6 +1,5 @@
package org.sadtech.bot.bitbucketbot.service.converter; package org.sadtech.bot.bitbucketbot.service.converter;
import org.sadtech.bot.bitbucketbot.domain.entity.Person;
import org.sadtech.bot.bitbucketbot.domain.entity.Task; import org.sadtech.bot.bitbucketbot.domain.entity.Task;
import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentJson; import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentJson;
import org.sadtech.bot.bitbucketbot.service.executor.ResultScan; import org.sadtech.bot.bitbucketbot.service.executor.ResultScan;
@ -15,7 +14,7 @@ public class ResultScanToTaskConvert implements Converter<ResultScan, Task> {
final CommentJson json = resultScan.getCommentJson(); final CommentJson json = resultScan.getCommentJson();
final Task task = new Task(); final Task task = new Task();
task.setId(json.getId()); task.setId(json.getId());
task.setAuthor(getAuthor(json)); task.setAuthor(json.getAuthor().getName());
task.setDescription(json.getText()); task.setDescription(json.getText());
task.setCreateDate(json.getCreatedDate()); task.setCreateDate(json.getCreatedDate());
task.setBitbucketVersion(json.getVersion()); task.setBitbucketVersion(json.getVersion());
@ -23,10 +22,4 @@ public class ResultScanToTaskConvert implements Converter<ResultScan, Task> {
return task; return task;
} }
private Person getAuthor(CommentJson json) {
final Person person = new Person();
person.setLogin(json.getAuthor().getName());
return person;
}
} }

View File

@ -10,11 +10,11 @@ public class UserDtoConverter implements Converter<UserDto, Person> {
@Override @Override
public Person convert(UserDto source) { public Person convert(UserDto source) {
return Person.builder() final Person person = new Person();
.login(source.getLogin()) person.setLogin(source.getLogin());
.token(source.getToken()) person.setToken(source.getToken());
.telegramId(source.getTelegramId()) person.setTelegramId(source.getTelegramId());
.build(); return person;
} }
} }

View File

@ -3,9 +3,9 @@ package org.sadtech.bot.bitbucketbot.service.converter;
import org.sadtech.bot.bitbucketbot.domain.entity.Person; import org.sadtech.bot.bitbucketbot.domain.entity.Person;
import org.sadtech.bot.bitbucketbot.dto.bitbucket.UserJson; import org.sadtech.bot.bitbucketbot.dto.bitbucket.UserJson;
import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Component;
@Service @Component
public class UserJsonConverter implements Converter<UserJson, Person> { public class UserJsonConverter implements Converter<UserJson, Person> {
@Override @Override

View File

@ -2,22 +2,100 @@ package org.sadtech.bot.bitbucketbot.service.impl;
import lombok.NonNull; import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.sadtech.bot.bitbucketbot.domain.ReviewerStatus;
import org.sadtech.bot.bitbucketbot.domain.change.Change; import org.sadtech.bot.bitbucketbot.domain.change.Change;
import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.NewPrChange;
import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.ReviewersPrChange;
import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.UpdatePrChange;
import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest;
import org.sadtech.bot.bitbucketbot.domain.entity.Reviewer;
import org.sadtech.bot.bitbucketbot.domain.util.ReviewerChange;
import org.sadtech.bot.bitbucketbot.repository.ChangeRepository; import org.sadtech.bot.bitbucketbot.repository.ChangeRepository;
import org.sadtech.bot.bitbucketbot.service.ChangeService; import org.sadtech.bot.bitbucketbot.service.ChangeService;
import org.sadtech.bot.bitbucketbot.service.PersonService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class ChangeServiceImpl implements ChangeService { public class ChangeServiceImpl implements ChangeService {
private final ChangeRepository changeRepository; private final ChangeRepository changeRepository;
private final PersonService personService;
@Override @Override
public void add(@NonNull Change change) { public NewPrChange create(@NonNull PullRequest newPullRequest) {
changeRepository.add(change); return changeRepository.add(
NewPrChange.builder()
.author(newPullRequest.getAuthorLogin())
.description(newPullRequest.getDescription())
.title(newPullRequest.getTitle())
.url(newPullRequest.getUrl())
.telegramIds(getReviewerTelegrams(newPullRequest.getReviewers()))
.build()
);
}
@Override
public UpdatePrChange createUpdatePr(@NonNull PullRequest oldPullRequest, @NonNull PullRequest newPullRequest) {
return changeRepository.add(
UpdatePrChange.builder()
.author(oldPullRequest.getAuthorLogin())
.name(newPullRequest.getTitle())
.telegramIds(getReviewerTelegrams(newPullRequest.getReviewers()))
.url(newPullRequest.getUrl())
.build()
);
}
@Override
public Change createReviewersPr(@NonNull PullRequest oldPullRequest, @NonNull PullRequest newPullRequest) {
final Map<Long, Reviewer> oldReviewers = oldPullRequest.getReviewers().stream()
.collect(Collectors.toMap(Reviewer::getId, reviewer -> reviewer));
final Map<Long, Reviewer> newReviewers = newPullRequest.getReviewers().stream()
.collect(Collectors.toMap(Reviewer::getId, reviewer -> reviewer));
final List<ReviewerChange> reviewerChanges = new ArrayList<>();
for (Reviewer newReviewer : newReviewers.values()) {
if (oldReviewers.containsKey(newReviewer.getId())) {
final Reviewer oldReviewer = oldReviewers.get(newReviewer.getId());
final ReviewerStatus oldStatus = oldReviewer.getStatus();
final ReviewerStatus newStatus = newReviewer.getStatus();
if (!oldStatus.equals(newStatus)) {
reviewerChanges.add(ReviewerChange.ofOld(oldReviewer.getUserLogin(), oldStatus, newStatus));
}
} else {
reviewerChanges.add(ReviewerChange.ofNew(newReviewer.getUserLogin(), newReviewer.getStatus()));
}
}
final Set<Long> oldIds = oldReviewers.keySet();
oldIds.removeAll(newReviewers.keySet());
reviewerChanges.addAll(
oldReviewers.entrySet().stream()
.filter(e -> oldIds.contains(e.getKey()))
.map(e -> ReviewerChange.ofDeleted(e.getValue().getUserLogin()))
.collect(Collectors.toList())
);
return changeRepository.add(
ReviewersPrChange.builder()
.title(newPullRequest.getTitle())
.url(newPullRequest.getUrl())
.telegramId(personService.getTelegramIdByLogin(newPullRequest.getAuthorLogin()).orElse(null))
.reviewerChanges(reviewerChanges)
.build()
);
}
private Set<Long> getReviewerTelegrams(@NonNull List<Reviewer> reviewers) {
return personService.getAllTelegramIdByLogin(
reviewers.stream()
.map(Reviewer::getUserLogin)
.collect(Collectors.toSet())
);
} }
@Override @Override

View File

@ -1,100 +1,79 @@
package org.sadtech.bot.bitbucketbot.service.impl; package org.sadtech.bot.bitbucketbot.service.impl;
import lombok.NonNull; //@Service
import lombok.RequiredArgsConstructor; //@RequiredArgsConstructor
import org.sadtech.bot.bitbucketbot.config.InitConfig; //public class CommentServiceImpl implements CommentService {
import org.sadtech.bot.bitbucketbot.domain.Pagination; //
import org.sadtech.bot.bitbucketbot.domain.entity.Comment; // private final PersonService personService;
import org.sadtech.bot.bitbucketbot.exception.NotFoundException; // private final CommentRepository commentRepository;
import org.sadtech.bot.bitbucketbot.repository.jpa.CommentRepository; // private final PullRequestsService pullRequestsService;
import org.sadtech.bot.bitbucketbot.service.CommentService; // private final InitConfig initConfig;
import org.sadtech.bot.bitbucketbot.service.PersonService; //
import org.sadtech.bot.bitbucketbot.service.PullRequestsService; // @Override
import org.springframework.data.domain.Page; // public Long getLastCommentId() {
import org.springframework.data.domain.PageRequest; // return commentRepository.findFirstByOrderByIdDesc().map(Comment::getId).orElse(getInitCommentId());
import org.springframework.stereotype.Service; // }
//
import javax.transaction.Transactional; // private Long getInitCommentId() {
import java.time.LocalDateTime; // return initConfig.getStartCommentId() != null ? initConfig.getStartCommentId() : 0L;
import java.util.List; // }
import java.util.Optional; //
import java.util.Set; // @Override
import java.util.stream.Collectors; // public Page<Comment> getAll(@NonNull Pagination pagination) {
// return commentRepository.findAll(PageRequest.of(pagination.getPage(), pagination.getSize()));
@Service // }
@RequiredArgsConstructor //
public class CommentServiceImpl implements CommentService { // @Override
// public @NonNull List<Comment> getAllBetweenDate(LocalDateTime dateFrom, LocalDateTime dateTo) {
private final PersonService personService; // return commentRepository.findByDateBetween(dateFrom, dateTo);
private final CommentRepository commentRepository; // }
private final PullRequestsService pullRequestsService; //
private final InitConfig initConfig; // @Override
// public Comment create(@NonNull Comment comment) {
@Override // comment.setAuthor(personService.getProxyByLogin(
public Long getLastCommentId() { // comment.getAuthor().getLogin()).orElseThrow(() -> new NotFoundException(""))
return commentRepository.findFirstByOrderByIdDesc().map(Comment::getId).orElse(getInitCommentId()); // );
} // comment.setPullRequest(
// pullRequestsService.getProxyById(comment.getPullRequest().getId()).orElseThrow(() -> new NotFoundException(""))
private Long getInitCommentId() { // );
return initConfig.getStartCommentId() != null ? initConfig.getStartCommentId() : 0L; // return commentRepository.save(comment);
} // }
//
@Override // @Override
public Page<Comment> getAll(@NonNull Pagination pagination) { // public void delete(@NonNull Long id) {
return commentRepository.findAll(PageRequest.of(pagination.getPage(), pagination.getSize())); // commentRepository.deleteById(id);
} // }
//
@Override // @Override
public @NonNull List<Comment> getAllBetweenDate(LocalDateTime dateFrom, LocalDateTime dateTo) { // public Optional<Comment> getProxyById(@NonNull Long id) {
return commentRepository.findByDateBetween(dateFrom, dateTo); // return Optional.ofNullable(commentRepository.getOne(id));
} // }
//
@Override // @Override
public Comment create(@NonNull Comment comment) { // @Transactional
comment.setAuthor(personService.getProxyByLogin( // public List<Comment> createAll(List<Comment> newComments) {
comment.getAuthor().getLogin()).orElseThrow(() -> new NotFoundException("")) // return newComments.stream()
); // .map(this::create)
comment.setPullRequest( // .collect(Collectors.toList());
pullRequestsService.getProxyById(comment.getPullRequest().getId()).orElseThrow(() -> new NotFoundException("")) // }
); //
return commentRepository.save(comment); // @Override
} // public Comment update(Comment comment) {
// final Comment oldComment = commentRepository.findById(comment.getId())
@Override // .orElseThrow(() -> new NotFoundException("Комментарий не найден"));
public void delete(@NonNull Long id) { //
commentRepository.deleteById(id); // if (oldComment.getBitbucketVersion().equals(comment.getBitbucketVersion())) {
} // oldComment.setBitbucketVersion(comment.getBitbucketVersion());
// oldComment.setMessage(oldComment.getMessage());
@Override // return commentRepository.save(oldComment);
public Optional<Comment> getProxyById(@NonNull Long id) { // }
return Optional.ofNullable(commentRepository.getOne(id)); //
} // return oldComment;
// }
@Override //
@Transactional // @Override
public List<Comment> createAll(List<Comment> newComments) { // public List<Comment> getAllById(@NonNull Set<Long> ids) {
return newComments.stream() // return commentRepository.findAllById(ids);
.map(this::create) // }
.collect(Collectors.toList()); //
} //}
@Override
public Comment update(Comment comment) {
final Comment oldComment = commentRepository.findById(comment.getId())
.orElseThrow(() -> new NotFoundException("Комментарий не найден"));
if (oldComment.getBitbucketVersion().equals(comment.getBitbucketVersion())) {
oldComment.setBitbucketVersion(comment.getBitbucketVersion());
oldComment.setMessage(oldComment.getMessage());
return commentRepository.save(oldComment);
}
return oldComment;
}
@Override
public List<Comment> getAllById(@NonNull Set<Long> ids) {
return commentRepository.findAllById(ids);
}
}

View File

@ -2,12 +2,13 @@ package org.sadtech.bot.bitbucketbot.service.impl;
import lombok.NonNull; import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.sadtech.basic.core.util.Assert;
import org.sadtech.bot.bitbucketbot.config.properties.BitbucketProperty; import org.sadtech.bot.bitbucketbot.config.properties.BitbucketProperty;
import org.sadtech.bot.bitbucketbot.domain.entity.Person; import org.sadtech.bot.bitbucketbot.domain.entity.Person;
import org.sadtech.bot.bitbucketbot.dto.bitbucket.sheet.PullRequestSheetJson; import org.sadtech.bot.bitbucketbot.dto.bitbucket.sheet.PullRequestSheetJson;
import org.sadtech.bot.bitbucketbot.exception.CreateException;
import org.sadtech.bot.bitbucketbot.exception.RegException; import org.sadtech.bot.bitbucketbot.exception.RegException;
import org.sadtech.bot.bitbucketbot.repository.jpa.PersonRepository; import org.sadtech.bot.bitbucketbot.repository.PersonRepository;
import org.sadtech.bot.bitbucketbot.service.PersonService; import org.sadtech.bot.bitbucketbot.service.PersonService;
import org.sadtech.bot.bitbucketbot.service.Utils; import org.sadtech.bot.bitbucketbot.service.Utils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -18,6 +19,7 @@ import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Slf4j
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class PersonServiceImpl implements PersonService { public class PersonServiceImpl implements PersonService {
@ -27,12 +29,14 @@ public class PersonServiceImpl implements PersonService {
@Override @Override
public Optional<Person> getByLogin(String login) { public Optional<Person> getByLogin(String login) {
return personRepository.findById(login); return personRepository.findByLogin(login);
} }
@Override @Override
public Set<String> existsByLogin(@NonNull Set<String> logins) { public Set<String> existsByLogin(@NonNull Set<String> logins) {
return logins.stream().filter(personRepository::existsById).collect(Collectors.toSet()); return logins.stream()
.filter(personRepository::existsByLogin)
.collect(Collectors.toSet());
} }
@Override @Override
@ -75,17 +79,10 @@ public class PersonServiceImpl implements PersonService {
return personRepository.findAllTelegramIdByLogin(logins); return personRepository.findAllTelegramIdByLogin(logins);
} }
@Override
public Optional<Person> getProxyByLogin(@NonNull String login) {
return Optional.ofNullable(personRepository.getByLogin(login));
}
@Override @Override
public Person create(@NonNull Person person) { public Person create(@NonNull Person person) {
if (person.getId() == null) { Assert.isNotNull(person.getLogin(), "При создании пользователя должен присутствовать логин");
return personRepository.save(person); return personRepository.save(person);
}
throw new CreateException("При создании пользователя должен отсутствовать id");
} }
@Override @Override

View File

@ -4,7 +4,8 @@ import lombok.NonNull;
import org.sadtech.basic.context.page.Pagination; import org.sadtech.basic.context.page.Pagination;
import org.sadtech.basic.context.page.Sheet; import org.sadtech.basic.context.page.Sheet;
import org.sadtech.basic.context.service.simple.FilterService; import org.sadtech.basic.context.service.simple.FilterService;
import org.sadtech.basic.core.service.AbstractBusinessLogicService; import org.sadtech.basic.core.service.AbstractSimpleManagerService;
import org.sadtech.basic.core.util.Assert;
import org.sadtech.basic.filter.criteria.CriteriaFilter; import org.sadtech.basic.filter.criteria.CriteriaFilter;
import org.sadtech.basic.filter.criteria.CriteriaQuery; import org.sadtech.basic.filter.criteria.CriteriaQuery;
import org.sadtech.bot.bitbucketbot.domain.IdAndStatusPr; import org.sadtech.bot.bitbucketbot.domain.IdAndStatusPr;
@ -13,12 +14,10 @@ import org.sadtech.bot.bitbucketbot.domain.ReviewerStatus;
import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest; import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest;
import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest_; import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest_;
import org.sadtech.bot.bitbucketbot.domain.filter.PullRequestFilter; import org.sadtech.bot.bitbucketbot.domain.filter.PullRequestFilter;
import org.sadtech.bot.bitbucketbot.exception.CreateException;
import org.sadtech.bot.bitbucketbot.exception.UpdateException; import org.sadtech.bot.bitbucketbot.exception.UpdateException;
import org.sadtech.bot.bitbucketbot.repository.PullRequestsRepository; import org.sadtech.bot.bitbucketbot.repository.PullRequestsRepository;
import org.sadtech.bot.bitbucketbot.service.ChangeService; import org.sadtech.bot.bitbucketbot.service.ChangeService;
import org.sadtech.bot.bitbucketbot.service.PullRequestsService; import org.sadtech.bot.bitbucketbot.service.PullRequestsService;
import org.sadtech.bot.bitbucketbot.utils.ChangeGenerator;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -27,7 +26,7 @@ import java.util.Optional;
import java.util.Set; import java.util.Set;
@Service @Service
public class PullRequestsServiceImpl extends AbstractBusinessLogicService<PullRequest, Long> implements PullRequestsService { public class PullRequestsServiceImpl extends AbstractSimpleManagerService<PullRequest, Long> implements PullRequestsService {
private final ChangeService changeService; private final ChangeService changeService;
private final PullRequestsRepository pullRequestsRepository; private final PullRequestsRepository pullRequestsRepository;
@ -46,12 +45,13 @@ public class PullRequestsServiceImpl extends AbstractBusinessLogicService<PullRe
@Override @Override
public PullRequest create(@NonNull PullRequest pullRequest) { public PullRequest create(@NonNull PullRequest pullRequest) {
if (pullRequest.getId() == null) { Assert.isNull(pullRequest.getId(), "При создании идентификатор должен быть пустым");
final PullRequest newPullRequest = pullRequestsRepository.save(pullRequest);
changeService.add(ChangeGenerator.create(newPullRequest)); final PullRequest newPullRequest = pullRequestsRepository.save(pullRequest);
return newPullRequest;
} changeService.create(newPullRequest);
throw new CreateException("При создании идентификатор должен быть пустым");
return newPullRequest;
} }
@Override @Override
@ -59,7 +59,7 @@ public class PullRequestsServiceImpl extends AbstractBusinessLogicService<PullRe
final PullRequest oldPullRequest = findAndFillId(pullRequest); final PullRequest oldPullRequest = findAndFillId(pullRequest);
if (!oldPullRequest.getBitbucketVersion().equals(pullRequest.getBitbucketVersion())) { if (!oldPullRequest.getBitbucketVersion().equals(pullRequest.getBitbucketVersion())) {
oldPullRequest.setBitbucketVersion(pullRequest.getVersion()); oldPullRequest.setBitbucketVersion(pullRequest.getBitbucketVersion());
oldPullRequest.setConflict(pullRequest.isConflict()); oldPullRequest.setConflict(pullRequest.isConflict());
oldPullRequest.setTitle(pullRequest.getTitle()); oldPullRequest.setTitle(pullRequest.getTitle());
oldPullRequest.setDescription(pullRequest.getDescription()); oldPullRequest.setDescription(pullRequest.getDescription());
@ -68,8 +68,8 @@ public class PullRequestsServiceImpl extends AbstractBusinessLogicService<PullRe
final PullRequest newPullRequest = pullRequestsRepository.save(oldPullRequest); final PullRequest newPullRequest = pullRequestsRepository.save(oldPullRequest);
changeService.add(ChangeGenerator.createUpdatePr(pullRequest, newPullRequest)); changeService.createUpdatePr(pullRequest, newPullRequest);
changeService.add(ChangeGenerator.createReviewersPr(pullRequest, newPullRequest)); changeService.createReviewersPr(pullRequest, newPullRequest);
return newPullRequest; return newPullRequest;
} }

View File

@ -1,66 +0,0 @@
package org.sadtech.bot.bitbucketbot.service.impl;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest;
import org.sadtech.bot.bitbucketbot.service.PullRequestsService;
import org.sadtech.bot.bitbucketbot.service.ReportService;
import org.sadtech.bot.bitbucketbot.utils.Smile;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public class ReportServiceSimple implements ReportService {
private final PullRequestsService pullRequestsService;
@Override
public String generateReport(@NonNull String login) {
final LocalDateTime now = LocalDateTime.now();
final Map<LocalDate, List<PullRequest>> prByDay = pullRequestsService.getAllByAuthor(login, now.minusDays(7L), now).stream()
.collect(Collectors.groupingBy(pullRequest -> pullRequest.getUpdateDate().toLocalDate()));
return generateMessage(prByDay).orElse("Кажется эту неделю ты не работал");
}
private Optional<String> generateMessage(@NonNull Map<LocalDate, List<PullRequest>> prByDay) {
if (!prByDay.isEmpty()) {
final StringBuilder message = new StringBuilder("Твой отчет на эту неделю:").append(Smile.TWO_BR);
for (Map.Entry<LocalDate, List<PullRequest>> entry : prByDay.entrySet()) {
message.append(dayOfWeek(entry.getKey())).append(": ");
for (PullRequest pullRequest : entry.getValue()) {
message.append(" - ").append(pullRequest.getName()).append(Smile.BR)
.append(" --").append(pullRequest.getDescription());
}
}
}
return Optional.empty();
}
private String dayOfWeek(LocalDate date) {
switch (date.getDayOfWeek()) {
case MONDAY:
return "Понедельник";
case SUNDAY:
return "Воскресенье";
case TUESDAY:
return "Вторник";
case SATURDAY:
return "Суббота";
case THURSDAY:
return "Четверг";
case WEDNESDAY:
return "Среда";
case FRIDAY:
return "Пятница";
}
return "";
}
}

View File

@ -1,10 +1,7 @@
package org.sadtech.bot.bitbucketbot.service.impl.filter; package org.sadtech.bot.bitbucketbot.service.impl.filter;
import lombok.NonNull; import lombok.NonNull;
import lombok.RequiredArgsConstructor; import org.sadtech.basic.core.service.AbstractFilterService;
import org.sadtech.basic.context.page.Pagination;
import org.sadtech.basic.context.page.Sheet;
import org.sadtech.basic.context.service.simple.FilterService;
import org.sadtech.basic.filter.Filter; import org.sadtech.basic.filter.Filter;
import org.sadtech.basic.filter.FilterQuery; import org.sadtech.basic.filter.FilterQuery;
import org.sadtech.basic.filter.criteria.CriteriaFilter; import org.sadtech.basic.filter.criteria.CriteriaFilter;
@ -15,33 +12,19 @@ import org.sadtech.bot.bitbucketbot.domain.filter.PullRequestFilter;
import org.sadtech.bot.bitbucketbot.repository.PullRequestsRepository; import org.sadtech.bot.bitbucketbot.repository.PullRequestsRepository;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service @Service
@RequiredArgsConstructor public class PullRequestFilterService extends AbstractFilterService<PullRequest, PullRequestFilter> {
public class PullRequestFilterService implements FilterService<PullRequest, PullRequestFilter> {
private final PullRequestsRepository pullRequestsRepository; public PullRequestFilterService(PullRequestsRepository filterOperation) {
super(filterOperation);
@Override
public Sheet<PullRequest> getAll(@NonNull PullRequestFilter filter, Pagination pagination) {
return pullRequestsRepository.findAll(createFilter(filter), pagination);
} }
@Override @Override
public List<PullRequest> getAll(@NonNull PullRequestFilter filter) { protected Filter createFilter(@NonNull PullRequestFilter filter) {
return pullRequestsRepository.findAll(createFilter(filter)); return CriteriaFilter.<PullRequest>create()
} .and(
convertFilter(filter)
@Override );
public Optional<PullRequest> getFirst(@NonNull PullRequestFilter filter) {
return pullRequestsRepository.findFirst(createFilter(filter));
}
@Override
public boolean exists(@NonNull PullRequestFilter filter) {
return pullRequestsRepository.exists(createFilter(filter));
} }
private FilterQuery convertFilter(@NonNull PullRequestFilter filter) { private FilterQuery convertFilter(@NonNull PullRequestFilter filter) {
@ -50,11 +33,4 @@ public class PullRequestFilterService implements FilterService<PullRequest, Pull
.matchPhrase(PullRequest_.REPOSITORY_ID, filter.getBitbucketRepositoryId()); .matchPhrase(PullRequest_.REPOSITORY_ID, filter.getBitbucketRepositoryId());
} }
private Filter createFilter(PullRequestFilter filter) {
return CriteriaFilter.<PullRequest>create()
.and(
convertFilter(filter)
);
}
} }

View File

@ -0,0 +1,51 @@
package org.sadtech.bot.bitbucketbot.service.impl.parser;
import lombok.RequiredArgsConstructor;
import org.sadtech.bot.bitbucketbot.config.properties.BitbucketProperty;
import org.sadtech.bot.bitbucketbot.domain.entity.Person;
import org.sadtech.bot.bitbucketbot.dto.bitbucket.UserJson;
import org.sadtech.bot.bitbucketbot.dto.bitbucket.sheet.UserSheetJson;
import org.sadtech.bot.bitbucketbot.service.PersonService;
import org.sadtech.bot.bitbucketbot.service.Utils;
import org.sadtech.bot.bitbucketbot.service.parser.PersonParser;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public class PersonBitbucketParser implements PersonParser {
private final PersonService personService;
private final ConversionService conversionService;
private final BitbucketProperty bitbucketProperty;
@Override
public void scanNewPerson() {
Optional<UserSheetJson> sheetJson = Utils.urlToJson(bitbucketProperty.getUrlUsers(), bitbucketProperty.getToken(), UserSheetJson.class);
while (sheetJson.isPresent() && sheetJson.get().hasContent()) {
final UserSheetJson sheetUsers = sheetJson.get();
final List<UserJson> users = sheetUsers.getValues();
final Set<String> logins = users.stream().map(UserJson::getName).collect(Collectors.toSet());
final Set<String> existsLogins = personService.existsByLogin(logins);
final Set<Person> newUsers = users.stream()
.filter(userJson -> !existsLogins.contains(userJson.getName()))
.map(userJson -> conversionService.convert(userJson, Person.class))
.collect(Collectors.toSet());
if (!newUsers.isEmpty()) {
personService.createAll(newUsers);
}
if (sheetUsers.getNextPageStart() != null) {
sheetJson = Utils.urlToJson(bitbucketProperty.getUrlUsers() + sheetUsers.getNextPageStart(), bitbucketProperty.getToken(), UserSheetJson.class);
} else {
break;
}
}
}
}

View File

@ -0,0 +1,130 @@
package org.sadtech.bot.bitbucketbot.service.impl.parser;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.sadtech.bot.bitbucketbot.config.properties.BitbucketProperty;
import org.sadtech.bot.bitbucketbot.domain.IdAndStatusPr;
import org.sadtech.bot.bitbucketbot.domain.PullRequestStatus;
import org.sadtech.bot.bitbucketbot.domain.entity.Person;
import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest;
import org.sadtech.bot.bitbucketbot.domain.filter.PullRequestFilter;
import org.sadtech.bot.bitbucketbot.dto.bitbucket.PullRequestJson;
import org.sadtech.bot.bitbucketbot.dto.bitbucket.sheet.PullRequestSheetJson;
import org.sadtech.bot.bitbucketbot.service.PersonService;
import org.sadtech.bot.bitbucketbot.service.PullRequestsService;
import org.sadtech.bot.bitbucketbot.service.Utils;
import org.sadtech.bot.bitbucketbot.service.parser.PullRequestParser;
import org.sadtech.bot.bitbucketbot.utils.Pair;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.sadtech.bot.bitbucketbot.domain.PullRequestStatus.DECLINED;
import static org.sadtech.bot.bitbucketbot.domain.PullRequestStatus.MERGED;
import static org.sadtech.bot.bitbucketbot.domain.PullRequestStatus.OPEN;
@Slf4j
@Service
@RequiredArgsConstructor
public class PullRequestBitbucketParser implements PullRequestParser {
private static final Set<PullRequestStatus> OLD_STATUSES = Stream.of(MERGED, OPEN, DECLINED).collect(Collectors.toSet());
private final PullRequestsService pullRequestsService;
private final PersonService personService;
private final ConversionService conversionService;
private final BitbucketProperty bitbucketProperty;
@Override
public void parsingOldPullRequest() {
final Set<Long> existsId = pullRequestsService.getAllId(OLD_STATUSES).stream()
.map(IdAndStatusPr::getId)
.collect(Collectors.toSet());
final Set<Long> openId = parsingPullRequest(bitbucketProperty.getUrlPullRequestOpen());
final Set<Long> closeId = parsingPullRequest(bitbucketProperty.getUrlPullRequestClose());
final Set<Long> newNotExistsId = existsId.stream()
.filter(id -> !openId.contains(id) && !closeId.contains(id))
.collect(Collectors.toSet());
log.info("Открыты: " + Arrays.toString(openId.toArray()));
log.info("Закрыты: " + Arrays.toString(closeId.toArray()));
log.info("Не найдены: " + Arrays.toString(newNotExistsId.toArray()));
if (!newNotExistsId.isEmpty()) {
pullRequestsService.deleteAllById(newNotExistsId);
}
}
@Override
public void parsingNewPullRequest() {
final List<Person> users = personService.getAllRegister();
for (Person user : users) {
Optional<PullRequestSheetJson> sheetJson = Utils.urlToJson(bitbucketProperty.getUrlPullRequestOpen(), user.getToken(), PullRequestSheetJson.class);
while (sheetJson.isPresent() && sheetJson.get().hasContent()) {
final PullRequestSheetJson pullRequestBitbucketSheet = sheetJson.get();
final List<PullRequest> newPullRequest = pullRequestBitbucketSheet.getValues().stream()
.collect(Collectors.toMap(pullRequestJson -> new Pair<>(pullRequestJson.getId(), pullRequestJson.getFromRef().getRepository().getId()), pullRequestJson -> pullRequestJson))
.values()
.stream()
.filter(pullRequestJson -> !pullRequestsService.exists(bitbucketIdAndPullRequestId(pullRequestJson)))
.map(pullRequestJson -> conversionService.convert(pullRequestJson, PullRequest.class))
.collect(Collectors.toList());
pullRequestsService.createAll(newPullRequest);
if (pullRequestBitbucketSheet.getNextPageStart() != null) {
sheetJson = Utils.urlToJson(bitbucketProperty.getUrlPullRequestOpen() + pullRequestBitbucketSheet.getNextPageStart(), bitbucketProperty.getToken(), PullRequestSheetJson.class);
} else {
break;
}
}
}
}
private Set<Long> parsingPullRequest(@NonNull String url) {
final List<Person> users = personService.getAllRegister();
final Set<Long> ids = new HashSet<>();
for (Person user : users) {
Optional<PullRequestSheetJson> sheetJson = Utils.urlToJson(url, user.getToken(), PullRequestSheetJson.class);
while (sheetJson.isPresent() && sheetJson.get().hasContent()) {
final PullRequestSheetJson jsonSheet = sheetJson.get();
final List<PullRequest> existsPr = getExistsPr(jsonSheet.getValues());
ids.addAll(
pullRequestsService.updateAll(existsPr).stream()
.map(PullRequest::getId)
.collect(Collectors.toSet())
);
if (jsonSheet.getNextPageStart() != null) {
sheetJson = Utils.urlToJson(url + jsonSheet.getNextPageStart(), bitbucketProperty.getToken(), PullRequestSheetJson.class);
} else {
break;
}
}
}
return ids;
}
private List<PullRequest> getExistsPr(@NonNull List<PullRequestJson> pullRequestJsons) {
return pullRequestJsons.stream()
.map(json -> pullRequestsService.getFirst(bitbucketIdAndPullRequestId(json)))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
}
private PullRequestFilter bitbucketIdAndPullRequestId(PullRequestJson json) {
return PullRequestFilter.builder()
.bitbucketId(json.getId())
.bitbucketRepositoryId(json.getFromRef().getRepository().getId())
.build();
}
}

View File

@ -1,44 +1,8 @@
package org.sadtech.bot.bitbucketbot.service.parser; package org.sadtech.bot.bitbucketbot.service.parser;
import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.sadtech.bot.bitbucketbot.config.properties.BitbucketProperty;
import org.sadtech.bot.bitbucketbot.config.properties.CommentSchedulerProperty;
import org.sadtech.bot.bitbucketbot.domain.Answer;
import org.sadtech.bot.bitbucketbot.domain.Pagination;
import org.sadtech.bot.bitbucketbot.domain.change.ChangeType;
import org.sadtech.bot.bitbucketbot.domain.change.comment.AnswerCommentChange;
import org.sadtech.bot.bitbucketbot.domain.change.comment.CommentChange;
import org.sadtech.bot.bitbucketbot.domain.change.task.TaskChange;
import org.sadtech.bot.bitbucketbot.domain.entity.Comment;
import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest;
import org.sadtech.bot.bitbucketbot.domain.entity.Task;
import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentJson;
import org.sadtech.bot.bitbucketbot.dto.bitbucket.Severity;
import org.sadtech.bot.bitbucketbot.service.ChangeService;
import org.sadtech.bot.bitbucketbot.service.CommentService;
import org.sadtech.bot.bitbucketbot.service.PersonService;
import org.sadtech.bot.bitbucketbot.service.PullRequestsService;
import org.sadtech.bot.bitbucketbot.service.TaskService;
import org.sadtech.bot.bitbucketbot.service.Utils;
import org.sadtech.bot.bitbucketbot.service.executor.DataScan;
import org.sadtech.bot.bitbucketbot.service.executor.ResultScan;
import org.sadtech.bot.bitbucketbot.service.impl.ExecutorScanner;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/** /**
* <p>Поиск новых комментариев и задач.</p> * <p>Поиск новых комментариев и задач.</p>
* <p>К несчастью, у битбакета не очень удобный API, и у них таска это то же самое что и комментарий, только с флагом</p> * <p>К несчастью, у битбакета не очень удобный API, и у них таска это то же самое что и комментарий, только с флагом</p>
@ -46,168 +10,168 @@ import java.util.stream.Collectors;
@Component @Component
@RequiredArgsConstructor @RequiredArgsConstructor
public class CommentAndTaskParser { public class CommentAndTaskParser {
//
private static final Pattern PATTERN = Pattern.compile("@[\\w]+"); // private static final Pattern PATTERN = Pattern.compile("@[\\w]+");
//
private final CommentService commentService; // private final CommentService commentService;
private final PullRequestsService pullRequestsService; // private final PullRequestsService pullRequestsService;
private final PersonService personService; // private final PersonService personService;
private final ChangeService changeService; // private final ChangeService changeService;
private final ExecutorScanner executorScanner; // private final ExecutorScanner executorScanner;
private final TaskService taskService; // private final TaskService taskService;
private final ConversionService conversionService; // private final ConversionService conversionService;
//
private final BitbucketProperty bitbucketProperty; // private final BitbucketProperty bitbucketProperty;
private final CommentSchedulerProperty commentSchedulerProperty; // private final CommentSchedulerProperty commentSchedulerProperty;
//
public void scanNewCommentAndTask() { // public void scanNewCommentAndTask() {
long commentId = getLastIdCommentOrTask() + 1; // long commentId = getLastIdCommentOrTask() + 1;
int count = 0; // int count = 0;
do { // do {
final List<DataScan> dataScans = generatingLinksToPossibleComments(commentId); // final List<DataScan> dataScans = generatingLinksToPossibleComments(commentId);
executorScanner.registration(dataScans); // executorScanner.registration(dataScans);
final List<ResultScan> resultScans = executorScanner.getResult(); // final List<ResultScan> resultScans = executorScanner.getResult();
if (!resultScans.isEmpty()) { // if (!resultScans.isEmpty()) {
processingComments(resultScans); // processingComments(resultScans);
processingTasks(resultScans); // processingTasks(resultScans);
count = 0; // count = 0;
} // }
} while (count++ < commentSchedulerProperty.getNoCommentCount()); // } while (count++ < commentSchedulerProperty.getNoCommentCount());
} // }
//
private long getLastIdCommentOrTask() { // private long getLastIdCommentOrTask() {
return Long.max(commentService.getLastCommentId(), taskService.getLastTaskId()); // return Long.max(commentService.getLastCommentId(), taskService.getLastTaskId());
} // }
//
private void processingComments(List<ResultScan> resultScans) { // private void processingComments(List<ResultScan> resultScans) {
final List<Comment> newComments = commentService.createAll(getCommentsByResultScan(resultScans)); // final List<Comment> newComments = commentService.createAll(getCommentsByResultScan(resultScans));
newComments.forEach(this::notificationPersonal); // newComments.forEach(this::notificationPersonal);
} // }
//
private void processingTasks(List<ResultScan> resultScans) { // private void processingTasks(List<ResultScan> resultScans) {
final List<Task> newTasks = taskService.createAll(getTaskByResultScan(resultScans)); // final List<Task> newTasks = taskService.createAll(getTaskByResultScan(resultScans));
newTasks.forEach(this::notificationNewTask); // newTasks.forEach(this::notificationNewTask);
} // }
//
private List<DataScan> generatingLinksToPossibleComments(@NonNull Long commentId) { // private List<DataScan> generatingLinksToPossibleComments(@NonNull Long commentId) {
List<DataScan> commentUrls = new ArrayList<>(); // List<DataScan> commentUrls = new ArrayList<>();
for (int i = 0; i < 5; i++) { // for (int i = 0; i < 5; i++) {
int page = 0; // int page = 0;
Page<PullRequest> pullRequestPage = pullRequestsService.getAll( // Page<PullRequest> pullRequestPage = pullRequestsService.getAll(
Pagination.of(page, commentSchedulerProperty.getCommentCount()) // Pagination.of(page, commentSchedulerProperty.getCommentCount())
); // );
while (pullRequestPage.hasContent()) { // while (pullRequestPage.hasContent()) {
long finalCommentId = commentId; // long finalCommentId = commentId;
commentUrls.addAll(pullRequestPage.getContent().stream() // commentUrls.addAll(pullRequestPage.getContent().stream()
.map( // .map(
pullRequest -> new DataScan( // pullRequest -> new DataScan(
getCommentUrl(finalCommentId, pullRequest), // getCommentUrl(finalCommentId, pullRequest),
pullRequest.getId() // pullRequest.getId()
) // )
) // )
.collect(Collectors.toList())); // .collect(Collectors.toList()));
pullRequestPage = pullRequestsService.getAll( // pullRequestPage = pullRequestsService.getAll(
Pagination.of(++page, commentSchedulerProperty.getCommentCount()) // Pagination.of(++page, commentSchedulerProperty.getCommentCount())
); // );
} // }
commentId++; // commentId++;
} // }
return commentUrls; // return commentUrls;
} // }
//
private List<Comment> getCommentsByResultScan(List<ResultScan> resultScans) { // private List<Comment> getCommentsByResultScan(List<ResultScan> resultScans) {
return resultScans.stream() // return resultScans.stream()
.filter(resultScan -> Severity.NORMAL.equals(resultScan.getCommentJson().getSeverity())) // .filter(resultScan -> Severity.NORMAL.equals(resultScan.getCommentJson().getSeverity()))
.map(resultScan -> conversionService.convert(resultScan, Comment.class)) // .map(resultScan -> conversionService.convert(resultScan, Comment.class))
.collect(Collectors.toList()); // .collect(Collectors.toList());
} // }
//
private List<Task> getTaskByResultScan(List<ResultScan> resultScans) { // private List<Task> getTaskByResultScan(List<ResultScan> resultScans) {
return resultScans.stream() // return resultScans.stream()
.filter(commentJson -> Severity.BLOCKER.equals(commentJson.getCommentJson().getSeverity())) // .filter(commentJson -> Severity.BLOCKER.equals(commentJson.getCommentJson().getSeverity()))
.map(resultScan -> conversionService.convert(resultScan, Task.class)) // .map(resultScan -> conversionService.convert(resultScan, Task.class))
.collect(Collectors.toList()); // .collect(Collectors.toList());
} // }
//
private String getCommentUrl(long commentId, PullRequest pullRequest) { // private String getCommentUrl(long commentId, PullRequest pullRequest) {
return bitbucketProperty.getUrlPullRequestComment() // return bitbucketProperty.getUrlPullRequestComment()
.replace("{projectKey}", pullRequest.getProjectKey()) // .replace("{projectKey}", pullRequest.getProjectKey())
.replace("{repositorySlug}", pullRequest.getRepositorySlug()) // .replace("{repositorySlug}", pullRequest.getRepositorySlug())
.replace("{pullRequestId}", pullRequest.getBitbucketId().toString()) // .replace("{pullRequestId}", pullRequest.getBitbucketId().toString())
.replace("{commentId}", String.valueOf(commentId)); // .replace("{commentId}", String.valueOf(commentId));
} // }
//
private void notificationPersonal(@NonNull Comment comment) { // private void notificationPersonal(@NonNull Comment comment) {
Matcher matcher = PATTERN.matcher(comment.getMessage()); // Matcher matcher = PATTERN.matcher(comment.getMessage());
Set<String> recipientsLogins = new HashSet<>(); // Set<String> recipientsLogins = new HashSet<>();
while (matcher.find()) { // while (matcher.find()) {
final String login = matcher.group(0).replace("@", ""); // final String login = matcher.group(0).replace("@", "");
recipientsLogins.add(login); // recipientsLogins.add(login);
} // }
final Set<Long> recipientsIds = personService.getAllTelegramIdByLogin(recipientsLogins); // final Set<Long> recipientsIds = personService.getAllTelegramIdByLogin(recipientsLogins);
changeService.add( // changeService.add(
CommentChange.builder() // CommentChange.builder()
.authorName(comment.getAuthor().getLogin()) // .authorName(comment.getAuthor().getLogin())
.url(comment.getUrl()) // .url(comment.getUrl())
.telegramIds(recipientsIds) // .telegramIds(recipientsIds)
.message(comment.getMessage()) // .message(comment.getMessage())
.build() // .build()
); // );
} // }
//
private void notificationNewTask(@NonNull Task task) { // private void notificationNewTask(@NonNull Task task) {
changeService.add( // changeService.add(
TaskChange.builder() // TaskChange.builder()
.authorName(task.getAuthor().getFullName()) // .authorName(task.getAuthor().getFullName())
.messageTask(task.getDescription()) // .messageTask(task.getDescription())
.type(ChangeType.NEW_TASK) // .type(ChangeType.NEW_TASK)
.url(task.getUrl()) // .url(task.getUrl())
.telegramIds(Collections.singleton(task.getPullRequest().getAuthor().getTelegramId())) // .telegramIds(Collections.singleton(task.getPullRequest().getAuthor().getTelegramId()))
.build() // .build()
); // );
} // }
//
public void scanOldComment() { // public void scanOldComment() {
@NonNull final List<Comment> comments = commentService.getAllBetweenDate( // @NonNull final List<Comment> comments = commentService.getAllBetweenDate(
LocalDateTime.now().minusDays(10), LocalDateTime.now() // LocalDateTime.now().minusDays(10), LocalDateTime.now()
); // );
for (Comment oldComment : comments) { // for (Comment oldComment : comments) {
final Optional<CommentJson> optCommentJson = Utils.urlToJson( // final Optional<CommentJson> optCommentJson = Utils.urlToJson(
oldComment.getUrl(), // oldComment.getUrl(),
bitbucketProperty.getToken(), // bitbucketProperty.getToken(),
CommentJson.class // CommentJson.class
); // );
final Comment newComment = commentService.update(conversionService.convert(oldComment, Comment.class)); // final Comment newComment = commentService.update(conversionService.convert(oldComment, Comment.class));
//
if (optCommentJson.isPresent()) { // if (optCommentJson.isPresent()) {
final CommentJson commentJson = optCommentJson.get(); // final CommentJson commentJson = optCommentJson.get();
notifyNewCommentAnswers(oldComment, newComment); // notifyNewCommentAnswers(oldComment, newComment);
} // }
} // }
} // }
//
private void notifyNewCommentAnswers(Comment oldComment, Comment newComment) { // private void notifyNewCommentAnswers(Comment oldComment, Comment newComment) {
final Set<Long> oldAnswerIds = oldComment.getAnswers(); // final Set<Long> oldAnswerIds = oldComment.getAnswers();
final Set<Long> newAnswerIds = newComment.getAnswers(); // final Set<Long> newAnswerIds = newComment.getAnswers();
if (!newAnswerIds.isEmpty()) { // if (!newAnswerIds.isEmpty()) {
final List<Comment> newAnswers = commentService.getAllById(newAnswerIds).stream() // final List<Comment> newAnswers = commentService.getAllById(newAnswerIds).stream()
.filter(comment -> !oldAnswerIds.contains(comment.getId())) // .filter(comment -> !oldAnswerIds.contains(comment.getId()))
.collect(Collectors.toList()); // .collect(Collectors.toList());
changeService.add( // changeService.add(
AnswerCommentChange.builder() // AnswerCommentChange.builder()
.telegramIds( // .telegramIds(
Collections.singleton(newComment.getAuthor().getTelegramId()) // Collections.singleton(newComment.getAuthor().getTelegramId())
) // )
.url(newComment.getPullRequest().getUrl()) // .url(newComment.getPullRequest().getUrl())
.youMessage(newComment.getMessage()) // .youMessage(newComment.getMessage())
.answers( // .answers(
newAnswers.stream() // newAnswers.stream()
.map(comment -> Answer.of(comment.getAuthor().getFullName(), comment.getMessage())) // .map(comment -> Answer.of(comment.getAuthor().getFullName(), comment.getMessage()))
.collect(Collectors.toList()) // .collect(Collectors.toList())
) // )
.build() // .build()
); // );
} // }
} // }
} }

View File

@ -1,49 +1,15 @@
package org.sadtech.bot.bitbucketbot.service.parser; package org.sadtech.bot.bitbucketbot.service.parser;
import lombok.RequiredArgsConstructor; /**
import org.sadtech.bot.bitbucketbot.config.properties.BitbucketProperty; * // TODO: 06.09.2020 Добавить описание.
import org.sadtech.bot.bitbucketbot.domain.entity.Person; *
import org.sadtech.bot.bitbucketbot.dto.bitbucket.UserJson; * @author upagge 06.09.2020
import org.sadtech.bot.bitbucketbot.dto.bitbucket.sheet.UserSheetJson; */
import org.sadtech.bot.bitbucketbot.service.PersonService; public interface PersonParser {
import org.sadtech.bot.bitbucketbot.service.Utils;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Service;
import java.util.List; /**
import java.util.Optional; * Извлечение новых пользователей SCV.
import java.util.Set; */
import java.util.stream.Collectors; void scanNewPerson();
@Service
@RequiredArgsConstructor
public class PersonParser {
private final PersonService personService;
private final ConversionService conversionService;
private final BitbucketProperty bitbucketProperty;
public void scanNewPerson() {
Optional<UserSheetJson> sheetJson = Utils.urlToJson(bitbucketProperty.getUrlUsers(), bitbucketProperty.getToken(), UserSheetJson.class);
while (sheetJson.isPresent() && sheetJson.get().hasContent()) {
final UserSheetJson sheetUsers = sheetJson.get();
final List<UserJson> users = sheetUsers.getValues();
final Set<String> logins = users.stream().map(UserJson::getName).collect(Collectors.toSet());
final Set<String> existsLogins = personService.existsByLogin(logins);
final Set<Person> newUsers = users.stream()
.filter(userJson -> !existsLogins.contains(userJson.getName()))
.map(userJson -> conversionService.convert(userJson, Person.class))
.collect(Collectors.toSet());
if (!newUsers.isEmpty()) {
personService.createAll(newUsers);
}
if (sheetUsers.getNextPageStart() != null) {
sheetJson = Utils.urlToJson(bitbucketProperty.getUrlUsers() + sheetUsers.getNextPageStart(), bitbucketProperty.getToken(), UserSheetJson.class);
} else {
break;
}
}
}
} }

View File

@ -1,128 +1,20 @@
package org.sadtech.bot.bitbucketbot.service.parser; package org.sadtech.bot.bitbucketbot.service.parser;
import lombok.NonNull; /**
import lombok.RequiredArgsConstructor; * // TODO: 06.09.2020 Добавить описание.
import lombok.extern.slf4j.Slf4j; *
import org.sadtech.bot.bitbucketbot.config.properties.BitbucketProperty; * @author upagge 06.09.2020
import org.sadtech.bot.bitbucketbot.domain.IdAndStatusPr; */
import org.sadtech.bot.bitbucketbot.domain.PullRequestStatus; public interface PullRequestParser {
import org.sadtech.bot.bitbucketbot.domain.entity.Person;
import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest;
import org.sadtech.bot.bitbucketbot.domain.filter.PullRequestFilter;
import org.sadtech.bot.bitbucketbot.dto.bitbucket.PullRequestJson;
import org.sadtech.bot.bitbucketbot.dto.bitbucket.sheet.PullRequestSheetJson;
import org.sadtech.bot.bitbucketbot.service.PersonService;
import org.sadtech.bot.bitbucketbot.service.PullRequestsService;
import org.sadtech.bot.bitbucketbot.service.Utils;
import org.sadtech.bot.bitbucketbot.utils.Pair;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Service;
import java.util.Arrays; /**
import java.util.HashSet; * Проверка старых ПР на изменение.
import java.util.List; */
import java.util.Optional; void parsingOldPullRequest();
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.sadtech.bot.bitbucketbot.domain.PullRequestStatus.DECLINED; /**
import static org.sadtech.bot.bitbucketbot.domain.PullRequestStatus.MERGED; * Извлекает новые ПР.
import static org.sadtech.bot.bitbucketbot.domain.PullRequestStatus.OPEN; */
void parsingNewPullRequest();
@Slf4j
@Service
@RequiredArgsConstructor
public class PullRequestParser {
private static final Set<PullRequestStatus> STATUSES = Stream.of(MERGED, OPEN, DECLINED).collect(Collectors.toSet());
private final PullRequestsService pullRequestsService;
private final PersonService personService;
private final ConversionService conversionService;
private final BitbucketProperty bitbucketProperty;
public void parsingOldPullRequest() {
final Set<Long> existsId = pullRequestsService.getAllId(STATUSES).stream()
.map(IdAndStatusPr::getId)
.collect(Collectors.toSet());
final Set<Long> openId = parsingPullRequest(bitbucketProperty.getUrlPullRequestOpen());
final Set<Long> closeId = parsingPullRequest(bitbucketProperty.getUrlPullRequestClose());
final Set<Long> newNotExistsId = existsId.stream()
.filter(id -> !openId.contains(id) && !closeId.contains(id))
.collect(Collectors.toSet());
log.info("Открыты: " + Arrays.toString(openId.toArray()));
log.info("Закрыты: " + Arrays.toString(closeId.toArray()));
log.info("Не найдены: " + Arrays.toString(newNotExistsId.toArray()));
if (!newNotExistsId.isEmpty()) {
pullRequestsService.deleteAllById(newNotExistsId);
}
}
private Set<Long> parsingPullRequest(@NonNull String url) {
final List<Person> users = personService.getAllRegister();
final Set<Long> ids = new HashSet<>();
for (Person user : users) {
Optional<PullRequestSheetJson> sheetJson = Utils.urlToJson(url, user.getToken(), PullRequestSheetJson.class);
while (sheetJson.isPresent() && sheetJson.get().hasContent()) {
final PullRequestSheetJson jsonSheet = sheetJson.get();
final List<PullRequest> existsPr = getExistsPr(jsonSheet.getValues());
ids.addAll(
pullRequestsService.updateAll(existsPr).stream()
.map(PullRequest::getId)
.collect(Collectors.toSet())
);
if (jsonSheet.getNextPageStart() != null) {
sheetJson = Utils.urlToJson(url + jsonSheet.getNextPageStart(), bitbucketProperty.getToken(), PullRequestSheetJson.class);
} else {
break;
}
}
}
return ids;
}
private List<PullRequest> getExistsPr(@NonNull List<PullRequestJson> pullRequestJsons) {
return pullRequestJsons.stream()
.map(json -> pullRequestsService.getByFilterQuery(bitbucketIdAndPullRequestId(json)))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
}
private PullRequestFilter bitbucketIdAndPullRequestId(PullRequestJson json) {
return PullRequestFilter.builder()
.bitbucketId(json.getId())
.bitbucketRepositoryId(json.getFromRef().getRepository().getId())
.build();
}
public void parsingNewPullRequest() {
final List<Person> users = personService.getAllRegister();
for (Person user : users) {
Optional<PullRequestSheetJson> sheetJson = Utils.urlToJson(bitbucketProperty.getUrlPullRequestOpen(), user.getToken(), PullRequestSheetJson.class);
while (sheetJson.isPresent() && sheetJson.get().hasContent()) {
final PullRequestSheetJson pullRequestBitbucketSheet = sheetJson.get();
final List<PullRequest> newPullRequest = pullRequestBitbucketSheet.getValues().stream()
.collect(Collectors.toMap(pullRequestJson -> new Pair<>(pullRequestJson.getId(), pullRequestJson.getFromRef().getRepository().getId()), pullRequestJson -> pullRequestJson))
.values()
.stream()
.filter(pullRequestJson -> !pullRequestsService.existsByFilterQuery(bitbucketIdAndPullRequestId(pullRequestJson)))
.map(pullRequestJson -> conversionService.convert(pullRequestJson, PullRequest.class))
.collect(Collectors.toList());
pullRequestsService.createAll(newPullRequest);
if (pullRequestBitbucketSheet.getNextPageStart() != null) {
sheetJson = Utils.urlToJson(bitbucketProperty.getUrlPullRequestOpen() + pullRequestBitbucketSheet.getNextPageStart(), bitbucketProperty.getToken(), PullRequestSheetJson.class);
} else {
break;
}
}
}
}
} }

View File

@ -1,84 +0,0 @@
package org.sadtech.bot.bitbucketbot.utils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import org.sadtech.bot.bitbucketbot.domain.ReviewerStatus;
import org.sadtech.bot.bitbucketbot.domain.change.Change;
import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.NewPrChange;
import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.ReviewersPrChange;
import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.UpdatePrChange;
import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest;
import org.sadtech.bot.bitbucketbot.domain.entity.Reviewer;
import org.sadtech.bot.bitbucketbot.domain.util.ReviewerChange;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ChangeGenerator {
public static NewPrChange create(@NonNull PullRequest newPullRequest) {
return NewPrChange.builder()
.author(newPullRequest.getAuthor().getFullName())
.description(newPullRequest.getDescription())
.title(newPullRequest.getTitle())
.url(newPullRequest.getUrl())
.telegramIds(
newPullRequest.getReviewers().stream()
.map(reviewer -> reviewer.getUser().getTelegramId())
.collect(Collectors.toSet())
)
.build();
}
public static UpdatePrChange createUpdatePr(@NonNull PullRequest oldPullRequest, @NonNull PullRequest newPullRequest) {
return UpdatePrChange.builder()
.author(oldPullRequest.getAuthor().getFullName())
.name(newPullRequest.getAuthor().getFullName())
.telegramIds(
newPullRequest.getReviewers().stream()
.map(reviewer -> reviewer.getUser().getTelegramId())
.collect(Collectors.toSet())
)
.url(newPullRequest.getUrl())
.build();
}
public static Change createReviewersPr(@NonNull PullRequest oldPullRequest, @NonNull PullRequest newPullRequest) {
final Map<Long, Reviewer> oldReviewers = oldPullRequest.getReviewers().stream()
.collect(Collectors.toMap(Reviewer::getId, reviewer -> reviewer));
final Map<Long, Reviewer> newReviewers = newPullRequest.getReviewers().stream()
.collect(Collectors.toMap(Reviewer::getId, reviewer -> reviewer));
final List<ReviewerChange> reviewerChanges = new ArrayList<>();
for (Reviewer newReviewer : newReviewers.values()) {
if (oldReviewers.containsKey(newReviewer.getId())) {
final Reviewer oldReviewer = oldReviewers.get(newReviewer.getId());
final ReviewerStatus oldStatus = oldReviewer.getStatus();
final ReviewerStatus newStatus = newReviewer.getStatus();
if (!oldStatus.equals(newStatus)) {
reviewerChanges.add(ReviewerChange.ofOld(oldReviewer.getUser().getFullName(), oldStatus, newStatus));
}
} else {
reviewerChanges.add(ReviewerChange.ofNew(newReviewer.getUser().getFullName(), newReviewer.getStatus()));
}
}
final Set<Long> oldIds = oldReviewers.keySet();
oldIds.removeAll(newReviewers.keySet());
reviewerChanges.addAll(
oldReviewers.entrySet().stream()
.filter(e -> oldIds.contains(e.getKey()))
.map(e -> ReviewerChange.ofDeleted(e.getValue().getUser().getFullName()))
.collect(Collectors.toList())
);
return ReviewersPrChange.builder()
.title(newPullRequest.getTitle())
.url(newPullRequest.getUrl())
.telegramId(newPullRequest.getAuthor().getTelegramId())
.reviewerChanges(reviewerChanges)
.build();
}
}

View File

@ -184,14 +184,14 @@ public class Message {
pullRequestsNeedWork.stream() pullRequestsNeedWork.stream()
.limit(3) .limit(3)
.forEach( .forEach(
pullRequest -> message.append("-- ").append(link(pullRequest.getName(), pullRequest.getUrl())).append(Smile.BR) pullRequest -> message.append("-- ").append(link(pullRequest.getTitle(), pullRequest.getUrl())).append(Smile.BR)
); );
return message.toString(); return message.toString();
} }
private static String topPr(PullRequest pullRequest) { private static String topPr(PullRequest pullRequest) {
return Smile.statusPr(pullRequest.getUpdateDate()) + " " + return Smile.statusPr(pullRequest.getUpdateDate()) + " " +
link(pullRequest.getName(), pullRequest.getUrl()) + link(pullRequest.getTitle(), pullRequest.getUrl()) +
Smile.BR; Smile.BR;
} }

View File

@ -3,6 +3,6 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<include file="liquibase/v.2.0.0/cumulative.xml"/> <include file="liquibase/v.2.0.0/2020-09-06-cumulative.xml"/>
</databaseChangeLog> </databaseChangeLog>

View File

@ -3,7 +3,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<changeSet id="create-table-person" author="upagge"> <changeSet id="2020-09-06-create-table-person" author="upagge">
<createTable tableName="person"> <createTable tableName="person">
<column name="login" type="varchar(64)"> <column name="login" type="varchar(64)">
<constraints nullable="false" primaryKey="true"/> <constraints nullable="false" primaryKey="true"/>
@ -18,7 +18,7 @@
</createTable> </createTable>
</changeSet> </changeSet>
<changeSet id="create-table-pull-request" author="upagge"> <changeSet id="2020-09-06-create-table-pull-request" author="upagge">
<createTable tableName="pull_request"> <createTable tableName="pull_request">
<column name="id" type="integer" autoIncrement="true"> <column name="id" type="integer" autoIncrement="true">
<constraints nullable="false" primaryKey="true"/> <constraints nullable="false" primaryKey="true"/>
@ -60,11 +60,11 @@
</column> </column>
</createTable> </createTable>
<addUniqueConstraint tableName="pull_request" columnNames="bitbucket_pr_id, repository_id"/> <addUniqueConstraint tableName="pull_request" columnNames="bitbucket_id, repository_id"/>
</changeSet> </changeSet>
<changeSet id="create-table-pull-request-reviewer" author="upagge"> <changeSet id="2020-09-06-create-table-pull-request-reviewer" author="upagge">
<createTable tableName="pull_request_reviewer"> <createTable tableName="pull_request_reviewer">
<column name="id" type="integer" autoIncrement="true"> <column name="id" type="integer" autoIncrement="true">
<constraints nullable="false" primaryKey="true"/> <constraints nullable="false" primaryKey="true"/>
@ -83,16 +83,16 @@
</column> </column>
</createTable> </createTable>
<addUniqueConstraint tableName="reviewer" columnNames="pull_request_id, user_login"/> <addUniqueConstraint tableName="pull_request_reviewer" columnNames="pull_request_id, user_login"/>
</changeSet> </changeSet>
<changeSet id="create-table-comments" author="upagge"> <changeSet id="2020-09-06-create-table-comments" author="upagge">
<createTable tableName="pull_request_comment"> <createTable tableName="pull_request_comment">
<column name="id" type="int"> <column name="id" type="int">
<constraints primaryKey="true"/> <constraints primaryKey="true"/>
</column> </column>
<column name="url" type="varchar(300)"/> <column name="url" type="varchar(300)"/>
<column name="author_login" type="integer"> <column name="author_login" type="varchar(64)">
<constraints nullable="false" foreignKeyName="pull_request_task_author_login_person_login" <constraints nullable="false" foreignKeyName="pull_request_task_author_login_person_login"
references="person(login)" deleteCascade="true"/> references="person(login)" deleteCascade="true"/>
</column> </column>
@ -110,14 +110,16 @@
</createTable> </createTable>
</changeSet> </changeSet>
<changeSet id="create-table-comment-tree" author="upagge"> <changeSet id="2020-09-06-create-table-comment-tree" author="upagge">
<createTable tableName="comment_tree"> <createTable tableName="comment_tree">
<column name="parent_id" type="int"> <column name="parent_id" type="int">
<constraints foreignKeyName="fk_parent_id_from_comment_id" references="comment(id)" nullable="false" <constraints foreignKeyName="comment_tree_parent_id_pull_request_comment_id"
references="pull_request_comment(id)" nullable="false"
deleteCascade="true"/> deleteCascade="true"/>
</column> </column>
<column name="child_id" type="int"> <column name="child_id" type="int">
<constraints foreignKeyName="fk_child_id_from_comment_id" references="comment(id)" nullable="false" <constraints foreignKeyName="comment_tree_child_id_pull_request_comment_id"
references="pull_request_comment(id)" nullable="false"
deleteCascade="true"/> deleteCascade="true"/>
</column> </column>
</createTable> </createTable>
@ -125,7 +127,7 @@
<addPrimaryKey tableName="comment_tree" columnNames="parent_id, child_id"/> <addPrimaryKey tableName="comment_tree" columnNames="parent_id, child_id"/>
</changeSet> </changeSet>
<changeSet id="create-table-task" author="upagge"> <changeSet id="2020-09-06-create-table-task" author="upagge">
<createTable tableName="pull_request_task"> <createTable tableName="pull_request_task">
<column name="id" type="integer" autoIncrement="true"> <column name="id" type="integer" autoIncrement="true">
<constraints nullable="false" primaryKey="true"/> <constraints nullable="false" primaryKey="true"/>

View File

@ -3,6 +3,6 @@
xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<include file="liquibase/v.2.0.0/create-table.xml"/> <include file="liquibase/v.2.0.0/2020-09-06-create-table.xml"/>
</databaseChangeLog> </databaseChangeLog>