Изменение подхода к уведомлениям
This commit is contained in:
@@ -10,8 +10,12 @@ import jakarta.persistence.JoinTable;
|
|||||||
import jakarta.persistence.ManyToOne;
|
import jakarta.persistence.ManyToOne;
|
||||||
import jakarta.persistence.OneToMany;
|
import jakarta.persistence.OneToMany;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -25,7 +29,10 @@ import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
|
|||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@Entity
|
@Entity
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Builder(toBuilder = true)
|
||||||
@Table(name = "discussion")
|
@Table(name = "discussion")
|
||||||
|
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
|
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
|
||||||
public class Discussion {
|
public class Discussion {
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,12 @@ import jakarta.persistence.JoinTable;
|
|||||||
import jakarta.persistence.ManyToOne;
|
import jakarta.persistence.ManyToOne;
|
||||||
import jakarta.persistence.OneToMany;
|
import jakarta.persistence.OneToMany;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@@ -35,9 +39,12 @@ import java.util.Set;
|
|||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@Entity
|
@Entity
|
||||||
@FieldNames(mode = {Mode.TABLE, Mode.SIMPLE})
|
@NoArgsConstructor
|
||||||
|
@Builder(toBuilder = true)
|
||||||
@Table(name = "merge_request")
|
@Table(name = "merge_request")
|
||||||
|
@FieldNames(mode = {Mode.TABLE, Mode.SIMPLE})
|
||||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
|
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
|
||||||
|
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
public class MergeRequest {
|
public class MergeRequest {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@@ -95,17 +102,6 @@ public class MergeRequest {
|
|||||||
)
|
)
|
||||||
private List<Person> reviewers = new ArrayList<>();
|
private List<Person> reviewers = new ArrayList<>();
|
||||||
|
|
||||||
@OneToMany(
|
|
||||||
fetch = FetchType.LAZY,
|
|
||||||
cascade = {CascadeType.PERSIST, CascadeType.MERGE}
|
|
||||||
)
|
|
||||||
@JoinTable(
|
|
||||||
name = "merge_request_approvals",
|
|
||||||
joinColumns = @JoinColumn(name = "merge_request_id", referencedColumnName = "id"),
|
|
||||||
inverseJoinColumns = @JoinColumn(name = "person_id", referencedColumnName = "id")
|
|
||||||
)
|
|
||||||
private List<Person> approvals = new ArrayList<>();
|
|
||||||
|
|
||||||
@Column(name = "target_branch")
|
@Column(name = "target_branch")
|
||||||
private String targetBranch;
|
private String targetBranch;
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import jakarta.persistence.Table;
|
|||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author upagge 14.01.2021
|
* @author upagge 14.01.2021
|
||||||
@@ -16,9 +17,10 @@ import lombok.Setter;
|
|||||||
@Entity
|
@Entity
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
|
@ToString
|
||||||
@Table(name = "person")
|
@Table(name = "person")
|
||||||
@FieldNames(mode = {Mode.TABLE, Mode.SIMPLE})
|
@FieldNames(mode = {Mode.TABLE, Mode.SIMPLE})
|
||||||
|
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
|
||||||
public class Person {
|
public class Person {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
|
|||||||
@@ -11,8 +11,12 @@ import jakarta.persistence.Id;
|
|||||||
import jakarta.persistence.JoinColumn;
|
import jakarta.persistence.JoinColumn;
|
||||||
import jakarta.persistence.ManyToOne;
|
import jakarta.persistence.ManyToOne;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@@ -25,8 +29,11 @@ import java.time.LocalDateTime;
|
|||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@FieldNames
|
@FieldNames
|
||||||
|
@NoArgsConstructor
|
||||||
@Table(name = "pipeline")
|
@Table(name = "pipeline")
|
||||||
|
@Builder(toBuilder = true)
|
||||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
|
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
|
||||||
|
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
public class Pipeline {
|
public class Pipeline {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package dev.struchkov.bot.gitlab.context.domain.event;
|
||||||
|
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.entity.Discussion;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor(staticName = "newDiscussion")
|
||||||
|
public class NewDiscussionEvent {
|
||||||
|
|
||||||
|
private Discussion discussion;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package dev.struchkov.bot.gitlab.context.domain.event;
|
||||||
|
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequest;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor(staticName = "newMergeRequest")
|
||||||
|
public class NewMergeRequestEvent {
|
||||||
|
|
||||||
|
private MergeRequest mergeRequest;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package dev.struchkov.bot.gitlab.context.domain.event;
|
||||||
|
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.entity.Pipeline;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor(staticName = "newPipeline")
|
||||||
|
public class NewPipelineEvent {
|
||||||
|
|
||||||
|
private Pipeline pipeline;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package dev.struchkov.bot.gitlab.context.domain.event;
|
||||||
|
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.entity.Project;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor(staticName = "newProject")
|
||||||
|
public class NewProjectEvent {
|
||||||
|
|
||||||
|
private Project project;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package dev.struchkov.bot.gitlab.context.domain.event;
|
||||||
|
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.entity.Discussion;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor(staticName = "updateDiscussion")
|
||||||
|
public class UpdateDiscussionEvent {
|
||||||
|
|
||||||
|
private Discussion oldDiscussion;
|
||||||
|
private Discussion newDiscussion;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package dev.struchkov.bot.gitlab.context.domain.event;
|
||||||
|
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.AssigneeChanged;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.ReviewerChanged;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequest;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor(staticName = "updateMergeRequest")
|
||||||
|
public class UpdateMergeRequestEvent {
|
||||||
|
|
||||||
|
private MergeRequest oldMergeRequest;
|
||||||
|
private MergeRequest newMergeRequest;
|
||||||
|
|
||||||
|
private AssigneeChanged assigneeChanged;
|
||||||
|
private ReviewerChanged reviewerChanged;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package dev.struchkov.bot.gitlab.context.domain.event;
|
||||||
|
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.entity.Pipeline;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor(staticName = "updatePipeline")
|
||||||
|
public class UpdatePipelineEvent {
|
||||||
|
|
||||||
|
private Pipeline oldPipeline;
|
||||||
|
private Pipeline newPipeline;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
package dev.struchkov.bot.gitlab.core.handler;
|
||||||
|
|
||||||
|
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.MergeRequestForDiscussion;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.entity.Note;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.event.NewDiscussionEvent;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.event.UpdateDiscussionEvent;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.notify.comment.NewCommentNotify;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.notify.task.DiscussionNewNotify;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.notify.task.ThreadCloseNotify;
|
||||||
|
import dev.struchkov.bot.gitlab.context.service.AppSettingService;
|
||||||
|
import dev.struchkov.bot.gitlab.context.service.DiscussionService;
|
||||||
|
import dev.struchkov.bot.gitlab.context.service.NotifyService;
|
||||||
|
import dev.struchkov.haiti.utils.container.Pair;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel.NOTIFY_WITH_CONTEXT;
|
||||||
|
import static dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel.WITHOUT_NOTIFY;
|
||||||
|
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
|
||||||
|
import static dev.struchkov.haiti.utils.Checker.checkNull;
|
||||||
|
import static java.lang.Boolean.FALSE;
|
||||||
|
import static java.lang.Boolean.TRUE;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class DiscussionHandler {
|
||||||
|
|
||||||
|
protected static final Pattern PATTERN = Pattern.compile("@[\\w]+");
|
||||||
|
|
||||||
|
private final PersonInformation personInformation;
|
||||||
|
private final AppSettingService settingService;
|
||||||
|
private final DiscussionService discussionService;
|
||||||
|
|
||||||
|
private final NotifyService notifyService;
|
||||||
|
|
||||||
|
@EventListener
|
||||||
|
public void newDiscussionEvent(NewDiscussionEvent event) {
|
||||||
|
final Discussion discussion = event.getDiscussion();
|
||||||
|
final List<Note> notes = discussion.getNotes();
|
||||||
|
|
||||||
|
if (isNeedNotifyNewNote(discussion)) {
|
||||||
|
notifyNewThread(discussion);
|
||||||
|
} else {
|
||||||
|
notes.forEach(note -> notifyAboutPersonalAnswer(discussion, note));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventListener
|
||||||
|
public void updateDiscussionHandle(UpdateDiscussionEvent event) {
|
||||||
|
final Discussion oldDiscussion = event.getOldDiscussion();
|
||||||
|
final Discussion newDiscussion = event.getNewDiscussion();
|
||||||
|
|
||||||
|
if (oldDiscussion.isNotification()) {
|
||||||
|
final Map<Long, Note> oldNoteMap = oldDiscussion
|
||||||
|
.getNotes().stream()
|
||||||
|
.collect(Collectors.toMap(Note::getId, n -> n));
|
||||||
|
|
||||||
|
// Пользователь участвовал в обсуждении
|
||||||
|
final boolean userParticipatedInDiscussion = oldDiscussion.getNotes().stream()
|
||||||
|
.anyMatch(note -> personInformation.getId().equals(note.getAuthor().getId()));
|
||||||
|
|
||||||
|
final Note threadFirstNote = newDiscussion.getFirstNote();
|
||||||
|
if (TRUE.equals(newDiscussion.getResolved())) {
|
||||||
|
notifyAboutCloseThread(threadFirstNote, oldNoteMap.get(threadFirstNote.getId()), newDiscussion.getLastNote());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Note newNote : newDiscussion.getNotes()) {
|
||||||
|
final Long newNoteId = newNote.getId();
|
||||||
|
if (!oldNoteMap.containsKey(newNoteId)) {
|
||||||
|
if (userParticipatedInDiscussion) {
|
||||||
|
notifyAboutNewAnswer(newDiscussion, newNote);
|
||||||
|
} else {
|
||||||
|
notifyAboutPersonalAnswer(newDiscussion, newNote);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Уведомляет пользователя, если появился новый комментарий</p>
|
||||||
|
*/
|
||||||
|
private void notifyNewThread(Discussion discussion) {
|
||||||
|
final DiscussionLevel discussionLevel = settingService.getLevelDiscussionNotify();
|
||||||
|
if (!WITHOUT_NOTIFY.equals(discussionLevel)) {
|
||||||
|
final Note firstNote = discussion.getFirstNote();
|
||||||
|
|
||||||
|
final MergeRequestForDiscussion mergeRequest = discussion.getMergeRequest();
|
||||||
|
final DiscussionNewNotify.DiscussionNewNotifyBuilder messageBuilder = DiscussionNewNotify.builder()
|
||||||
|
.url(firstNote.getWebUrl())
|
||||||
|
.threadId(discussion.getId())
|
||||||
|
.mergeRequestName(mergeRequest.getTitle())
|
||||||
|
.authorName(firstNote.getAuthor().getName());
|
||||||
|
|
||||||
|
if (NOTIFY_WITH_CONTEXT.equals(discussionLevel)) {
|
||||||
|
final List<Note> notes = discussion.getNotes();
|
||||||
|
|
||||||
|
messageBuilder
|
||||||
|
.discussionMessage(firstNote.getBody());
|
||||||
|
|
||||||
|
if (notes.size() > 1) {
|
||||||
|
for (int i = 1; i < notes.size(); i++) {
|
||||||
|
final Note note = notes.get(i);
|
||||||
|
messageBuilder.note(
|
||||||
|
new Pair<>(note.getAuthor().getName(), note.getBody())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyService.send(messageBuilder.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isNeedNotifyNewNote(Discussion discussion) {
|
||||||
|
final Note firstNote = discussion.getFirstNote();
|
||||||
|
final Long gitlabUserId = personInformation.getId();
|
||||||
|
return firstNote.isResolvable() // Тип комментария требует решения (Задачи)
|
||||||
|
&& gitlabUserId.equals(discussion.getResponsible().getId()) // Ответственный за дискуссию пользователь
|
||||||
|
&& !gitlabUserId.equals(firstNote.getAuthor().getId()) // Создатель комментария не пользователь системы
|
||||||
|
&& FALSE.equals(firstNote.getResolved()); // Комментарий не отмечен как решенный
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Уведомляет пользователя, если его никнейм упоминается в комментарии.
|
||||||
|
*/
|
||||||
|
private void notifyAboutPersonalAnswer(Discussion discussion, Note note) {
|
||||||
|
final DiscussionLevel discussionLevel = settingService.getLevelDiscussionNotify();
|
||||||
|
if (!WITHOUT_NOTIFY.equals(discussionLevel)) {
|
||||||
|
final Matcher matcher = PATTERN.matcher(note.getBody());
|
||||||
|
final Set<String> recipientsLogins = new HashSet<>();
|
||||||
|
|
||||||
|
while (matcher.find()) {
|
||||||
|
final String login = matcher.group(0).replace("@", "");
|
||||||
|
recipientsLogins.add(login);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recipientsLogins.contains(personInformation.getUsername())) {
|
||||||
|
final NewCommentNotify.NewCommentNotifyBuilder notifyBuilder = NewCommentNotify.builder()
|
||||||
|
.threadId(discussion.getId())
|
||||||
|
.mergeRequestName(discussion.getMergeRequest().getTitle())
|
||||||
|
.url(note.getWebUrl());
|
||||||
|
|
||||||
|
if (NOTIFY_WITH_CONTEXT.equals(discussionLevel)) {
|
||||||
|
final Optional<Note> prevLastNote = discussion.getPrevLastNote();
|
||||||
|
final Note firstNote = discussion.getFirstNote();
|
||||||
|
|
||||||
|
if (!firstNote.equals(note)) {
|
||||||
|
notifyBuilder.message(note.getBody())
|
||||||
|
.authorName(note.getAuthor().getName());
|
||||||
|
}
|
||||||
|
if (prevLastNote.isPresent()) {
|
||||||
|
final Note prevNote = prevLastNote.get();
|
||||||
|
notifyBuilder.previousMessage(prevNote.getBody());
|
||||||
|
notifyBuilder.previousAuthor(prevNote.getAuthor().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyBuilder
|
||||||
|
.discussionMessage(firstNote.getBody())
|
||||||
|
.discussionAuthor(firstNote.getAuthor().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyService.send(notifyBuilder.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyAboutNewAnswer(Discussion discussion, Note note) {
|
||||||
|
final DiscussionLevel discussionLevel = settingService.getLevelDiscussionNotify();
|
||||||
|
|
||||||
|
if (!WITHOUT_NOTIFY.equals(discussionLevel)
|
||||||
|
&& !personInformation.getId().equals(note.getAuthor().getId())) {
|
||||||
|
final Note firstNote = discussion.getFirstNote();
|
||||||
|
|
||||||
|
final NewCommentNotify.NewCommentNotifyBuilder notifyBuilder = NewCommentNotify.builder()
|
||||||
|
.threadId(discussion.getId())
|
||||||
|
.url(note.getWebUrl())
|
||||||
|
.mergeRequestName(discussion.getMergeRequest().getTitle());
|
||||||
|
|
||||||
|
if (NOTIFY_WITH_CONTEXT.equals(discussionLevel)) {
|
||||||
|
final Optional<Note> prevLastNote = discussion.getPrevLastNote();
|
||||||
|
|
||||||
|
if (prevLastNote.isPresent()) {
|
||||||
|
final Note prevNote = prevLastNote.get();
|
||||||
|
notifyBuilder.previousMessage(prevNote.getBody());
|
||||||
|
notifyBuilder.previousAuthor(prevNote.getAuthor().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyBuilder
|
||||||
|
.discussionMessage(firstNote.getBody())
|
||||||
|
.discussionAuthor(firstNote.getAuthor().getName())
|
||||||
|
.message(note.getBody())
|
||||||
|
.authorName(note.getAuthor().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyService.send(notifyBuilder.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyAboutCloseThread(Note newNote, Note oldNote, Optional<Note> lastNote) {
|
||||||
|
final DiscussionLevel level = settingService.getLevelDiscussionNotify();
|
||||||
|
if (!WITHOUT_NOTIFY.equals(level)) {
|
||||||
|
|
||||||
|
if (isResolved(newNote, oldNote)) {
|
||||||
|
final MergeRequestForDiscussion mergeRequest = oldNote.getDiscussion().getMergeRequest();
|
||||||
|
|
||||||
|
final List<Discussion> discussions = discussionService.getAllByMergeRequestId(mergeRequest.getId())
|
||||||
|
.stream()
|
||||||
|
.filter(discussion -> Objects.nonNull(discussion.getResponsible()))
|
||||||
|
.toList();
|
||||||
|
final long allYouTasks = discussions.stream()
|
||||||
|
.filter(discussion -> personInformation.getId().equals(discussion.getFirstNote().getAuthor().getId()))
|
||||||
|
.count();
|
||||||
|
final long resolvedYouTask = discussions.stream()
|
||||||
|
.filter(discussion -> personInformation.getId().equals(discussion.getFirstNote().getAuthor().getId()) && discussion.getResolved())
|
||||||
|
.count();
|
||||||
|
|
||||||
|
final ThreadCloseNotify.ThreadCloseNotifyBuilder notifyBuilder = ThreadCloseNotify.builder()
|
||||||
|
.mergeRequestName(mergeRequest.getTitle())
|
||||||
|
.url(oldNote.getWebUrl())
|
||||||
|
.personTasks(allYouTasks)
|
||||||
|
.personResolvedTasks(resolvedYouTask);
|
||||||
|
|
||||||
|
if (NOTIFY_WITH_CONTEXT.equals(level)) {
|
||||||
|
notifyBuilder
|
||||||
|
.authorName(oldNote.getAuthor().getName())
|
||||||
|
.messageTask(oldNote.getBody());
|
||||||
|
|
||||||
|
|
||||||
|
lastNote.ifPresent(
|
||||||
|
note -> {
|
||||||
|
notifyBuilder.authorLastNote(note.getAuthor().getName());
|
||||||
|
notifyBuilder.messageLastNote(note.getBody());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyService.send(notifyBuilder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isResolved(Note note, Note oldNote) {
|
||||||
|
return checkNull(oldNote.getResolvedBy()) // В старом комментарии не было отметки о решении
|
||||||
|
&& checkNotNull(note.getResolvedBy()) // А в новом есть отметка
|
||||||
|
&& personInformation.getId().equals(oldNote.getAuthor().getId()) // и решающий не является пользователем бота
|
||||||
|
&& !note.getResolvedBy().getId().equals(oldNote.getAuthor().getId()); // и решающий не является автором треда
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,273 @@
|
|||||||
|
package dev.struchkov.bot.gitlab.core.handler;
|
||||||
|
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.AssigneeChanged;
|
||||||
|
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;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.entity.Project;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.event.NewMergeRequestEvent;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.event.UpdateMergeRequestEvent;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.ConflictMrNotify;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.ConflictResolveMrNotify;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.NewMrForAssignee;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.NewMrForReview;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.StatusMrNotify;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.UpdateMrNotify;
|
||||||
|
import dev.struchkov.bot.gitlab.context.service.DiscussionService;
|
||||||
|
import dev.struchkov.bot.gitlab.context.service.NotifyService;
|
||||||
|
import dev.struchkov.bot.gitlab.context.service.ProjectService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
|
||||||
|
import static java.lang.Boolean.TRUE;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MergeRequestHandler {
|
||||||
|
|
||||||
|
private final NotifyService notifyService;
|
||||||
|
|
||||||
|
private final PersonInformation personInformation;
|
||||||
|
private final ProjectService projectService;
|
||||||
|
private final DiscussionService discussionService;
|
||||||
|
|
||||||
|
@EventListener
|
||||||
|
public void newMrHandle(NewMergeRequestEvent event) {
|
||||||
|
final MergeRequest mergeRequest = event.getMergeRequest();
|
||||||
|
final String projectName = projectService.getByIdOrThrow(mergeRequest.getProjectId()).getName();
|
||||||
|
|
||||||
|
final boolean userReviewer = mergeRequest.isUserReviewer();
|
||||||
|
final boolean userAssignee = mergeRequest.isUserAssignee();
|
||||||
|
if (userReviewer || userAssignee) {
|
||||||
|
if (!mergeRequest.isConflict()) {
|
||||||
|
|
||||||
|
if (userReviewer) sendNotifyNewMrReview(mergeRequest, projectName);
|
||||||
|
if (userAssignee) sendNotifyNewAssignee(mergeRequest, projectName, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventListener
|
||||||
|
public void updateMrHandle(UpdateMergeRequestEvent event) {
|
||||||
|
final MergeRequest oldMergeRequest = event.getOldMergeRequest();
|
||||||
|
final MergeRequest newMergeRequest = event.getNewMergeRequest();
|
||||||
|
final AssigneeChanged assigneeChanged = event.getAssigneeChanged();
|
||||||
|
final ReviewerChanged reviewerChanged = event.getReviewerChanged();
|
||||||
|
|
||||||
|
final boolean isChangedMr = !oldMergeRequest.getUpdatedDate().equals(newMergeRequest.getUpdatedDate()) || oldMergeRequest.isConflict() != newMergeRequest.isConflict();
|
||||||
|
final boolean isChangedLinkedEntity = reviewerChanged.isChanged() || assigneeChanged.isChanged();
|
||||||
|
final boolean isMilestone = !Objects.equals(oldMergeRequest.getMilestone(), newMergeRequest.getMilestone());
|
||||||
|
|
||||||
|
if (isChangedMr || isChangedLinkedEntity || isMilestone) {
|
||||||
|
|
||||||
|
if (oldMergeRequest.isNotification()) {
|
||||||
|
final Project project = projectService.getByIdOrThrow(newMergeRequest.getProjectId());
|
||||||
|
|
||||||
|
if (isChangedMr) {
|
||||||
|
notifyAboutStatus(oldMergeRequest, newMergeRequest, project);
|
||||||
|
notifyAboutNewConflict(oldMergeRequest, newMergeRequest, project);
|
||||||
|
notifyAboutResolveConflict(oldMergeRequest, newMergeRequest, project);
|
||||||
|
notifyAboutUpdate(oldMergeRequest, newMergeRequest, project);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isChangedLinkedEntity) {
|
||||||
|
notifyReviewer(reviewerChanged, newMergeRequest, project);
|
||||||
|
notifyAssignee(assigneeChanged, oldMergeRequest, newMergeRequest, project);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendNotifyNewMrReview(MergeRequest mergeRequest, String projectName) {
|
||||||
|
final NewMrForReview.NewMrForReviewBuilder builder = NewMrForReview.builder()
|
||||||
|
.mrId(mergeRequest.getId())
|
||||||
|
.projectName(projectName)
|
||||||
|
.labels(mergeRequest.getLabels())
|
||||||
|
.author(mergeRequest.getAuthor().getName())
|
||||||
|
.milestone(mergeRequest.getMilestone())
|
||||||
|
.description(mergeRequest.getDescription())
|
||||||
|
.title(mergeRequest.getTitle())
|
||||||
|
.url(mergeRequest.getWebUrl())
|
||||||
|
.targetBranch(mergeRequest.getTargetBranch())
|
||||||
|
.sourceBranch(mergeRequest.getSourceBranch());
|
||||||
|
|
||||||
|
getAssignee(mergeRequest)
|
||||||
|
.map(Person::getName)
|
||||||
|
.ifPresent(builder::assignee);
|
||||||
|
|
||||||
|
notifyService.send(builder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendNotifyNewAssignee(MergeRequest mergeRequest, String projectName, String oldAssigneeName) {
|
||||||
|
final NewMrForAssignee.NewMrForAssigneeBuilder builder = NewMrForAssignee.builder()
|
||||||
|
.mrId(mergeRequest.getId())
|
||||||
|
.projectName(projectName)
|
||||||
|
.labels(mergeRequest.getLabels())
|
||||||
|
.author(mergeRequest.getAuthor().getName())
|
||||||
|
.description(mergeRequest.getDescription())
|
||||||
|
.milestone(mergeRequest.getMilestone())
|
||||||
|
.title(mergeRequest.getTitle())
|
||||||
|
.url(mergeRequest.getWebUrl())
|
||||||
|
.targetBranch(mergeRequest.getTargetBranch())
|
||||||
|
.sourceBranch(mergeRequest.getSourceBranch())
|
||||||
|
.milestone(mergeRequest.getMilestone())
|
||||||
|
.reviewers(mergeRequest.getReviewers().stream().map(Person::getName).toList());
|
||||||
|
|
||||||
|
if (checkNotNull(oldAssigneeName)) {
|
||||||
|
builder.oldAssigneeName(oldAssigneeName);
|
||||||
|
|
||||||
|
getAssignee(mergeRequest)
|
||||||
|
.map(Person::getName)
|
||||||
|
.ifPresent(builder::newAssigneeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyService.send(builder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyAboutUpdate(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) {
|
||||||
|
final Long botUserGitlabId = personInformation.getId();
|
||||||
|
if (
|
||||||
|
!botUserGitlabId.equals(mergeRequest.getAuthor().getId()) // Автор MR не пользователь приложения
|
||||||
|
&& !oldMergeRequest.getDateLastCommit().equals(mergeRequest.getDateLastCommit()) // Изменилась дата последнего коммита
|
||||||
|
&& !mergeRequest.isConflict() // MR не находится в состоянии конфликта
|
||||||
|
&& !botUserGitlabId.equals(oldMergeRequest.getAuthor().getId()) // и MR создан НЕ пользователем бота
|
||||||
|
) {
|
||||||
|
long allTask = 0;
|
||||||
|
long resolvedTask = 0;
|
||||||
|
long allYouTasks = 0;
|
||||||
|
long resolvedYouTask = 0;
|
||||||
|
|
||||||
|
final List<Discussion> discussions = discussionService.getAllByMergeRequestId(oldMergeRequest.getId());
|
||||||
|
for (Discussion discussion : discussions) {
|
||||||
|
if (checkNotNull(discussion.getResponsible())) {
|
||||||
|
final boolean isBotUserAuthorDiscussion = botUserGitlabId.equals(discussion.getFirstNote().getAuthor().getId());
|
||||||
|
allTask += 1;
|
||||||
|
if (isBotUserAuthorDiscussion) {
|
||||||
|
allYouTasks += 1;
|
||||||
|
}
|
||||||
|
if (TRUE.equals(discussion.getResolved())) {
|
||||||
|
resolvedTask += 1;
|
||||||
|
if (isBotUserAuthorDiscussion) {
|
||||||
|
resolvedYouTask += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final UpdateMrNotify.UpdateMrNotifyBuilder notifyBuilder = UpdateMrNotify.builder()
|
||||||
|
.mrId(oldMergeRequest.getId())
|
||||||
|
.author(oldMergeRequest.getAuthor().getName())
|
||||||
|
.name(oldMergeRequest.getTitle())
|
||||||
|
.projectName(project.getName())
|
||||||
|
.url(oldMergeRequest.getWebUrl())
|
||||||
|
.allTasks(allTask)
|
||||||
|
.milestone(mergeRequest.getMilestone())
|
||||||
|
.allResolvedTasks(resolvedTask)
|
||||||
|
.personTasks(allYouTasks)
|
||||||
|
.personResolvedTasks(resolvedYouTask);
|
||||||
|
|
||||||
|
if (oldMergeRequest.isConflict() && !mergeRequest.isConflict()) {
|
||||||
|
notifyBuilder.comment("The conflict has been resolved");
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyService.send(notifyBuilder.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void notifyAboutNewConflict(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) {
|
||||||
|
final Long gitlabUserId = personInformation.getId();
|
||||||
|
if (
|
||||||
|
!oldMergeRequest.isConflict() // У старого MR не было конфликта
|
||||||
|
&& mergeRequest.isConflict() // А у нового есть
|
||||||
|
&& gitlabUserId.equals(oldMergeRequest.getAuthor().getId()) // и MR создан пользователем бота
|
||||||
|
) {
|
||||||
|
notifyService.send(
|
||||||
|
ConflictMrNotify.builder()
|
||||||
|
.mrId(oldMergeRequest.getId())
|
||||||
|
.sourceBranch(oldMergeRequest.getSourceBranch())
|
||||||
|
.name(mergeRequest.getTitle())
|
||||||
|
.url(mergeRequest.getWebUrl())
|
||||||
|
.projectKey(project.getName())
|
||||||
|
.milestone(mergeRequest.getMilestone())
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyAboutResolveConflict(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) {
|
||||||
|
final Long gitlabUserId = personInformation.getId();
|
||||||
|
if (oldMergeRequest.isConflict() && !mergeRequest.isConflict()) {
|
||||||
|
// проверяем даты коммитов, так как при пуше в target ветку MR у которого есть конфликт, конфликт на время пропадает. Судя по всему GitLab после пуша заново проверяет вероятность конфликта. Чаще всего конфликт никуда не девается.
|
||||||
|
if (oldMergeRequest.getDateLastCommit().equals(mergeRequest.getDateLastCommit())) {
|
||||||
|
mergeRequest.setConflict(true);
|
||||||
|
} else {
|
||||||
|
if (gitlabUserId.equals(oldMergeRequest.getAuthor().getId())) {
|
||||||
|
notifyService.send(
|
||||||
|
ConflictResolveMrNotify.builder()
|
||||||
|
.mrId(oldMergeRequest.getId())
|
||||||
|
.sourceBranch(oldMergeRequest.getSourceBranch())
|
||||||
|
.name(mergeRequest.getTitle())
|
||||||
|
.url(mergeRequest.getWebUrl())
|
||||||
|
.projectKey(project.getName())
|
||||||
|
.milestone(mergeRequest.getMilestone())
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) // статус изменился
|
||||||
|
&& gitlabUserId.equals(oldMergeRequest.getAuthor().getId()) // создатель MR является пользователем бота
|
||||||
|
) {
|
||||||
|
notifyService.send(
|
||||||
|
StatusMrNotify.builder()
|
||||||
|
.mrId(oldMergeRequest.getId())
|
||||||
|
.name(newMergeRequest.getTitle())
|
||||||
|
.url(oldMergeRequest.getWebUrl())
|
||||||
|
.projectName(project.getName())
|
||||||
|
.newStatus(newStatus)
|
||||||
|
.oldStatus(oldStatus)
|
||||||
|
.milestone(newMergeRequest.getMilestone())
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<Person> getAssignee(MergeRequest mergeRequest) {
|
||||||
|
return Optional.ofNullable(mergeRequest.getAssignee());
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO [05.12.2022|uPagge]: Добавить уведомление, если происходит удаление
|
||||||
|
|
||||||
|
private void notifyAssignee(AssigneeChanged assigneeChanged, MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) {
|
||||||
|
switch (assigneeChanged) {
|
||||||
|
case BECOME ->
|
||||||
|
sendNotifyNewAssignee(mergeRequest, project.getName(), getAssignee(oldMergeRequest).map(Person::getName).orElse(null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//TODO [05.12.2022|uPagge]: Добавить уведомление, если происходит удаление ревьювера
|
||||||
|
|
||||||
|
private void notifyReviewer(ReviewerChanged reviewerChanged, MergeRequest mergeRequest, Project project) {
|
||||||
|
switch (reviewerChanged) {
|
||||||
|
case BECOME -> sendNotifyNewMrReview(mergeRequest, project.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package dev.struchkov.bot.gitlab.core.handler;
|
||||||
|
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.PersonInformation;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.PipelineStatus;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.entity.Pipeline;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.event.NewPipelineEvent;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.notify.pipeline.PipelineNotify;
|
||||||
|
import dev.struchkov.bot.gitlab.context.service.NotifyService;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.CANCELED;
|
||||||
|
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.FAILED;
|
||||||
|
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.SKIPPED;
|
||||||
|
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.SUCCESS;
|
||||||
|
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class PipelineHandler {
|
||||||
|
|
||||||
|
// Статусы пайплайнов, о которых нужно уведомить
|
||||||
|
private static final Set<PipelineStatus> notificationStatus = Set.of(FAILED, SUCCESS, CANCELED, SKIPPED);
|
||||||
|
|
||||||
|
private final PersonInformation personInformation;
|
||||||
|
private final NotifyService notifyService;
|
||||||
|
|
||||||
|
@EventListener
|
||||||
|
public void newPipelineHandle(NewPipelineEvent event) {
|
||||||
|
final Pipeline pipeline = event.getPipeline();
|
||||||
|
if (isNeedNotifyNewPipeline(pipeline)) {
|
||||||
|
notifyService.send(
|
||||||
|
PipelineNotify.builder()
|
||||||
|
.projectId(pipeline.getProjectId())
|
||||||
|
.newStatus(pipeline.getStatus())
|
||||||
|
.pipelineId(pipeline.getId())
|
||||||
|
.refName(pipeline.getRef())
|
||||||
|
.webUrl(pipeline.getWebUrl())
|
||||||
|
.oldStatus(PipelineStatus.NULL)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isNeedNotifyNewPipeline(@NonNull Pipeline pipeline) {
|
||||||
|
final Person personPipelineCreator = pipeline.getPerson();
|
||||||
|
return notificationStatus.contains(pipeline.getStatus()) // Пайплайн имеет статус необходимый для уведомления
|
||||||
|
&& checkNotNull(personPipelineCreator) // Создатель пайплайна не null
|
||||||
|
&& personInformation.getId().equals(personPipelineCreator.getId()) // Пользователь приложения является инициатором пайплайна
|
||||||
|
&& LocalDateTime.now().minusDays(1).isBefore(pipeline.getCreated()); // Пайплан был создан не более 24 часов назад
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package dev.struchkov.bot.gitlab.core.handler;
|
||||||
|
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.entity.Project;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.event.NewProjectEvent;
|
||||||
|
import dev.struchkov.bot.gitlab.context.domain.notify.project.NewProjectNotify;
|
||||||
|
import dev.struchkov.bot.gitlab.context.service.NotifyService;
|
||||||
|
import dev.struchkov.bot.gitlab.context.service.PersonService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ProjectHandler {
|
||||||
|
|
||||||
|
private final NotifyService notifyService;
|
||||||
|
private final PersonService personService;
|
||||||
|
|
||||||
|
@EventListener
|
||||||
|
public void handleNewProjectEvent(NewProjectEvent event) {
|
||||||
|
final Project newProject = event.getProject();
|
||||||
|
final String authorName = personService.getByIdOrThrown(newProject.getCreatorId()).getName();
|
||||||
|
notifyService.send(
|
||||||
|
NewProjectNotify.builder()
|
||||||
|
.projectId(newProject.getId())
|
||||||
|
.projectDescription(newProject.getDescription())
|
||||||
|
.projectName(newProject.getName())
|
||||||
|
.projectUrl(newProject.getWebUrl())
|
||||||
|
.sshUrlToRepo(newProject.getSshUrlToRepo())
|
||||||
|
.httpUrlToRepo(newProject.getHttpUrlToRepo())
|
||||||
|
.authorName(authorName)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,44 +1,31 @@
|
|||||||
package dev.struchkov.bot.gitlab.core.service;
|
package dev.struchkov.bot.gitlab.core.service;
|
||||||
|
|
||||||
import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
|
import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
|
||||||
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.Discussion;
|
||||||
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequestForDiscussion;
|
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequestForDiscussion;
|
||||||
import dev.struchkov.bot.gitlab.context.domain.entity.Note;
|
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.entity.Person;
|
||||||
import dev.struchkov.bot.gitlab.context.domain.notify.comment.NewCommentNotify;
|
|
||||||
import dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel;
|
import dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel;
|
||||||
import dev.struchkov.bot.gitlab.context.domain.notify.task.DiscussionNewNotify;
|
|
||||||
import dev.struchkov.bot.gitlab.context.domain.notify.task.ThreadCloseNotify;
|
|
||||||
import dev.struchkov.bot.gitlab.context.repository.DiscussionRepository;
|
import dev.struchkov.bot.gitlab.context.repository.DiscussionRepository;
|
||||||
import dev.struchkov.bot.gitlab.context.service.AppSettingService;
|
import dev.struchkov.bot.gitlab.context.service.AppSettingService;
|
||||||
import dev.struchkov.bot.gitlab.context.service.DiscussionService;
|
import dev.struchkov.bot.gitlab.context.service.DiscussionService;
|
||||||
import dev.struchkov.bot.gitlab.context.service.NotifyService;
|
|
||||||
import dev.struchkov.haiti.utils.container.Pair;
|
|
||||||
import dev.struchkov.sdk.gitlab.core.GitlabSdkManager;
|
import dev.struchkov.sdk.gitlab.core.GitlabSdkManager;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel.NOTIFY_WITH_CONTEXT;
|
import static dev.struchkov.bot.gitlab.context.domain.event.NewDiscussionEvent.newDiscussion;
|
||||||
|
import static dev.struchkov.bot.gitlab.context.domain.event.UpdateDiscussionEvent.updateDiscussion;
|
||||||
import static dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel.WITHOUT_NOTIFY;
|
import static dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel.WITHOUT_NOTIFY;
|
||||||
import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException;
|
import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException;
|
||||||
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
|
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
|
||||||
import static dev.struchkov.haiti.utils.Checker.checkNull;
|
|
||||||
import static java.lang.Boolean.FALSE;
|
|
||||||
import static java.lang.Boolean.TRUE;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Сервис для работы с дискуссиями.
|
* Сервис для работы с дискуссиями.
|
||||||
@@ -50,31 +37,21 @@ import static java.lang.Boolean.TRUE;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class DiscussionServiceImpl implements DiscussionService {
|
public class DiscussionServiceImpl implements DiscussionService {
|
||||||
|
|
||||||
protected static final Pattern PATTERN = Pattern.compile("@[\\w]+");
|
|
||||||
|
|
||||||
private final DiscussionRepository repository;
|
private final DiscussionRepository repository;
|
||||||
|
|
||||||
private final NotifyService notifyService;
|
|
||||||
private final AppSettingService settingService;
|
private final AppSettingService settingService;
|
||||||
|
|
||||||
private final PersonInformation personInformation;
|
|
||||||
|
|
||||||
private final GitlabSdkManager gitlabSdkManager;
|
private final GitlabSdkManager gitlabSdkManager;
|
||||||
|
private final ApplicationEventPublisher eventPublisher;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public Discussion create(@NonNull Discussion discussion) {
|
public Discussion create(@NonNull Discussion discussion) {
|
||||||
final List<Note> notes = discussion.getNotes();
|
|
||||||
|
|
||||||
final DiscussionLevel levelDiscussionNotify = settingService.getLevelDiscussionNotify();
|
final DiscussionLevel levelDiscussionNotify = settingService.getLevelDiscussionNotify();
|
||||||
if (!WITHOUT_NOTIFY.equals(levelDiscussionNotify)) {
|
if (!WITHOUT_NOTIFY.equals(levelDiscussionNotify)) {
|
||||||
discussion.setNotification(true);
|
discussion.setNotification(true);
|
||||||
|
|
||||||
if (isNeedNotifyNewNote(discussion)) {
|
eventPublisher.publishEvent(newDiscussion(discussion));
|
||||||
notifyNewThread(discussion);
|
|
||||||
} else {
|
|
||||||
notes.forEach(note -> notifyAboutPersonalAnswer(discussion, note));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
discussion.setNotification(false);
|
discussion.setNotification(false);
|
||||||
}
|
}
|
||||||
@@ -116,23 +93,11 @@ public class DiscussionServiceImpl implements DiscussionService {
|
|||||||
.allMatch(note -> note.isResolvable() && note.getResolved());
|
.allMatch(note -> note.isResolvable() && note.getResolved());
|
||||||
discussion.setResolved(resolved);
|
discussion.setResolved(resolved);
|
||||||
|
|
||||||
if (oldDiscussion.isNotification()) {
|
eventPublisher.publishEvent(updateDiscussion(oldDiscussion, discussion));
|
||||||
notifyUpdateNote(oldDiscussion, discussion);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return repository.save(discussion);
|
return repository.save(discussion);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isNeedNotifyNewNote(Discussion discussion) {
|
|
||||||
final Note firstNote = discussion.getFirstNote();
|
|
||||||
final Long gitlabUserId = personInformation.getId();
|
|
||||||
return firstNote.isResolvable() // Тип комментария требует решения (Задачи)
|
|
||||||
&& gitlabUserId.equals(discussion.getResponsible().getId()) // Ответственный за дискуссию пользователь
|
|
||||||
&& !gitlabUserId.equals(firstNote.getAuthor().getId()) // Создатель комментария не пользователь системы
|
|
||||||
&& FALSE.equals(firstNote.getResolved()); // Комментарий не отмечен как решенный
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Discussion> updateAll(@NonNull List<Discussion> discussions) {
|
public List<Discussion> updateAll(@NonNull List<Discussion> discussions) {
|
||||||
return discussions.stream()
|
return discussions.stream()
|
||||||
@@ -140,85 +105,6 @@ public class DiscussionServiceImpl implements DiscussionService {
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyUpdateNote(Discussion oldDiscussion, Discussion discussion) {
|
|
||||||
final Map<Long, Note> oldNoteMap = oldDiscussion
|
|
||||||
.getNotes().stream()
|
|
||||||
.collect(Collectors.toMap(Note::getId, n -> n));
|
|
||||||
|
|
||||||
// Пользователь участвовал в обсуждении
|
|
||||||
final boolean userParticipatedInDiscussion = oldDiscussion.getNotes().stream()
|
|
||||||
.anyMatch(note -> personInformation.getId().equals(note.getAuthor().getId()));
|
|
||||||
|
|
||||||
final Note threadFirstNote = discussion.getFirstNote();
|
|
||||||
if (TRUE.equals(discussion.getResolved())) {
|
|
||||||
notifyAboutCloseThread(threadFirstNote, oldNoteMap.get(threadFirstNote.getId()), discussion.getLastNote());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Note newNote : discussion.getNotes()) {
|
|
||||||
final Long newNoteId = newNote.getId();
|
|
||||||
if (!oldNoteMap.containsKey(newNoteId)) {
|
|
||||||
if (userParticipatedInDiscussion) {
|
|
||||||
notifyAboutNewAnswer(discussion, newNote);
|
|
||||||
} else {
|
|
||||||
notifyAboutPersonalAnswer(discussion, newNote);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyAboutCloseThread(Note newNote, Note oldNote, Optional<Note> lastNote) {
|
|
||||||
final DiscussionLevel level = settingService.getLevelDiscussionNotify();
|
|
||||||
if (!WITHOUT_NOTIFY.equals(level)) {
|
|
||||||
|
|
||||||
if (isResolved(newNote, oldNote)) {
|
|
||||||
final MergeRequestForDiscussion mergeRequest = oldNote.getDiscussion().getMergeRequest();
|
|
||||||
|
|
||||||
final List<Discussion> discussions = getAllByMergeRequestId(mergeRequest.getId())
|
|
||||||
.stream()
|
|
||||||
.filter(discussion -> Objects.nonNull(discussion.getResponsible()))
|
|
||||||
.toList();
|
|
||||||
final long allYouTasks = discussions.stream()
|
|
||||||
.filter(discussion -> personInformation.getId().equals(discussion.getFirstNote().getAuthor().getId()))
|
|
||||||
.count();
|
|
||||||
final long resolvedYouTask = discussions.stream()
|
|
||||||
.filter(discussion -> personInformation.getId().equals(discussion.getFirstNote().getAuthor().getId()) && discussion.getResolved())
|
|
||||||
.count();
|
|
||||||
|
|
||||||
final ThreadCloseNotify.ThreadCloseNotifyBuilder notifyBuilder = ThreadCloseNotify.builder()
|
|
||||||
.mergeRequestName(mergeRequest.getTitle())
|
|
||||||
.url(oldNote.getWebUrl())
|
|
||||||
.personTasks(allYouTasks)
|
|
||||||
.personResolvedTasks(resolvedYouTask);
|
|
||||||
|
|
||||||
if (NOTIFY_WITH_CONTEXT.equals(level)) {
|
|
||||||
notifyBuilder
|
|
||||||
.authorName(oldNote.getAuthor().getName())
|
|
||||||
.messageTask(oldNote.getBody());
|
|
||||||
|
|
||||||
|
|
||||||
lastNote.ifPresent(
|
|
||||||
note -> {
|
|
||||||
notifyBuilder.authorLastNote(note.getAuthor().getName());
|
|
||||||
notifyBuilder.messageLastNote(note.getBody());
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyService.send(notifyBuilder.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isResolved(Note note, Note oldNote) {
|
|
||||||
return checkNull(oldNote.getResolvedBy()) // В старом комментарии не было отметки о решении
|
|
||||||
&& checkNotNull(note.getResolvedBy()) // А в новом есть отметка
|
|
||||||
&& personInformation.getId().equals(oldNote.getAuthor().getId()) // и решающий не является пользователем бота
|
|
||||||
&& !note.getResolvedBy().getId().equals(oldNote.getAuthor().getId()); // и решающий не является автором треда
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void answer(@NonNull String discussionId, @NonNull String text) {
|
public void answer(@NonNull String discussionId, @NonNull String text) {
|
||||||
final Discussion discussion = repository.findById(discussionId)
|
final Discussion discussion = repository.findById(discussionId)
|
||||||
@@ -285,115 +171,4 @@ public class DiscussionServiceImpl implements DiscussionService {
|
|||||||
repository.notification(enable, discussionId);
|
repository.notification(enable, discussionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyAboutNewAnswer(Discussion discussion, Note note) {
|
|
||||||
final DiscussionLevel discussionLevel = settingService.getLevelDiscussionNotify();
|
|
||||||
|
|
||||||
if (!WITHOUT_NOTIFY.equals(discussionLevel)
|
|
||||||
&& !personInformation.getId().equals(note.getAuthor().getId())) {
|
|
||||||
final Note firstNote = discussion.getFirstNote();
|
|
||||||
|
|
||||||
final NewCommentNotify.NewCommentNotifyBuilder notifyBuilder = NewCommentNotify.builder()
|
|
||||||
.threadId(discussion.getId())
|
|
||||||
.url(note.getWebUrl())
|
|
||||||
.mergeRequestName(discussion.getMergeRequest().getTitle());
|
|
||||||
|
|
||||||
if (NOTIFY_WITH_CONTEXT.equals(discussionLevel)) {
|
|
||||||
final Optional<Note> prevLastNote = discussion.getPrevLastNote();
|
|
||||||
|
|
||||||
if (prevLastNote.isPresent()) {
|
|
||||||
final Note prevNote = prevLastNote.get();
|
|
||||||
notifyBuilder.previousMessage(prevNote.getBody());
|
|
||||||
notifyBuilder.previousAuthor(prevNote.getAuthor().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyBuilder
|
|
||||||
.discussionMessage(firstNote.getBody())
|
|
||||||
.discussionAuthor(firstNote.getAuthor().getName())
|
|
||||||
.message(note.getBody())
|
|
||||||
.authorName(note.getAuthor().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyService.send(notifyBuilder.build());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Уведомляет пользователя, если его никнейм упоминается в комментарии.
|
|
||||||
*/
|
|
||||||
private void notifyAboutPersonalAnswer(Discussion discussion, Note note) {
|
|
||||||
final DiscussionLevel discussionLevel = settingService.getLevelDiscussionNotify();
|
|
||||||
if (!WITHOUT_NOTIFY.equals(discussionLevel)) {
|
|
||||||
final Matcher matcher = PATTERN.matcher(note.getBody());
|
|
||||||
final Set<String> recipientsLogins = new HashSet<>();
|
|
||||||
|
|
||||||
while (matcher.find()) {
|
|
||||||
final String login = matcher.group(0).replace("@", "");
|
|
||||||
recipientsLogins.add(login);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (recipientsLogins.contains(personInformation.getUsername())) {
|
|
||||||
final NewCommentNotify.NewCommentNotifyBuilder notifyBuilder = NewCommentNotify.builder()
|
|
||||||
.threadId(discussion.getId())
|
|
||||||
.mergeRequestName(discussion.getMergeRequest().getTitle())
|
|
||||||
.url(note.getWebUrl());
|
|
||||||
|
|
||||||
if (NOTIFY_WITH_CONTEXT.equals(discussionLevel)) {
|
|
||||||
final Optional<Note> prevLastNote = discussion.getPrevLastNote();
|
|
||||||
final Note firstNote = discussion.getFirstNote();
|
|
||||||
|
|
||||||
if (!firstNote.equals(note)) {
|
|
||||||
notifyBuilder.message(note.getBody())
|
|
||||||
.authorName(note.getAuthor().getName());
|
|
||||||
}
|
|
||||||
if (prevLastNote.isPresent()) {
|
|
||||||
final Note prevNote = prevLastNote.get();
|
|
||||||
notifyBuilder.previousMessage(prevNote.getBody());
|
|
||||||
notifyBuilder.previousAuthor(prevNote.getAuthor().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyBuilder
|
|
||||||
.discussionMessage(firstNote.getBody())
|
|
||||||
.discussionAuthor(firstNote.getAuthor().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyService.send(notifyBuilder.build());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Уведомляет пользователя, если появился новый комментарий</p>
|
|
||||||
*/
|
|
||||||
private void notifyNewThread(Discussion discussion) {
|
|
||||||
final DiscussionLevel discussionLevel = settingService.getLevelDiscussionNotify();
|
|
||||||
if (!WITHOUT_NOTIFY.equals(discussionLevel)) {
|
|
||||||
final Note firstNote = discussion.getFirstNote();
|
|
||||||
|
|
||||||
final MergeRequestForDiscussion mergeRequest = discussion.getMergeRequest();
|
|
||||||
final DiscussionNewNotify.DiscussionNewNotifyBuilder messageBuilder = DiscussionNewNotify.builder()
|
|
||||||
.url(firstNote.getWebUrl())
|
|
||||||
.threadId(discussion.getId())
|
|
||||||
.mergeRequestName(mergeRequest.getTitle())
|
|
||||||
.authorName(firstNote.getAuthor().getName());
|
|
||||||
|
|
||||||
if (NOTIFY_WITH_CONTEXT.equals(discussionLevel)) {
|
|
||||||
final List<Note> notes = discussion.getNotes();
|
|
||||||
|
|
||||||
messageBuilder
|
|
||||||
.discussionMessage(firstNote.getBody());
|
|
||||||
|
|
||||||
if (notes.size() > 1) {
|
|
||||||
for (int i = 1; i < notes.size(); i++) {
|
|
||||||
final Note note = notes.get(i);
|
|
||||||
messageBuilder.note(
|
|
||||||
new Pair<>(note.getAuthor().getName(), note.getBody())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyService.send(messageBuilder.build());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,40 +6,29 @@ import dev.struchkov.bot.gitlab.context.domain.IdAndStatusPr;
|
|||||||
import dev.struchkov.bot.gitlab.context.domain.MergeRequestState;
|
import dev.struchkov.bot.gitlab.context.domain.MergeRequestState;
|
||||||
import dev.struchkov.bot.gitlab.context.domain.PersonInformation;
|
import dev.struchkov.bot.gitlab.context.domain.PersonInformation;
|
||||||
import dev.struchkov.bot.gitlab.context.domain.ReviewerChanged;
|
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.MergeRequest;
|
||||||
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequestForDiscussion;
|
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequestForDiscussion;
|
||||||
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
|
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
|
||||||
import dev.struchkov.bot.gitlab.context.domain.entity.Project;
|
|
||||||
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.ConflictMrNotify;
|
|
||||||
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.ConflictResolveMrNotify;
|
|
||||||
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.NewMrForAssignee;
|
|
||||||
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.NewMrForReview;
|
|
||||||
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.StatusMrNotify;
|
|
||||||
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.UpdateMrNotify;
|
|
||||||
import dev.struchkov.bot.gitlab.context.repository.MergeRequestRepository;
|
import dev.struchkov.bot.gitlab.context.repository.MergeRequestRepository;
|
||||||
import dev.struchkov.bot.gitlab.context.service.DiscussionService;
|
|
||||||
import dev.struchkov.bot.gitlab.context.service.MergeRequestsService;
|
import dev.struchkov.bot.gitlab.context.service.MergeRequestsService;
|
||||||
import dev.struchkov.bot.gitlab.context.service.NotifyService;
|
|
||||||
import dev.struchkov.bot.gitlab.context.service.ProjectService;
|
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static dev.struchkov.bot.gitlab.context.domain.MergeRequestState.CLOSED;
|
import static dev.struchkov.bot.gitlab.context.domain.MergeRequestState.CLOSED;
|
||||||
import static dev.struchkov.bot.gitlab.context.domain.MergeRequestState.MERGED;
|
import static dev.struchkov.bot.gitlab.context.domain.MergeRequestState.MERGED;
|
||||||
|
import static dev.struchkov.bot.gitlab.context.domain.event.NewMergeRequestEvent.newMergeRequest;
|
||||||
|
import static dev.struchkov.bot.gitlab.context.domain.event.UpdateMergeRequestEvent.updateMergeRequest;
|
||||||
import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException;
|
import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException;
|
||||||
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
|
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
|
||||||
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
|
|
||||||
import static java.lang.Boolean.TRUE;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@@ -48,11 +37,9 @@ public class MergeRequestsServiceImpl implements MergeRequestsService {
|
|||||||
|
|
||||||
public static final Set<MergeRequestState> DELETE_STATES = Set.of(MERGED, CLOSED);
|
public static final Set<MergeRequestState> DELETE_STATES = Set.of(MERGED, CLOSED);
|
||||||
|
|
||||||
private final MergeRequestRepository repository;
|
private final ApplicationEventPublisher eventPublisher;
|
||||||
|
|
||||||
private final NotifyService notifyService;
|
private final MergeRequestRepository repository;
|
||||||
private final ProjectService projectService;
|
|
||||||
private final DiscussionService discussionService;
|
|
||||||
|
|
||||||
private final PersonInformation personInformation;
|
private final PersonInformation personInformation;
|
||||||
|
|
||||||
@@ -69,13 +56,7 @@ public class MergeRequestsServiceImpl implements MergeRequestsService {
|
|||||||
|
|
||||||
final MergeRequest savedMergeRequest = repository.save(mergeRequest);
|
final MergeRequest savedMergeRequest = repository.save(mergeRequest);
|
||||||
|
|
||||||
if (botUserReviewer || botUserAssignee) {
|
eventPublisher.publishEvent(newMergeRequest(savedMergeRequest));
|
||||||
if (!mergeRequest.isConflict()) {
|
|
||||||
final String projectName = projectService.getByIdOrThrow(savedMergeRequest.getProjectId()).getName();
|
|
||||||
if (botUserReviewer) sendNotifyNewMrReview(savedMergeRequest, projectName);
|
|
||||||
if (botUserAssignee) sendNotifyNewAssignee(mergeRequest, projectName, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return savedMergeRequest;
|
return savedMergeRequest;
|
||||||
}
|
}
|
||||||
@@ -117,62 +98,14 @@ public class MergeRequestsServiceImpl implements MergeRequestsService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendNotifyNewMrReview(MergeRequest mergeRequest, String projectName) {
|
|
||||||
final NewMrForReview.NewMrForReviewBuilder builder = NewMrForReview.builder()
|
|
||||||
.mrId(mergeRequest.getId())
|
|
||||||
.projectName(projectName)
|
|
||||||
.labels(mergeRequest.getLabels())
|
|
||||||
.author(mergeRequest.getAuthor().getName())
|
|
||||||
.milestone(mergeRequest.getMilestone())
|
|
||||||
.description(mergeRequest.getDescription())
|
|
||||||
.title(mergeRequest.getTitle())
|
|
||||||
.url(mergeRequest.getWebUrl())
|
|
||||||
.targetBranch(mergeRequest.getTargetBranch())
|
|
||||||
.sourceBranch(mergeRequest.getSourceBranch());
|
|
||||||
|
|
||||||
getAssignee(mergeRequest)
|
|
||||||
.map(Person::getName)
|
|
||||||
.ifPresent(builder::assignee);
|
|
||||||
|
|
||||||
notifyService.send(builder.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Optional<Person> getAssignee(MergeRequest mergeRequest) {
|
|
||||||
return Optional.ofNullable(mergeRequest.getAssignee());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendNotifyNewAssignee(MergeRequest mergeRequest, String projectName, String oldAssigneeName) {
|
|
||||||
final NewMrForAssignee.NewMrForAssigneeBuilder builder = NewMrForAssignee.builder()
|
|
||||||
.mrId(mergeRequest.getId())
|
|
||||||
.projectName(projectName)
|
|
||||||
.labels(mergeRequest.getLabels())
|
|
||||||
.author(mergeRequest.getAuthor().getName())
|
|
||||||
.description(mergeRequest.getDescription())
|
|
||||||
.milestone(mergeRequest.getMilestone())
|
|
||||||
.title(mergeRequest.getTitle())
|
|
||||||
.url(mergeRequest.getWebUrl())
|
|
||||||
.targetBranch(mergeRequest.getTargetBranch())
|
|
||||||
.sourceBranch(mergeRequest.getSourceBranch())
|
|
||||||
.milestone(mergeRequest.getMilestone())
|
|
||||||
.reviewers(mergeRequest.getReviewers().stream().map(Person::getName).toList());
|
|
||||||
|
|
||||||
if (checkNotNull(oldAssigneeName)) {
|
|
||||||
builder.oldAssigneeName(oldAssigneeName);
|
|
||||||
|
|
||||||
getAssignee(mergeRequest)
|
|
||||||
.map(Person::getName)
|
|
||||||
.ifPresent(builder::newAssigneeName);
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyService.send(builder.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public MergeRequest update(@NonNull MergeRequest mergeRequest) {
|
public MergeRequest update(@NonNull MergeRequest mergeRequest) {
|
||||||
final MergeRequest oldMergeRequest = repository.findById(mergeRequest.getId())
|
final MergeRequest oldMergeRequest = repository.findById(mergeRequest.getId())
|
||||||
.orElseThrow(notFoundException("MergeRequest не найден"));
|
.orElseThrow(notFoundException("MergeRequest не найден"));
|
||||||
|
|
||||||
|
final MergeRequest cloneOldMergeRequest = oldMergeRequest.toBuilder().build();
|
||||||
|
|
||||||
mergeRequest.setNotification(oldMergeRequest.isNotification());
|
mergeRequest.setNotification(oldMergeRequest.isNotification());
|
||||||
|
|
||||||
final Long gitlabUserId = personInformation.getId();
|
final Long gitlabUserId = personInformation.getId();
|
||||||
@@ -182,49 +115,13 @@ public class MergeRequestsServiceImpl implements MergeRequestsService {
|
|||||||
mergeRequest.setUserAssignee(assigneeChanged.getNewStatus(oldMergeRequest.isUserAssignee()));
|
mergeRequest.setUserAssignee(assigneeChanged.getNewStatus(oldMergeRequest.isUserAssignee()));
|
||||||
mergeRequest.setUserReviewer(reviewerChanged.getNewStatus(oldMergeRequest.isUserReviewer()));
|
mergeRequest.setUserReviewer(reviewerChanged.getNewStatus(oldMergeRequest.isUserReviewer()));
|
||||||
|
|
||||||
final boolean isChangedMr = !oldMergeRequest.getUpdatedDate().equals(mergeRequest.getUpdatedDate()) || oldMergeRequest.isConflict() != mergeRequest.isConflict();
|
eventPublisher.publishEvent(
|
||||||
final boolean isChangedLinkedEntity = reviewerChanged.isChanged() || assigneeChanged.isChanged();
|
updateMergeRequest(cloneOldMergeRequest, mergeRequest, assigneeChanged, reviewerChanged)
|
||||||
final boolean isMilestone = !Objects.equals(oldMergeRequest.getMilestone(), mergeRequest.getMilestone());
|
);
|
||||||
|
|
||||||
if (isChangedMr || isChangedLinkedEntity || isMilestone) {
|
return repository.save(mergeRequest);
|
||||||
|
|
||||||
if (oldMergeRequest.isNotification()) {
|
|
||||||
final Project project = projectService.getByIdOrThrow(mergeRequest.getProjectId());
|
|
||||||
|
|
||||||
if (isChangedMr) {
|
|
||||||
notifyAboutStatus(oldMergeRequest, mergeRequest, project);
|
|
||||||
notifyAboutNewConflict(oldMergeRequest, mergeRequest, project);
|
|
||||||
notifyAboutResolveConflict(oldMergeRequest, mergeRequest, project);
|
|
||||||
notifyAboutUpdate(oldMergeRequest, mergeRequest, project);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isChangedLinkedEntity) {
|
|
||||||
notifyReviewer(reviewerChanged, mergeRequest, project);
|
|
||||||
notifyAssignee(assigneeChanged, oldMergeRequest, mergeRequest, project);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return repository.save(mergeRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
return oldMergeRequest;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO [05.12.2022|uPagge]: Добавить уведомление, если происходит удаление
|
|
||||||
|
|
||||||
private void notifyAssignee(AssigneeChanged assigneeChanged, MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) {
|
|
||||||
switch (assigneeChanged) {
|
|
||||||
case BECOME ->
|
|
||||||
sendNotifyNewAssignee(mergeRequest, project.getName(), getAssignee(oldMergeRequest).map(Person::getName).orElse(null));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//TODO [05.12.2022|uPagge]: Добавить уведомление, если происходит удаление ревьювера
|
|
||||||
|
|
||||||
private void notifyReviewer(ReviewerChanged reviewerChanged, MergeRequest mergeRequest, Project project) {
|
|
||||||
switch (reviewerChanged) {
|
|
||||||
case BECOME -> sendNotifyNewMrReview(mergeRequest, project.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
@@ -295,119 +192,8 @@ public class MergeRequestsServiceImpl implements MergeRequestsService {
|
|||||||
repository.notificationByProjectId(enable, projectIds);
|
repository.notificationByProjectId(enable, projectIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyAboutUpdate(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) {
|
private Optional<Person> getAssignee(MergeRequest mergeRequest) {
|
||||||
final Long botUserGitlabId = personInformation.getId();
|
return Optional.ofNullable(mergeRequest.getAssignee());
|
||||||
if (
|
|
||||||
!botUserGitlabId.equals(mergeRequest.getAuthor().getId()) // Автор MR не пользователь приложения
|
|
||||||
&& !oldMergeRequest.getDateLastCommit().equals(mergeRequest.getDateLastCommit()) // Изменилась дата последнего коммита
|
|
||||||
&& !mergeRequest.isConflict() // MR не находится в состоянии конфликта
|
|
||||||
&& !botUserGitlabId.equals(oldMergeRequest.getAuthor().getId()) // и MR создан НЕ пользователем бота
|
|
||||||
) {
|
|
||||||
long allTask = 0;
|
|
||||||
long resolvedTask = 0;
|
|
||||||
long allYouTasks = 0;
|
|
||||||
long resolvedYouTask = 0;
|
|
||||||
|
|
||||||
final List<Discussion> discussions = discussionService.getAllByMergeRequestId(oldMergeRequest.getId());
|
|
||||||
for (Discussion discussion : discussions) {
|
|
||||||
if (checkNotNull(discussion.getResponsible())) {
|
|
||||||
final boolean isBotUserAuthorDiscussion = botUserGitlabId.equals(discussion.getFirstNote().getAuthor().getId());
|
|
||||||
allTask += 1;
|
|
||||||
if (isBotUserAuthorDiscussion) {
|
|
||||||
allYouTasks += 1;
|
|
||||||
}
|
|
||||||
if (TRUE.equals(discussion.getResolved())) {
|
|
||||||
resolvedTask += 1;
|
|
||||||
if (isBotUserAuthorDiscussion) {
|
|
||||||
resolvedYouTask += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final UpdateMrNotify.UpdateMrNotifyBuilder notifyBuilder = UpdateMrNotify.builder()
|
|
||||||
.mrId(oldMergeRequest.getId())
|
|
||||||
.author(oldMergeRequest.getAuthor().getName())
|
|
||||||
.name(oldMergeRequest.getTitle())
|
|
||||||
.projectName(project.getName())
|
|
||||||
.url(oldMergeRequest.getWebUrl())
|
|
||||||
.allTasks(allTask)
|
|
||||||
.milestone(mergeRequest.getMilestone())
|
|
||||||
.allResolvedTasks(resolvedTask)
|
|
||||||
.personTasks(allYouTasks)
|
|
||||||
.personResolvedTasks(resolvedYouTask);
|
|
||||||
|
|
||||||
if (oldMergeRequest.isConflict() && !mergeRequest.isConflict()) {
|
|
||||||
notifyBuilder.comment("The conflict has been resolved");
|
|
||||||
}
|
|
||||||
|
|
||||||
notifyService.send(notifyBuilder.build());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void notifyAboutNewConflict(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) {
|
|
||||||
final Long gitlabUserId = personInformation.getId();
|
|
||||||
if (
|
|
||||||
!oldMergeRequest.isConflict() // У старого MR не было конфликта
|
|
||||||
&& mergeRequest.isConflict() // А у нового есть
|
|
||||||
&& gitlabUserId.equals(oldMergeRequest.getAuthor().getId()) // и MR создан пользователем бота
|
|
||||||
) {
|
|
||||||
notifyService.send(
|
|
||||||
ConflictMrNotify.builder()
|
|
||||||
.mrId(oldMergeRequest.getId())
|
|
||||||
.sourceBranch(oldMergeRequest.getSourceBranch())
|
|
||||||
.name(mergeRequest.getTitle())
|
|
||||||
.url(mergeRequest.getWebUrl())
|
|
||||||
.projectKey(project.getName())
|
|
||||||
.milestone(mergeRequest.getMilestone())
|
|
||||||
.build()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyAboutResolveConflict(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) {
|
|
||||||
final Long gitlabUserId = personInformation.getId();
|
|
||||||
if (oldMergeRequest.isConflict() && !mergeRequest.isConflict()) {
|
|
||||||
// проверяем даты коммитов, так как при пуше в target ветку MR у которого есть конфликт, конфликт на время пропадает. Судя по всему GitLab после пуша заново проверяет вероятность конфликта. Чаще всего конфликт никуда не девается.
|
|
||||||
if (oldMergeRequest.getDateLastCommit().equals(mergeRequest.getDateLastCommit())) {
|
|
||||||
mergeRequest.setConflict(true);
|
|
||||||
} else {
|
|
||||||
if (gitlabUserId.equals(oldMergeRequest.getAuthor().getId())) {
|
|
||||||
notifyService.send(
|
|
||||||
ConflictResolveMrNotify.builder()
|
|
||||||
.mrId(oldMergeRequest.getId())
|
|
||||||
.sourceBranch(oldMergeRequest.getSourceBranch())
|
|
||||||
.name(mergeRequest.getTitle())
|
|
||||||
.url(mergeRequest.getWebUrl())
|
|
||||||
.projectKey(project.getName())
|
|
||||||
.milestone(mergeRequest.getMilestone())
|
|
||||||
.build()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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) // статус изменился
|
|
||||||
&& gitlabUserId.equals(oldMergeRequest.getAuthor().getId()) // создатель MR является пользователем бота
|
|
||||||
) {
|
|
||||||
notifyService.send(
|
|
||||||
StatusMrNotify.builder()
|
|
||||||
.mrId(oldMergeRequest.getId())
|
|
||||||
.name(newMergeRequest.getTitle())
|
|
||||||
.url(oldMergeRequest.getWebUrl())
|
|
||||||
.projectName(project.getName())
|
|
||||||
.newStatus(newStatus)
|
|
||||||
.oldStatus(oldStatus)
|
|
||||||
.milestone(newMergeRequest.getMilestone())
|
|
||||||
.build()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
package dev.struchkov.bot.gitlab.core.service;
|
package dev.struchkov.bot.gitlab.core.service;
|
||||||
|
|
||||||
import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
|
import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
|
||||||
import dev.struchkov.bot.gitlab.context.domain.PersonInformation;
|
|
||||||
import dev.struchkov.bot.gitlab.context.domain.PipelineStatus;
|
import dev.struchkov.bot.gitlab.context.domain.PipelineStatus;
|
||||||
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
|
|
||||||
import dev.struchkov.bot.gitlab.context.domain.entity.Pipeline;
|
import dev.struchkov.bot.gitlab.context.domain.entity.Pipeline;
|
||||||
import dev.struchkov.bot.gitlab.context.domain.notify.pipeline.PipelineNotify;
|
|
||||||
import dev.struchkov.bot.gitlab.context.repository.PipelineRepository;
|
import dev.struchkov.bot.gitlab.context.repository.PipelineRepository;
|
||||||
import dev.struchkov.bot.gitlab.context.service.NotifyService;
|
|
||||||
import dev.struchkov.bot.gitlab.context.service.PipelineService;
|
import dev.struchkov.bot.gitlab.context.service.PipelineService;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@@ -20,12 +17,9 @@ import java.util.List;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.CANCELED;
|
import static dev.struchkov.bot.gitlab.context.domain.event.NewPipelineEvent.newPipeline;
|
||||||
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.FAILED;
|
import static dev.struchkov.bot.gitlab.context.domain.event.UpdatePipelineEvent.updatePipeline;
|
||||||
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.SKIPPED;
|
|
||||||
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.SUCCESS;
|
|
||||||
import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException;
|
import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException;
|
||||||
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Реализация сервиса для работы с пайплайнами.
|
* Реализация сервиса для работы с пайплайнами.
|
||||||
@@ -37,19 +31,15 @@ import static dev.struchkov.haiti.utils.Checker.checkNotNull;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class PipelineServiceImpl implements PipelineService {
|
public class PipelineServiceImpl implements PipelineService {
|
||||||
|
|
||||||
// Статусы пайплайнов, о которых нужно уведомить
|
private final ApplicationEventPublisher eventPublisher;
|
||||||
private static final Set<PipelineStatus> notificationStatus = Set.of(FAILED, SUCCESS, CANCELED, SKIPPED);
|
|
||||||
|
|
||||||
private final NotifyService notifyService;
|
|
||||||
private final PipelineRepository repository;
|
private final PipelineRepository repository;
|
||||||
|
|
||||||
private final PersonInformation personInformation;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public Pipeline create(@NonNull Pipeline pipeline) {
|
public Pipeline create(@NonNull Pipeline pipeline) {
|
||||||
final Pipeline newPipeline = repository.save(pipeline);
|
final Pipeline newPipeline = repository.save(pipeline);
|
||||||
notifyNewPipeline(pipeline, PipelineStatus.NULL);
|
eventPublisher.publishEvent(newPipeline(newPipeline));
|
||||||
return newPipeline;
|
return newPipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,21 +51,6 @@ public class PipelineServiceImpl implements PipelineService {
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyNewPipeline(Pipeline pipeline, PipelineStatus oldStatus) {
|
|
||||||
if (isNeedNotifyNewPipeline(pipeline)) {
|
|
||||||
notifyService.send(
|
|
||||||
PipelineNotify.builder()
|
|
||||||
.projectId(pipeline.getProjectId())
|
|
||||||
.newStatus(pipeline.getStatus())
|
|
||||||
.pipelineId(pipeline.getId())
|
|
||||||
.refName(pipeline.getRef())
|
|
||||||
.webUrl(pipeline.getWebUrl())
|
|
||||||
.oldStatus(oldStatus)
|
|
||||||
.build()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pipeline update(@NonNull Pipeline pipeline) {
|
public Pipeline update(@NonNull Pipeline pipeline) {
|
||||||
final Pipeline oldPipeline = repository.findById(pipeline.getId())
|
final Pipeline oldPipeline = repository.findById(pipeline.getId())
|
||||||
@@ -84,7 +59,7 @@ public class PipelineServiceImpl implements PipelineService {
|
|||||||
pipeline.setProjectId(oldPipeline.getProjectId());
|
pipeline.setProjectId(oldPipeline.getProjectId());
|
||||||
|
|
||||||
if (!oldPipeline.getUpdated().equals(pipeline.getUpdated())) {
|
if (!oldPipeline.getUpdated().equals(pipeline.getUpdated())) {
|
||||||
notifyNewPipeline(pipeline, oldPipeline.getStatus());
|
eventPublisher.publishEvent(updatePipeline(oldPipeline.toBuilder().build(), pipeline));
|
||||||
return repository.save(pipeline);
|
return repository.save(pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,14 +73,6 @@ public class PipelineServiceImpl implements PipelineService {
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isNeedNotifyNewPipeline(@NonNull Pipeline pipeline) {
|
|
||||||
final Person personPipelineCreator = pipeline.getPerson();
|
|
||||||
return notificationStatus.contains(pipeline.getStatus()) // Пайплайн имеет статус необходимый для уведомления
|
|
||||||
&& checkNotNull(personPipelineCreator) // Создатель пайплайна не null
|
|
||||||
&& personInformation.getId().equals(personPipelineCreator.getId()) // Пользователь приложения является инициатором пайплайна
|
|
||||||
&& LocalDateTime.now().minusDays(1).isBefore(pipeline.getCreated()); // Пайплан был создан не более 24 часов назад
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Pipeline> getAllByStatuses(@NonNull Set<PipelineStatus> statuses) {
|
public List<Pipeline> getAllByStatuses(@NonNull Set<PipelineStatus> statuses) {
|
||||||
return repository.findAllByStatuses(statuses);
|
return repository.findAllByStatuses(statuses);
|
||||||
|
|||||||
@@ -2,13 +2,11 @@ package dev.struchkov.bot.gitlab.core.service;
|
|||||||
|
|
||||||
import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
|
import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
|
||||||
import dev.struchkov.bot.gitlab.context.domain.entity.Project;
|
import dev.struchkov.bot.gitlab.context.domain.entity.Project;
|
||||||
import dev.struchkov.bot.gitlab.context.domain.notify.project.NewProjectNotify;
|
|
||||||
import dev.struchkov.bot.gitlab.context.repository.ProjectRepository;
|
import dev.struchkov.bot.gitlab.context.repository.ProjectRepository;
|
||||||
import dev.struchkov.bot.gitlab.context.service.NotifyService;
|
|
||||||
import dev.struchkov.bot.gitlab.context.service.PersonService;
|
|
||||||
import dev.struchkov.bot.gitlab.context.service.ProjectService;
|
import dev.struchkov.bot.gitlab.context.service.ProjectService;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@@ -17,6 +15,7 @@ import java.util.Optional;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static dev.struchkov.bot.gitlab.context.domain.event.NewProjectEvent.newProject;
|
||||||
import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException;
|
import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,8 +27,7 @@ public class ProjectServiceImpl implements ProjectService {
|
|||||||
|
|
||||||
private final ProjectRepository repository;
|
private final ProjectRepository repository;
|
||||||
|
|
||||||
private final NotifyService notifyService;
|
private final ApplicationEventPublisher eventPublisher;
|
||||||
private final PersonService personService;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
@@ -37,8 +35,7 @@ public class ProjectServiceImpl implements ProjectService {
|
|||||||
final Project newProject = repository.save(project);
|
final Project newProject = repository.save(project);
|
||||||
|
|
||||||
if (sendNotify) {
|
if (sendNotify) {
|
||||||
final String authorName = personService.getByIdOrThrown(newProject.getCreatorId()).getName();
|
eventPublisher.publishEvent(newProject(project));
|
||||||
notifyAboutNewProject(newProject, authorName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return newProject;
|
return newProject;
|
||||||
@@ -111,18 +108,4 @@ public class ProjectServiceImpl implements ProjectService {
|
|||||||
repository.processing(enable, projectIds);
|
repository.processing(enable, projectIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyAboutNewProject(Project newProject, String authorName) {
|
|
||||||
notifyService.send(
|
|
||||||
NewProjectNotify.builder()
|
|
||||||
.projectId(newProject.getId())
|
|
||||||
.projectDescription(newProject.getDescription())
|
|
||||||
.projectName(newProject.getName())
|
|
||||||
.projectUrl(newProject.getWebUrl())
|
|
||||||
.sshUrlToRepo(newProject.getSshUrlToRepo())
|
|
||||||
.httpUrlToRepo(newProject.getHttpUrlToRepo())
|
|
||||||
.authorName(authorName)
|
|
||||||
.build()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user