From a6dce07b3f5516ea640ce69646b14f3e319a47b7 Mon Sep 17 00:00:00 2001 From: Struchkov Mark Date: Mon, 5 Dec 2022 22:25:59 +0300 Subject: [PATCH] =?UTF-8?q?=D0=91=D0=BE=D0=BB=D1=8C=D1=88=D0=BE=D0=B9=20?= =?UTF-8?q?=D1=80=D0=B5=D1=84=D0=B0=D0=BA=D1=82=D0=BE=D1=80=D0=B8=D0=BD?= =?UTF-8?q?=D0=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../context/domain/AssigneeChanged.java | 40 +++++++ .../context/domain/ReviewerChanged.java | 38 ++++++ .../context/domain/entity/Discussion.java | 7 +- .../context/domain/entity/MergeRequest.java | 7 +- .../gitlab/context/domain/entity/Note.java | 10 +- .../context/service/DiscussionService.java | 2 + .../service/impl/DiscussionServiceImpl.java | 87 +++++++++----- .../impl/MergeRequestsServiceImpl.java | 96 ++++++++++----- .../core/service/parser/DiscussionParser.java | 109 +++++++++++++++--- bot-data/pom.xml | 4 +- .../data/impl/DiscussionRepositoryImpl.java | 2 + gitlab-app/src/main/resources/application.yml | 2 +- 12 files changed, 318 insertions(+), 86 deletions(-) create mode 100644 bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/AssigneeChanged.java create mode 100644 bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/ReviewerChanged.java diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/AssigneeChanged.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/AssigneeChanged.java new file mode 100644 index 0000000..12df35c --- /dev/null +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/AssigneeChanged.java @@ -0,0 +1,40 @@ +package dev.struchkov.bot.gitlab.context.domain; + +import dev.struchkov.bot.gitlab.context.domain.entity.Person; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import static dev.struchkov.haiti.utils.Checker.checkNotNull; +import static dev.struchkov.haiti.utils.Checker.checkNull; + +@Getter +@RequiredArgsConstructor +public enum AssigneeChanged { + + BECOME(true), + DELETED(true), + NOT_AFFECT_USER(true), + NOT_CHANGED(false); + + private final boolean changed; + + public static AssigneeChanged valueOf(Long gitlabUserId, Person oldAssignee, Person newAssignee) { + if (checkNull(oldAssignee) && checkNotNull(newAssignee) && gitlabUserId.equals(newAssignee.getId())) { + return AssigneeChanged.BECOME; + } + if (checkNotNull(oldAssignee) && checkNull(newAssignee) && gitlabUserId.equals(oldAssignee.getId())) { + return AssigneeChanged.DELETED; + } + if (checkNotNull(oldAssignee) && checkNotNull(newAssignee) && !oldAssignee.getId().equals(newAssignee.getId())) { + if (gitlabUserId.equals(oldAssignee.getId())) { + return AssigneeChanged.DELETED; + } + if (gitlabUserId.equals(newAssignee.getId())) { + return AssigneeChanged.BECOME; + } + return AssigneeChanged.NOT_AFFECT_USER; + } + return AssigneeChanged.NOT_CHANGED; + } + +} \ No newline at end of file diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/ReviewerChanged.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/ReviewerChanged.java new file mode 100644 index 0000000..4dd38b2 --- /dev/null +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/ReviewerChanged.java @@ -0,0 +1,38 @@ +package dev.struchkov.bot.gitlab.context.domain; + +import dev.struchkov.bot.gitlab.context.domain.entity.Person; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Getter +@RequiredArgsConstructor +public enum ReviewerChanged { + + BECOME(true), + DELETED(true), + NOT_AFFECT_USER(true), + NOT_CHANGED(false); + + private final boolean changed; + + public static ReviewerChanged valueOf(Long gitlabUserId, List oldReviewers, List newReviewers) { + final Map oldMap = oldReviewers.stream().collect(Collectors.toMap(Person::getId, p -> p)); + final Map newMap = newReviewers.stream().collect(Collectors.toMap(Person::getId, p -> p)); + + if (!oldMap.keySet().equals(newMap.keySet())) { + if (oldMap.containsKey(gitlabUserId) && !newMap.containsKey(gitlabUserId)) { + return ReviewerChanged.DELETED; + } + if (!oldMap.containsKey(gitlabUserId) && newMap.containsKey(gitlabUserId)) { + return ReviewerChanged.BECOME; + } + return ReviewerChanged.NOT_AFFECT_USER; + } + return ReviewerChanged.NOT_CHANGED; + } + +} \ No newline at end of file diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/Discussion.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/Discussion.java index 2887848..4ca9352 100644 --- a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/Discussion.java +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/Discussion.java @@ -30,14 +30,14 @@ public class Discussion { @Column(name = "id") private String id; - @ManyToOne + @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}) @JoinColumn(name = "responsible_id") private Person responsible; @Column(name = "resolved") private Boolean resolved; - @ManyToOne() + @ManyToOne @JoinTable( name = "discussion_merge_request", joinColumns = @JoinColumn(name = "discussion_id"), @@ -50,7 +50,8 @@ public class Discussion { fetch = FetchType.EAGER, cascade = { CascadeType.PERSIST, - CascadeType.MERGE + CascadeType.MERGE, + CascadeType.REFRESH } ) private List notes; diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/MergeRequest.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/MergeRequest.java index 8ec97e5..5734e1e 100644 --- a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/MergeRequest.java +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/MergeRequest.java @@ -73,18 +73,17 @@ public class MergeRequest { @Column(name = "conflict") private boolean conflict; - @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.MERGE}) + @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @JoinColumn(name = "author_id") private Person author; - @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.MERGE}) + @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @JoinColumn(name = "assignee_id") private Person assignee; @OneToMany( fetch = FetchType.LAZY, - cascade = {CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.MERGE}, - orphanRemoval = true + cascade = {CascadeType.PERSIST, CascadeType.MERGE} ) @JoinTable( name = "merge_request_reviewer", diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/Note.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/Note.java index 504d3d0..608c2a8 100644 --- a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/Note.java +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/Note.java @@ -12,6 +12,9 @@ import javax.persistence.ManyToOne; import javax.persistence.Table; import java.time.LocalDateTime; +import static javax.persistence.CascadeType.MERGE; +import static javax.persistence.CascadeType.PERSIST; + @Getter @Setter @Entity @@ -20,7 +23,8 @@ import java.time.LocalDateTime; public class Note { @Id - @Column + @Column(name = "id") + @EqualsAndHashCode.Include private Long id; @Column(name = "type") @@ -35,7 +39,7 @@ public class Note { @Column(name = "updated_date") private LocalDateTime updated; - @ManyToOne + @ManyToOne(cascade = {PERSIST, MERGE}) @JoinColumn(name = "author_id") private Person author; @@ -57,7 +61,7 @@ public class Note { @Column(name = "resolved") private Boolean resolved; - @ManyToOne + @ManyToOne(cascade = {PERSIST, MERGE}) @JoinColumn(name = "resolved_id") private Person resolvedBy; diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/service/DiscussionService.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/service/DiscussionService.java index 06663eb..4765d15 100644 --- a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/service/DiscussionService.java +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/service/DiscussionService.java @@ -18,6 +18,8 @@ public interface DiscussionService { Discussion update(@NonNull Discussion discussion); + List updateAll(@NonNull List discussions); + /** * Метод отправляющий коментарий в дискуссию. * diff --git a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/DiscussionServiceImpl.java b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/DiscussionServiceImpl.java index 863b50b..e8241c7 100644 --- a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/DiscussionServiceImpl.java +++ b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/DiscussionServiceImpl.java @@ -5,13 +5,13 @@ import dev.struchkov.bot.gitlab.context.domain.PersonInformation; import dev.struchkov.bot.gitlab.context.domain.entity.Discussion; import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequest; import dev.struchkov.bot.gitlab.context.domain.entity.Note; +import dev.struchkov.bot.gitlab.context.domain.entity.Person; import dev.struchkov.bot.gitlab.context.domain.notify.comment.CommentNotify; import dev.struchkov.bot.gitlab.context.domain.notify.task.TaskCloseNotify; import dev.struchkov.bot.gitlab.context.domain.notify.task.TaskNewNotify; import dev.struchkov.bot.gitlab.context.repository.DiscussionRepository; import dev.struchkov.bot.gitlab.context.service.DiscussionService; import dev.struchkov.bot.gitlab.context.service.NotifyService; -import dev.struchkov.bot.gitlab.context.service.PersonService; import dev.struchkov.bot.gitlab.core.config.properties.GitlabProperty; import dev.struchkov.bot.gitlab.core.config.properties.PersonProperty; import dev.struchkov.bot.gitlab.core.utils.StringUtils; @@ -25,6 +25,7 @@ import okhttp3.RequestBody; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.io.IOException; import java.text.MessageFormat; @@ -38,6 +39,7 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException; +import static dev.struchkov.haiti.utils.Checker.checkNotNull; import static java.lang.Boolean.FALSE; /** @@ -52,7 +54,6 @@ public class DiscussionServiceImpl implements DiscussionService { protected static final Pattern PATTERN = Pattern.compile("@[\\w]+"); - private final PersonService personService; private final DiscussionRepository repository; private final PersonInformation personInformation; @@ -62,14 +63,18 @@ public class DiscussionServiceImpl implements DiscussionService { private final NotifyService notifyService; @Override + @Transactional public Discussion create(@NonNull Discussion discussion) { - discussion.getNotes().forEach(note -> personService.create(note.getAuthor())); - discussion.getNotes().forEach(this::notificationPersonal); - discussion.getNotes().forEach(note -> notifyNewNote(note, discussion)); + final List notes = discussion.getNotes(); + + notes.forEach(this::notificationPersonal); + notes.forEach(note -> notifyNewNote(note, discussion)); final boolean resolved = discussion.getNotes().stream() .allMatch(note -> note.isResolvable() && note.getResolved()); + discussion.setResolved(resolved); + return repository.save(discussion); } @@ -89,10 +94,10 @@ public class DiscussionServiceImpl implements DiscussionService { } private boolean isNeedNotifyNewNote(Note note, Discussion discussion) { - final Long personId = personInformation.getId(); + final Long gitlabUserId = personInformation.getId(); return note.isResolvable() // Тип комментария требует решения (Задачи) - && personId.equals(discussion.getResponsible().getId()) // Создатель дискуссии пользователь приложения - && !personId.equals(note.getAuthor().getId()) // Создатель комментария не пользователь системы + && gitlabUserId.equals(discussion.getResponsible().getId()) // Создатель дискуссии пользователь приложения + && !gitlabUserId.equals(note.getAuthor().getId()) // Создатель комментария не пользователь системы && FALSE.equals(note.getResolved()); // Комментарий не отмечен как решенный } @@ -100,40 +105,68 @@ public class DiscussionServiceImpl implements DiscussionService { public Discussion update(@NonNull Discussion discussion) { final Discussion oldDiscussion = repository.findById(discussion.getId()) .orElseThrow(notFoundException("Дискуссия не найдена")); - final Map idAndNoteMap = oldDiscussion - .getNotes().stream() - .collect(Collectors.toMap(Note::getId, note -> note)); - // Пользователь участвовал в обсуждении - final boolean userParticipatedInDiscussion = discussion.getNotes().stream() - .anyMatch(note -> personInformation.getId().equals(note.getAuthor().getId())); - - discussion.setMergeRequest(oldDiscussion.getMergeRequest()); discussion.setResponsible(oldDiscussion.getResponsible()); - discussion.getNotes().forEach(note -> updateNote(note, idAndNoteMap, userParticipatedInDiscussion)); + discussion.setMergeRequest(oldDiscussion.getMergeRequest()); + + final Person responsiblePerson = discussion.getResponsible(); + if (checkNotNull(responsiblePerson)) { + for (Note note : discussion.getNotes()) { + if (responsiblePerson.getId().equals(note.getAuthor().getId())) { + note.setAuthor(responsiblePerson); + } + final Person resolvedBy = note.getResolvedBy(); + if (checkNotNull(resolvedBy)) { + if (responsiblePerson.getId().equals(resolvedBy.getId())) { + note.setResolvedBy(responsiblePerson); + } + } + } + } + notifyUpdateNote(oldDiscussion, discussion); final boolean resolved = discussion.getNotes().stream() .allMatch(note -> note.isResolvable() && note.getResolved()); + discussion.setResolved(resolved); return repository.save(discussion); } - private void updateNote(Note note, Map noteMap, boolean inDiscussion) { - if (noteMap.containsKey(note.getId())) { - final Note oldNote = noteMap.get(note.getId()); + @Override + public List updateAll(@NonNull List discussions) { + return discussions.stream() + .map(this::update) + .collect(Collectors.toList()); + } - if (note.isResolvable()) { - updateTask(note, oldNote); - } + private void notifyUpdateNote(Discussion oldDiscussion, Discussion discussion) { + final Map noteMap = oldDiscussion + .getNotes().stream() + .collect(Collectors.toMap(Note::getId, n -> n)); + + // Пользователь участвовал в обсуждении + final boolean userParticipatedInDiscussion = oldDiscussion.getNotes().stream() + .anyMatch(note -> personInformation.getId().equals(note.getAuthor().getId())); + + for (Note newNote : discussion.getNotes()) { + final Long newNoteId = newNote.getId(); + if (noteMap.containsKey(newNoteId)) { + final Note oldNote = noteMap.get(newNoteId); + + if (newNote.isResolvable()) { + updateTask(newNote, oldNote); + } - } else { - if (inDiscussion) { - notifyNewAnswer(note); } else { - notificationPersonal(note); + if (userParticipatedInDiscussion) { + notifyNewAnswer(newNote); + } else { + notificationPersonal(newNote); + } } } + } private void notifyNewAnswer(Note note) { diff --git a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/MergeRequestsServiceImpl.java b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/MergeRequestsServiceImpl.java index e39ed38..0fb8cf5 100644 --- a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/MergeRequestsServiceImpl.java +++ b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/MergeRequestsServiceImpl.java @@ -1,9 +1,11 @@ package dev.struchkov.bot.gitlab.core.service.impl; +import dev.struchkov.bot.gitlab.context.domain.AssigneeChanged; import dev.struchkov.bot.gitlab.context.domain.ExistContainer; import dev.struchkov.bot.gitlab.context.domain.IdAndStatusPr; import dev.struchkov.bot.gitlab.context.domain.MergeRequestState; import dev.struchkov.bot.gitlab.context.domain.PersonInformation; +import dev.struchkov.bot.gitlab.context.domain.ReviewerChanged; import dev.struchkov.bot.gitlab.context.domain.entity.Discussion; import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequest; import dev.struchkov.bot.gitlab.context.domain.entity.Person; @@ -117,24 +119,29 @@ public class MergeRequestsServiceImpl implements MergeRequestsService { if (isUserInReviewers) { final String projectName = projectService.getByIdOrThrow(savedMergeRequest.getProjectId()).getName(); if (!savedMergeRequest.isConflict()) { - notifyService.send( - NewPrNotify.builder() - .projectName(projectName) - .labels(savedMergeRequest.getLabels()) - .author(savedMergeRequest.getAuthor().getName()) - .description(savedMergeRequest.getDescription()) - .title(savedMergeRequest.getTitle()) - .url(savedMergeRequest.getWebUrl()) - .targetBranch(savedMergeRequest.getTargetBranch()) - .sourceBranch(savedMergeRequest.getSourceBranch()) - .build() - ); + sendNotifyAboutNewMr(savedMergeRequest, projectName); } } } } + private void sendNotifyAboutNewMr(MergeRequest savedMergeRequest, String projectName) { + notifyService.send( + NewPrNotify.builder() + .projectName(projectName) + .labels(savedMergeRequest.getLabels()) + .author(savedMergeRequest.getAuthor().getName()) + .description(savedMergeRequest.getDescription()) + .title(savedMergeRequest.getTitle()) + .url(savedMergeRequest.getWebUrl()) + .targetBranch(savedMergeRequest.getTargetBranch()) + .sourceBranch(savedMergeRequest.getSourceBranch()) + .build() + ); + } + @Override + @Transactional public MergeRequest update(@NonNull MergeRequest mergeRequest) { final MergeRequest oldMergeRequest = repository.findById(mergeRequest.getId()) .orElseThrow(notFoundException("MergeRequest не найден")); @@ -144,24 +151,53 @@ public class MergeRequestsServiceImpl implements MergeRequestsService { mergeRequest.setNotification(oldMergeRequest.getNotification()); } - if ( + final Long gitlabUserId = personInformation.getId(); + final AssigneeChanged assigneeChanged = AssigneeChanged.valueOf(gitlabUserId, oldMergeRequest.getAssignee(), mergeRequest.getAssignee()); + final ReviewerChanged reviewerChanged = ReviewerChanged.valueOf(gitlabUserId, oldMergeRequest.getReviewers(), mergeRequest.getReviewers()); + + final boolean isChangedMr = !oldMergeRequest.getUpdatedDate().equals(mergeRequest.getUpdatedDate()) - || oldMergeRequest.isConflict() != mergeRequest.isConflict() - ) { + || oldMergeRequest.isConflict() != mergeRequest.isConflict(); + final boolean isChangedLinkedEntity = reviewerChanged.isChanged() || assigneeChanged.isChanged(); + + if (isChangedMr || isChangedLinkedEntity) { final Project project = projectService.getByIdOrThrow(mergeRequest.getProjectId()); - if (TRUE.equals(oldMergeRequest.getNotification())) { + if (TRUE.equals(notification) && isChangedMr) { notifyAboutStatus(oldMergeRequest, mergeRequest, project); notifyAboutConflict(oldMergeRequest, mergeRequest, project); - notifyUpdate(oldMergeRequest, mergeRequest, project); + notifyAboutUpdate(oldMergeRequest, mergeRequest, project); + } + + if (TRUE.equals(notification) && isChangedLinkedEntity) { + notifyReviewer(reviewerChanged, mergeRequest, project); + notifyAssignee(assigneeChanged, mergeRequest, project); } return repository.save(mergeRequest); } + return oldMergeRequest; } + + //TODO [05.12.2022|uPagge]: Добавить уведомление, если происходит удаление + private void notifyAssignee(AssigneeChanged assigneeChanged, MergeRequest mergeRequest, Project project) { + switch (assigneeChanged) { + case BECOME -> sendNotifyAboutNewMr(mergeRequest, project.getName()); + } + } + + //TODO [05.12.2022|uPagge]: Добавить уведомление, если происходит удаление ревьювера + //TODO [05.12.2022|uPagge]: Заменить тип уведомления на самостоятельный + private void notifyReviewer(ReviewerChanged reviewerChanged, MergeRequest mergeRequest, Project project) { + switch (reviewerChanged) { + case BECOME -> sendNotifyAboutNewMr(mergeRequest, project.getName()); + } + } + @Override + @Transactional public List updateAll(@NonNull List mergeRequests) { return mergeRequests.stream() .map(this::update) @@ -214,11 +250,13 @@ public class MergeRequestsServiceImpl implements MergeRequestsService { return repository.findAllByReviewerId(personId); } - private void notifyUpdate(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) { + private void notifyAboutUpdate(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) { + final Long gitlabUserId = personInformation.getId(); + if ( - !personInformation.getId().equals(mergeRequest.getAuthor().getId()) - && !oldMergeRequest.getDateLastCommit().equals(mergeRequest.getDateLastCommit()) - && !mergeRequest.isConflict() + !gitlabUserId.equals(mergeRequest.getAuthor().getId()) // Автор MR не пользователь приложения + && !oldMergeRequest.getDateLastCommit().equals(mergeRequest.getDateLastCommit()) // Изменилась дата последнего коммита + && !mergeRequest.isConflict() // MR не находится в состоянии конфликта ) { final List discussions = discussionService.getAllByMergeRequestId(oldMergeRequest.getId()) .stream() @@ -229,10 +267,10 @@ public class MergeRequestsServiceImpl implements MergeRequestsService { .filter(Discussion::getResolved) .count(); final long allYouTasks = discussions.stream() - .filter(discussion -> personInformation.getId().equals(discussion.getFirstNote().getAuthor().getId())) + .filter(discussion -> gitlabUserId.equals(discussion.getFirstNote().getAuthor().getId())) .count(); final long resolvedYouTask = discussions.stream() - .filter(discussion -> personInformation.getId().equals(discussion.getFirstNote().getAuthor().getId()) && discussion.getResolved()) + .filter(discussion -> gitlabUserId.equals(discussion.getFirstNote().getAuthor().getId()) && discussion.getResolved()) .count(); notifyService.send( UpdatePrNotify.builder() @@ -250,10 +288,11 @@ public class MergeRequestsServiceImpl implements MergeRequestsService { } protected void notifyAboutConflict(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) { + final Long gitlabUserId = personInformation.getId(); if ( - !oldMergeRequest.isConflict() - && mergeRequest.isConflict() - && personInformation.getId().equals(oldMergeRequest.getAuthor().getId()) + !oldMergeRequest.isConflict() // У старого MR не было конфликта + && mergeRequest.isConflict() // А у нового есть + && gitlabUserId.equals(oldMergeRequest.getAuthor().getId()) // и MR создан пользователем бота ) { notifyService.send( ConflictPrNotify.builder() @@ -269,9 +308,10 @@ public class MergeRequestsServiceImpl implements MergeRequestsService { protected void notifyAboutStatus(MergeRequest oldMergeRequest, MergeRequest newMergeRequest, Project project) { final MergeRequestState oldStatus = oldMergeRequest.getState(); final MergeRequestState newStatus = newMergeRequest.getState(); + final Long gitlabUserId = personInformation.getId(); if ( - !oldStatus.equals(newStatus) - && oldMergeRequest.getAuthor().getId().equals(personInformation.getId()) + !oldStatus.equals(newStatus) // статус изменился + && gitlabUserId.equals(oldMergeRequest.getAuthor().getId()) // создатель MR является пользователем бота ) { notifyService.send( StatusPrNotify.builder() diff --git a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/parser/DiscussionParser.java b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/parser/DiscussionParser.java index 346f36d..b22a778 100644 --- a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/parser/DiscussionParser.java +++ b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/parser/DiscussionParser.java @@ -4,6 +4,7 @@ import dev.struchkov.bot.gitlab.context.domain.ExistContainer; import dev.struchkov.bot.gitlab.context.domain.entity.Discussion; import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequest; import dev.struchkov.bot.gitlab.context.domain.entity.Note; +import dev.struchkov.bot.gitlab.context.domain.entity.Person; import dev.struchkov.bot.gitlab.context.service.DiscussionService; import dev.struchkov.bot.gitlab.context.service.MergeRequestsService; import dev.struchkov.bot.gitlab.core.config.properties.GitlabProperty; @@ -17,13 +18,20 @@ import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Component; import java.text.MessageFormat; +import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Consumer; import java.util.stream.Collectors; +import java.util.stream.Stream; import static dev.struchkov.bot.gitlab.core.utils.StringUtils.H_PRIVATE_TOKEN; +import static dev.struchkov.haiti.utils.Checker.checkNotEmpty; +import static dev.struchkov.haiti.utils.Checker.checkNotNull; +import static dev.struchkov.haiti.utils.Checker.checkNull; import static dev.struchkov.haiti.utils.network.HttpParse.ACCEPT; /** @@ -52,8 +60,12 @@ public class DiscussionParser { Page mergeRequestSheet = mergeRequestsService.getAll(PageRequest.of(page, COUNT)); while (mergeRequestSheet.hasContent()) { - mergeRequestSheet.getContent() - .forEach(this::processingMergeRequest); + final List mergeRequests = mergeRequestSheet.getContent(); + + for (MergeRequest mergeRequest : mergeRequests) { + processingMergeRequest(mergeRequest); + } + mergeRequestSheet = mergeRequestsService.getAll(PageRequest.of(++page, COUNT)); } } @@ -86,9 +98,52 @@ public class DiscussionParser { discussion.getNotes().forEach(createNoteLink(mergeRequest)); return discussion; }) - .filter(discussion -> discussion.getNotes() != null && !discussion.getNotes().isEmpty()) + // Фильтрация специально стоит после map(). Таким образом отбрасываются системные уведомления + .filter(discussion -> checkNotEmpty(discussion.getNotes())) .toList(); - discussionService.createAll(newDiscussions); + + if (checkNotEmpty(newDiscussions)) { + personMapping(newDiscussions); + discussionService.createAll(newDiscussions); + } + + } + } + + private void personMapping(List newDiscussions) { + final Stream firstStream = Stream.concat( + newDiscussions.stream() + .flatMap(discussion -> discussion.getNotes().stream()) + .map(Note::getResolvedBy) + .filter(Objects::nonNull), + newDiscussions.stream() + .flatMap(discussion -> discussion.getNotes().stream()) + .map(Note::getAuthor) + .filter(Objects::nonNull) + ); + + final Map personMap = Stream.concat( + firstStream, + newDiscussions.stream() + .map(Discussion::getResponsible) + .filter(Objects::nonNull) + ).distinct() + .collect(Collectors.toMap(Person::getId, p -> p)); + + for (Discussion newDiscussion : newDiscussions) { + final Person responsible = newDiscussion.getResponsible(); + if (checkNotNull(responsible)) { + newDiscussion.setResponsible(personMap.get(responsible.getId())); + } + + for (Note note : newDiscussion.getNotes()) { + note.setAuthor(personMap.get(note.getAuthor().getId())); + + final Person resolvedBy = note.getResolvedBy(); + if (checkNotNull(resolvedBy)) { + note.setResolvedBy(personMap.get(resolvedBy.getId())); + } + } } } @@ -97,33 +152,47 @@ public class DiscussionParser { */ public void scanOldDiscussions() { int page = 0; - Page discussionSheet = discussionService.getAll(PageRequest.of(page, COUNT)); + Page discussionPage = discussionService.getAll(PageRequest.of(page, COUNT)); - while (discussionSheet.hasContent()) { - final List discussions = discussionSheet.getContent(); + while (discussionPage.hasContent()) { + final List discussions = discussionPage.getContent(); + // Удаляем обсуждения, которые потеряли свои MR + //TODO [05.12.2022|uPagge]: Проверить целесообразность этого действия + discussions.stream() + .filter(discussion -> checkNull(discussion.getMergeRequest())) + .map(Discussion::getId) + .forEach(discussionService::deleteById); + + final List newDiscussions = new ArrayList<>(); for (Discussion discussion : discussions) { - if (discussion.getMergeRequest() != null) { - final Optional optNewDiscussion = HttpParse.request(createLinkOldDiscussion(discussion)) - .header(ACCEPT) - .header(H_PRIVATE_TOKEN, personProperty.getToken()) - .execute(DiscussionJson.class) + if (checkNotNull(discussion.getMergeRequest())) { + getOldDiscussionJson(discussion) .map(json -> { final Discussion newDiscussion = conversionService.convert(json, Discussion.class); newDiscussion.getNotes().forEach(createNoteLink(discussion.getMergeRequest())); return newDiscussion; - }); - optNewDiscussion.ifPresent(discussionService::update); - } else { - discussionService.deleteById(discussion.getId()); + }).ifPresent(newDiscussions::add); } } - discussionSheet = discussionService.getAll(PageRequest.of(++page, COUNT)); + if (checkNotEmpty(newDiscussions)) { + personMapping(newDiscussions); + discussionService.updateAll(newDiscussions); + } + + discussionPage = discussionService.getAll(PageRequest.of(++page, COUNT)); } } + private Optional getOldDiscussionJson(Discussion discussion) { + return HttpParse.request(createLinkOldDiscussion(discussion)) + .header(ACCEPT) + .header(H_PRIVATE_TOKEN, personProperty.getToken()) + .execute(DiscussionJson.class); + } + private String createLinkOldDiscussion(Discussion discussion) { return MessageFormat.format( gitlabProperty.getUrlOneDiscussion(), @@ -142,7 +211,11 @@ public class DiscussionParser { private Consumer createNoteLink(MergeRequest mergeRequest) { return note -> { - final String url = MessageFormat.format(gitlabProperty.getUrlNote(), mergeRequest.getWebUrl(), note.getId()); + final String url = MessageFormat.format( + gitlabProperty.getUrlNote(), + mergeRequest.getWebUrl(), + note.getId() + ); note.setWebUrl(url); }; } diff --git a/bot-data/pom.xml b/bot-data/pom.xml index d86ba85..0ce8d3b 100644 --- a/bot-data/pom.xml +++ b/bot-data/pom.xml @@ -21,8 +21,8 @@ bot-context - org.springframework.data - spring-data-jpa + org.springframework.boot + spring-boot-starter-data-jpa org.liquibase diff --git a/bot-data/src/main/java/dev/struchkov/bot/gitlab/data/impl/DiscussionRepositoryImpl.java b/bot-data/src/main/java/dev/struchkov/bot/gitlab/data/impl/DiscussionRepositoryImpl.java index 3ed56d5..2782985 100644 --- a/bot-data/src/main/java/dev/struchkov/bot/gitlab/data/impl/DiscussionRepositoryImpl.java +++ b/bot-data/src/main/java/dev/struchkov/bot/gitlab/data/impl/DiscussionRepositoryImpl.java @@ -5,6 +5,7 @@ import dev.struchkov.bot.gitlab.context.repository.DiscussionRepository; import dev.struchkov.bot.gitlab.data.jpa.DiscussionJpaRepository; import lombok.NonNull; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Repository; @@ -16,6 +17,7 @@ import java.util.Set; /** * @author upagge 11.02.2021 */ +@Slf4j @Repository @RequiredArgsConstructor public class DiscussionRepositoryImpl implements DiscussionRepository { diff --git a/gitlab-app/src/main/resources/application.yml b/gitlab-app/src/main/resources/application.yml index 4e6527a..45657eb 100644 --- a/gitlab-app/src/main/resources/application.yml +++ b/gitlab-app/src/main/resources/application.yml @@ -7,7 +7,7 @@ spring: liquibase: change-log: classpath:liquibase/changelog.xml jpa: - show-sql: false + show-sql: true hibernate: ddl-auto: none database-platform: org.hibernate.dialect.PostgreSQLDialect