Рефакторинг проектов и MR

This commit is contained in:
Struchkov Mark 2022-12-05 16:33:23 +03:00
parent 26a2e14b81
commit 55b1565089
18 changed files with 345 additions and 153 deletions

View File

@ -2,22 +2,29 @@ package dev.struchkov.bot.gitlab.context.domain.entity;
import dev.struchkov.bot.gitlab.context.domain.MergeRequestState; import dev.struchkov.bot.gitlab.context.domain.MergeRequestState;
import dev.struchkov.haiti.utils.fieldconstants.annotation.FieldNames; import dev.struchkov.haiti.utils.fieldconstants.annotation.FieldNames;
import dev.struchkov.haiti.utils.fieldconstants.domain.Mode;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import javax.persistence.CascadeType;
import javax.persistence.CollectionTable; import javax.persistence.CollectionTable;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.ElementCollection; import javax.persistence.ElementCollection;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.EnumType; import javax.persistence.EnumType;
import javax.persistence.Enumerated; import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table; import javax.persistence.Table;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
/** /**
@ -28,7 +35,7 @@ import java.util.Set;
@Getter @Getter
@Setter @Setter
@Entity @Entity
@FieldNames @FieldNames(mode = {Mode.TABLE, Mode.SIMPLE})
@Table(name = "merge_request") @Table(name = "merge_request")
@EqualsAndHashCode(onlyExplicitlyIncluded = true) @EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class MergeRequest { public class MergeRequest {
@ -66,14 +73,26 @@ public class MergeRequest {
@Column(name = "conflict") @Column(name = "conflict")
private boolean conflict; private boolean conflict;
@ManyToOne @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.MERGE})
@JoinColumn(name = "author_id") @JoinColumn(name = "author_id")
private Person author; private Person author;
@ManyToOne @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.MERGE})
@JoinColumn(name = "assignee_id") @JoinColumn(name = "assignee_id")
private Person assignee; private Person assignee;
@OneToMany(
fetch = FetchType.LAZY,
cascade = {CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.MERGE},
orphanRemoval = true
)
@JoinTable(
name = "merge_request_reviewer",
joinColumns = @JoinColumn(name = "merge_request_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "person_id", referencedColumnName = "id")
)
private List<Person> reviewers = new ArrayList<>();
@Column(name = "target_branch") @Column(name = "target_branch")
private String targetBranch; private String targetBranch;

View File

@ -1,5 +1,8 @@
package dev.struchkov.bot.gitlab.context.domain.entity; package dev.struchkov.bot.gitlab.context.domain.entity;
import dev.struchkov.haiti.utils.fieldconstants.annotation.FieldNames;
import dev.struchkov.haiti.utils.fieldconstants.domain.Mode;
import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
@ -14,10 +17,13 @@ import javax.persistence.Table;
@Entity @Entity
@Getter @Getter
@Setter @Setter
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Table(name = "person") @Table(name = "person")
@FieldNames(mode = {Mode.TABLE, Mode.SIMPLE})
public class Person { public class Person {
@Id @Id
@EqualsAndHashCode.Include
@Column(name = "id") @Column(name = "id")
private Long id; private Long id;

View File

@ -48,7 +48,7 @@ public class NewPrNotify extends PrNotify {
labelText = "\n\n" + labelText; labelText = "\n\n" + labelText;
} }
return MessageFormat.format( return MessageFormat.format(
"{0} *New MergeRequest | {1}*{2}[{3}]({4}){5}{2}{9}: {10} {12} {11}", "{0} *New merge request for review | {1}*{2}[{3}]({4}){5}{2}{9}: {10} {12} {11}\n{7}: {8}",
Smile.FUN.getValue(), Smile.FUN.getValue(),
projectName, projectName,
Smile.HR.getValue(), Smile.HR.getValue(),

View File

@ -18,6 +18,8 @@ public interface MergeRequestsService {
MergeRequest update(@NonNull MergeRequest mergeRequest); MergeRequest update(@NonNull MergeRequest mergeRequest);
List<MergeRequest> updateAll(@NonNull List<MergeRequest> mergeRequests);
/** /**
* Получить все идентификаторы вместе со статусами. * Получить все идентификаторы вместе со статусами.
* *

View File

@ -2,16 +2,20 @@ package dev.struchkov.bot.gitlab.core.service.convert;
import dev.struchkov.bot.gitlab.context.domain.MergeRequestState; import dev.struchkov.bot.gitlab.context.domain.MergeRequestState;
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.Person;
import dev.struchkov.bot.gitlab.sdk.domain.MergeRequestJson; import dev.struchkov.bot.gitlab.sdk.domain.MergeRequestJson;
import dev.struchkov.bot.gitlab.sdk.domain.MergeRequestStateJson; import dev.struchkov.bot.gitlab.sdk.domain.MergeRequestStateJson;
import dev.struchkov.bot.gitlab.sdk.domain.PersonJson;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
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.haiti.utils.Checker.checkNotEmpty; import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
/** /**
* @author upagge 15.01.2021 * @author upagge 15.01.2021
@ -35,23 +39,36 @@ public class MergeRequestJsonConverter implements Converter<MergeRequestJson, Me
mergeRequest.setState(convertState(source.getState())); mergeRequest.setState(convertState(source.getState()));
mergeRequest.setProjectId(source.getProjectId()); mergeRequest.setProjectId(source.getProjectId());
mergeRequest.setWebUrl(source.getWebUrl()); mergeRequest.setWebUrl(source.getWebUrl());
mergeRequest.setLabels(convertLabels(source.getLabels()));
if (source.getAssignee() != null) { convertLabels(mergeRequest, source.getLabels());
convertReviewers(mergeRequest, source.getReviewers());
if (checkNotNull(source.getAssignee())) {
mergeRequest.setAssignee(convertPerson.convert(source.getAssignee())); mergeRequest.setAssignee(convertPerson.convert(source.getAssignee()));
} }
mergeRequest.setAuthor(convertPerson.convert(source.getAuthor())); mergeRequest.setAuthor(convertPerson.convert(source.getAuthor()));
mergeRequest.setSourceBranch(source.getSourceBranch()); mergeRequest.setSourceBranch(source.getSourceBranch());
mergeRequest.setTargetBranch(source.getTargetBranch()); mergeRequest.setTargetBranch(source.getTargetBranch());
return mergeRequest; return mergeRequest;
} }
private static Set<String> convertLabels(Set<String> source) { private void convertReviewers(MergeRequest mergeRequest, List<PersonJson> jsonReviewers) {
if (checkNotEmpty(source)) { if (checkNotEmpty(jsonReviewers)) {
return source.stream() final List<Person> reviewers = jsonReviewers.stream()
.map(label -> label.replaceAll("-", "_")) .map(convertPerson::convert)
.collect(Collectors.toSet()); .toList();
mergeRequest.setReviewers(reviewers);
}
}
private static void convertLabels(MergeRequest mergeRequest, Set<String> source) {
if (checkNotEmpty(source)) {
final Set<String> labels = source.stream()
.map(label -> label.replace("-", "_"))
.collect(Collectors.toSet());
mergeRequest.setLabels(labels);
} }
return null;
} }
private MergeRequestState convertState(MergeRequestStateJson state) { private MergeRequestState convertState(MergeRequestStateJson state) {

View File

@ -2,6 +2,7 @@ package dev.struchkov.bot.gitlab.core.service.convert;
import dev.struchkov.bot.gitlab.context.domain.entity.Project; import dev.struchkov.bot.gitlab.context.domain.entity.Project;
import dev.struchkov.bot.gitlab.sdk.domain.ProjectJson; import dev.struchkov.bot.gitlab.sdk.domain.ProjectJson;
import lombok.RequiredArgsConstructor;
import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -9,6 +10,7 @@ import org.springframework.stereotype.Component;
* @author upagge 14.01.2021 * @author upagge 14.01.2021
*/ */
@Component @Component
@RequiredArgsConstructor
public class ProjectJsonConverter implements Converter<ProjectJson, Project> { public class ProjectJsonConverter implements Converter<ProjectJson, Project> {
@Override @Override

View File

@ -6,6 +6,7 @@ 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.entity.Discussion; 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.Person;
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.filter.MergeRequestFilter; import dev.struchkov.bot.gitlab.context.domain.filter.MergeRequestFilter;
import dev.struchkov.bot.gitlab.context.domain.notify.pullrequest.ConflictPrNotify; import dev.struchkov.bot.gitlab.context.domain.notify.pullrequest.ConflictPrNotify;
@ -16,7 +17,6 @@ import dev.struchkov.bot.gitlab.context.repository.MergeRequestRepository;
import dev.struchkov.bot.gitlab.context.service.DiscussionService; 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.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 dev.struchkov.bot.gitlab.core.service.impl.filter.MergeRequestFilterService; import dev.struchkov.bot.gitlab.core.service.impl.filter.MergeRequestFilterService;
import lombok.NonNull; import lombok.NonNull;
@ -24,6 +24,7 @@ import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@ -31,6 +32,9 @@ import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
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.checkNotNull;
import static dev.struchkov.haiti.utils.Checker.checkNull;
import static java.lang.Boolean.TRUE; import static java.lang.Boolean.TRUE;
@Service @Service
@ -39,7 +43,6 @@ public class MergeRequestsServiceImpl implements MergeRequestsService {
private final NotifyService notifyService; private final NotifyService notifyService;
private final MergeRequestRepository repository; private final MergeRequestRepository repository;
private final PersonService personService;
private final MergeRequestFilterService filterService; private final MergeRequestFilterService filterService;
private final ProjectService projectService; private final ProjectService projectService;
private final DiscussionService discussionService; private final DiscussionService discussionService;
@ -47,63 +50,109 @@ public class MergeRequestsServiceImpl implements MergeRequestsService {
private final PersonInformation personInformation; private final PersonInformation personInformation;
@Override @Override
@Transactional
public MergeRequest create(@NonNull MergeRequest mergeRequest) { public MergeRequest create(@NonNull MergeRequest mergeRequest) {
if (mergeRequest.getAssignee() != null) {
personService.create(mergeRequest.getAssignee());
}
personService.create(mergeRequest.getAuthor());
mergeRequest.setNotification(true); mergeRequest.setNotification(true);
final MergeRequest newMergeRequest = repository.save(mergeRequest); final MergeRequest newMergeRequest = repository.save(mergeRequest);
notifyNewPr(newMergeRequest); notifyNewMergeRequest(newMergeRequest);
return newMergeRequest; return newMergeRequest;
} }
private void notifyNewPr(MergeRequest newMergeRequest) { /**
if (!personInformation.getId().equals(newMergeRequest.getAuthor().getId())) { * Уведомление о новом MergeRequest.
*
* @param savedMergeRequest сохраненный в базу новый MergeRequest.
*/
private void notifyNewMergeRequest(MergeRequest savedMergeRequest) {
notifyUserAboutNewPullRequestIfHeIsReviewer(savedMergeRequest);
notifyUserAboutNewPullRequestIfHeIsAssignee(savedMergeRequest);
}
final String projectName = projectService.getByIdOrThrow(newMergeRequest.getProjectId()).getName(); private void notifyUserAboutNewPullRequestIfHeIsAssignee(MergeRequest savedMergeRequest) {
if (!newMergeRequest.isConflict()) { final Long gitlabUserId = personInformation.getId();
notifyService.send( final Person assignee = savedMergeRequest.getAssignee();
NewPrNotify.builder() final Person author = savedMergeRequest.getAuthor();
.projectName(projectName)
.labels(newMergeRequest.getLabels()) if (checkNotNull(assignee)) {
.author(newMergeRequest.getAuthor().getName()) if (gitlabUserId.equals(assignee.getId()) && !isAuthorSameAssignee(author, assignee)) {
.description(newMergeRequest.getDescription()) final String projectName = projectService.getByIdOrThrow(savedMergeRequest.getProjectId()).getName();
.title(newMergeRequest.getTitle()) if (!savedMergeRequest.isConflict()) {
.url(newMergeRequest.getWebUrl()) //TODO [05.12.2022|uPagge]: Заменить уведомление. Нужно создать новое уведомление, если пользователя назначали ответственным
.targetBranch(newMergeRequest.getTargetBranch()) notifyService.send(
.sourceBranch(newMergeRequest.getSourceBranch()) NewPrNotify.builder()
.build() .projectName(projectName)
); .labels(savedMergeRequest.getLabels())
.author(author.getName())
.description(savedMergeRequest.getDescription())
.title(savedMergeRequest.getTitle())
.url(savedMergeRequest.getWebUrl())
.targetBranch(savedMergeRequest.getTargetBranch())
.sourceBranch(savedMergeRequest.getSourceBranch())
.build()
);
}
} }
}
}
/**
* Создатель MR является ответственным за этот MR
*
* @return true, если автор и ответственный один и тот же человек.
*/
private boolean isAuthorSameAssignee(Person author, Person assignee) {
return author.getId().equals(assignee.getId());
}
private void notifyUserAboutNewPullRequestIfHeIsReviewer(MergeRequest savedMergeRequest) {
final List<Person> reviewers = savedMergeRequest.getReviewers();
final Long gitlabUserId = personInformation.getId();
if (checkNotEmpty(reviewers)) {
final boolean isUserInReviewers = reviewers.stream()
.anyMatch(reviewer -> gitlabUserId.equals(reviewer.getId()));
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()
);
}
}
} }
} }
@Override @Override
public MergeRequest update(@NonNull MergeRequest mergeRequest) { public MergeRequest update(@NonNull MergeRequest mergeRequest) {
if (mergeRequest.getAssignee() != null) {
personService.create(mergeRequest.getAssignee());
}
personService.create(mergeRequest.getAuthor());
final MergeRequest oldMergeRequest = repository.findById(mergeRequest.getId()) final MergeRequest oldMergeRequest = repository.findById(mergeRequest.getId())
.orElseThrow(notFoundException("МержРеквест не найден")); .orElseThrow(notFoundException("MergeRequest не найден"));
if (mergeRequest.getNotification() == null) { final Boolean notification = mergeRequest.getNotification();
if (checkNull(notification)) {
mergeRequest.setNotification(oldMergeRequest.getNotification()); mergeRequest.setNotification(oldMergeRequest.getNotification());
} }
if (!oldMergeRequest.getUpdatedDate().equals(mergeRequest.getUpdatedDate()) || oldMergeRequest.isConflict() != mergeRequest.isConflict()) { if (
!oldMergeRequest.getUpdatedDate().equals(mergeRequest.getUpdatedDate())
|| oldMergeRequest.isConflict() != mergeRequest.isConflict()
) {
final Project project = projectService.getByIdOrThrow(mergeRequest.getProjectId()); final Project project = projectService.getByIdOrThrow(mergeRequest.getProjectId());
if (TRUE.equals(oldMergeRequest.getNotification())) { if (TRUE.equals(oldMergeRequest.getNotification())) {
notifyStatus(oldMergeRequest, mergeRequest, project); notifyAboutStatus(oldMergeRequest, mergeRequest, project);
notifyConflict(oldMergeRequest, mergeRequest, project); notifyAboutConflict(oldMergeRequest, mergeRequest, project);
notifyUpdate(oldMergeRequest, mergeRequest, project); notifyUpdate(oldMergeRequest, mergeRequest, project);
} }
@ -112,76 +161,11 @@ public class MergeRequestsServiceImpl implements MergeRequestsService {
return oldMergeRequest; return oldMergeRequest;
} }
private void notifyUpdate(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) { @Override
if ( public List<MergeRequest> updateAll(@NonNull List<MergeRequest> mergeRequests) {
!personInformation.getId().equals(mergeRequest.getAuthor().getId()) return mergeRequests.stream()
&& !oldMergeRequest.getDateLastCommit().equals(mergeRequest.getDateLastCommit()) .map(this::update)
&& !mergeRequest.isConflict() .collect(Collectors.toList());
) {
final List<Discussion> discussions = discussionService.getAllByMergeRequestId(oldMergeRequest.getId())
.stream()
.filter(discussion -> Objects.nonNull(discussion.getResponsible()))
.toList();
final long allTask = discussions.size();
final long resolvedTask = discussions.stream()
.filter(Discussion::getResolved)
.count();
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();
notifyService.send(
UpdatePrNotify.builder()
.author(oldMergeRequest.getAuthor().getName())
.name(oldMergeRequest.getTitle())
.projectKey(project.getName())
.url(oldMergeRequest.getWebUrl())
.allTasks(allTask)
.allResolvedTasks(resolvedTask)
.personTasks(allYouTasks)
.personResolvedTasks(resolvedYouTask)
.build()
);
}
}
protected void notifyConflict(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) {
if (
!oldMergeRequest.isConflict()
&& mergeRequest.isConflict()
&& personInformation.getId().equals(oldMergeRequest.getAuthor().getId())
) {
notifyService.send(
ConflictPrNotify.builder()
.sourceBranch(oldMergeRequest.getSourceBranch())
.name(mergeRequest.getTitle())
.url(mergeRequest.getWebUrl())
.projectKey(project.getName())
.build()
);
}
}
protected void notifyStatus(MergeRequest oldMergeRequest, MergeRequest newMergeRequest, Project project) {
final MergeRequestState oldStatus = oldMergeRequest.getState();
final MergeRequestState newStatus = newMergeRequest.getState();
if (
!oldStatus.equals(newStatus)
&& oldMergeRequest.getAuthor().getId().equals(personInformation.getId())
) {
notifyService.send(
StatusPrNotify.builder()
.name(newMergeRequest.getTitle())
.url(oldMergeRequest.getWebUrl())
.projectName(project.getName())
.newStatus(newStatus)
.oldStatus(oldStatus)
.build()
);
}
} }
@Override @Override
@ -225,4 +209,75 @@ public class MergeRequestsServiceImpl implements MergeRequestsService {
repository.deleteByIds(mergeRequestIds); repository.deleteByIds(mergeRequestIds);
} }
private void notifyUpdate(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) {
if (
!personInformation.getId().equals(mergeRequest.getAuthor().getId())
&& !oldMergeRequest.getDateLastCommit().equals(mergeRequest.getDateLastCommit())
&& !mergeRequest.isConflict()
) {
final List<Discussion> discussions = discussionService.getAllByMergeRequestId(oldMergeRequest.getId())
.stream()
.filter(discussion -> Objects.nonNull(discussion.getResponsible()))
.toList();
final long allTask = discussions.size();
final long resolvedTask = discussions.stream()
.filter(Discussion::getResolved)
.count();
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();
notifyService.send(
UpdatePrNotify.builder()
.author(oldMergeRequest.getAuthor().getName())
.name(oldMergeRequest.getTitle())
.projectKey(project.getName())
.url(oldMergeRequest.getWebUrl())
.allTasks(allTask)
.allResolvedTasks(resolvedTask)
.personTasks(allYouTasks)
.personResolvedTasks(resolvedYouTask)
.build()
);
}
}
protected void notifyAboutConflict(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) {
if (
!oldMergeRequest.isConflict()
&& mergeRequest.isConflict()
&& personInformation.getId().equals(oldMergeRequest.getAuthor().getId())
) {
notifyService.send(
ConflictPrNotify.builder()
.sourceBranch(oldMergeRequest.getSourceBranch())
.name(mergeRequest.getTitle())
.url(mergeRequest.getWebUrl())
.projectKey(project.getName())
.build()
);
}
}
protected void notifyAboutStatus(MergeRequest oldMergeRequest, MergeRequest newMergeRequest, Project project) {
final MergeRequestState oldStatus = oldMergeRequest.getState();
final MergeRequestState newStatus = newMergeRequest.getState();
if (
!oldStatus.equals(newStatus)
&& oldMergeRequest.getAuthor().getId().equals(personInformation.getId())
) {
notifyService.send(
StatusPrNotify.builder()
.name(newMergeRequest.getTitle())
.url(oldMergeRequest.getWebUrl())
.projectName(project.getName())
.newStatus(newStatus)
.oldStatus(oldStatus)
.build()
);
}
}
} }

View File

@ -13,6 +13,7 @@ import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -34,12 +35,15 @@ public class ProjectServiceImpl implements ProjectService {
private final PersonInformation personInformation; private final PersonInformation personInformation;
@Override @Override
@Transactional
public Project create(@NonNull Project project) { public Project create(@NonNull Project project) {
final Project newProject = repository.save(project); final Project newProject = repository.save(project);
if (!personInformation.getId().equals(newProject.getCreatorId())) { final Long gitlabUserId = personInformation.getId();
if (!gitlabUserId.equals(newProject.getCreatorId())) {
final String authorName = personService.getByIdOrThrown(newProject.getCreatorId()).getName(); final String authorName = personService.getByIdOrThrown(newProject.getCreatorId()).getName();
sendNotifyNewProject(newProject, authorName); notifyAboutNewProject(newProject, authorName);
} }
return newProject; return newProject;
@ -87,7 +91,7 @@ public class ProjectServiceImpl implements ProjectService {
} }
} }
private void sendNotifyNewProject(Project newProject, String authorName) { private void notifyAboutNewProject(Project newProject, String authorName) {
notifyService.send( notifyService.send(
NewProjectNotify.builder() NewProjectNotify.builder()
.projectDescription(newProject.getDescription()) .projectDescription(newProject.getDescription())

View File

@ -4,6 +4,7 @@ import dev.struchkov.bot.gitlab.context.domain.ExistsContainer;
import dev.struchkov.bot.gitlab.context.domain.IdAndStatusPr; 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.entity.MergeRequest; 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.entity.Project;
import dev.struchkov.bot.gitlab.context.service.MergeRequestsService; import dev.struchkov.bot.gitlab.context.service.MergeRequestsService;
import dev.struchkov.bot.gitlab.context.service.ProjectService; import dev.struchkov.bot.gitlab.context.service.ProjectService;
@ -22,10 +23,15 @@ import org.springframework.stereotype.Service;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.List; import java.util.List;
import java.util.Map;
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 java.util.stream.Stream;
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
import static dev.struchkov.haiti.utils.network.HttpParse.ACCEPT; import static dev.struchkov.haiti.utils.network.HttpParse.ACCEPT;
@Slf4j @Slf4j
@ -47,19 +53,20 @@ public class MergeRequestParser {
public void parsingOldMergeRequest() { public void parsingOldMergeRequest() {
final Set<IdAndStatusPr> existIds = mergeRequestsService.getAllId(OLD_STATUSES); final Set<IdAndStatusPr> existIds = mergeRequestsService.getAllId(OLD_STATUSES);
for (IdAndStatusPr existId : existIds) { final List<MergeRequest> mergeRequests = existIds.stream()
final String mrUrl = MessageFormat.format(gitlabProperty.getUrlPullRequest(), existId.getProjectId(), existId.getTwoId()); .map(this::getMergeRequest)
final Optional<MergeRequestJson> json = HttpParse.request(mrUrl) .filter(Optional::isPresent)
.header(ACCEPT) .map(Optional::get)
.header(StringUtils.H_PRIVATE_TOKEN, personProperty.getToken()) .map(mergeRequestJson -> {
.execute(MergeRequestJson.class); final MergeRequest newMergeRequest = conversionService.convert(mergeRequestJson, MergeRequest.class);
final Optional<MergeRequest> mergeRequest = json parsingCommits(newMergeRequest);
.map(mergeRequestJson -> { return newMergeRequest;
final MergeRequest newMergeRequest = conversionService.convert(mergeRequestJson, MergeRequest.class); })
parsingCommits(newMergeRequest); .collect(Collectors.toList());
return newMergeRequest;
}); if (checkNotEmpty(mergeRequests)) {
mergeRequest.ifPresent(mergeRequestsService::update); personMapping(mergeRequests);
mergeRequestsService.updateAll(mergeRequests);
} }
} }
@ -83,7 +90,7 @@ public class MergeRequestParser {
int page = 1; int page = 1;
List<MergeRequestJson> mergeRequestJsons = getMergeRequestJsons(project, page); List<MergeRequestJson> mergeRequestJsons = getMergeRequestJsons(project, page);
while (!mergeRequestJsons.isEmpty()) { while (checkNotEmpty(mergeRequestJsons)) {
final Set<Long> jsonIds = mergeRequestJsons.stream() final Set<Long> jsonIds = mergeRequestJsons.stream()
.map(MergeRequestJson::getId) .map(MergeRequestJson::getId)
@ -99,6 +106,9 @@ public class MergeRequestParser {
return mergeRequest; return mergeRequest;
}) })
.toList(); .toList();
personMapping(newMergeRequests);
mergeRequestsService.createAll(newMergeRequests); mergeRequestsService.createAll(newMergeRequests);
} }
@ -106,6 +116,32 @@ public class MergeRequestParser {
} }
} }
private static void personMapping(List<MergeRequest> newMergeRequests) {
final Map<Long, Person> personMap = Stream.concat(
newMergeRequests.stream()
.flatMap(mergeRequest -> Stream.of(mergeRequest.getAssignee(), mergeRequest.getAuthor())),
newMergeRequests.stream()
.flatMap(mergeRequest -> mergeRequest.getReviewers().stream())
).distinct()
.filter(Objects::nonNull)
.collect(Collectors.toMap(Person::getId, p -> p));
for (MergeRequest newMergeRequest : newMergeRequests) {
newMergeRequest.setAuthor(personMap.get(newMergeRequest.getAuthor().getId()));
final Person assignee = newMergeRequest.getAssignee();
if (checkNotNull(assignee)) {
newMergeRequest.setAssignee(personMap.get(assignee.getId()));
}
newMergeRequest.setReviewers(
newMergeRequest.getReviewers().stream()
.map(reviewer -> personMap.get(reviewer.getId()))
.collect(Collectors.toList())
);
}
}
private void parsingCommits(MergeRequest mergeRequest) { private void parsingCommits(MergeRequest mergeRequest) {
final List<CommitJson> commitJson = HttpParse.request( final List<CommitJson> commitJson = HttpParse.request(
MessageFormat.format(gitlabProperty.getUrlCommit(), mergeRequest.getProjectId(), mergeRequest.getTwoId()) MessageFormat.format(gitlabProperty.getUrlCommit(), mergeRequest.getProjectId(), mergeRequest.getTwoId())
@ -125,4 +161,12 @@ public class MergeRequestParser {
.executeList(MergeRequestJson.class); .executeList(MergeRequestJson.class);
} }
private Optional<MergeRequestJson> getMergeRequest(IdAndStatusPr existId) {
final String mrUrl = MessageFormat.format(gitlabProperty.getUrlPullRequest(), existId.getProjectId(), existId.getTwoId());
return HttpParse.request(mrUrl)
.header(ACCEPT)
.header(StringUtils.H_PRIVATE_TOKEN, personProperty.getToken())
.execute(MergeRequestJson.class);
}
} }

View File

@ -15,6 +15,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Collection; import java.util.Collection;
@ -46,10 +47,12 @@ public class ProjectParser {
private final GitlabProperty gitlabProperty; private final GitlabProperty gitlabProperty;
private final PersonProperty personProperty; private final PersonProperty personProperty;
@Transactional
public void parseAllPrivateProject() { public void parseAllPrivateProject() {
parseProjects(PRIVATE); parseProjects(PRIVATE);
} }
@Transactional
public void parseAllProjectOwner() { public void parseAllProjectOwner() {
parseProjects(OWNER); parseProjects(OWNER);
} }
@ -80,6 +83,20 @@ public class ProjectParser {
} }
} }
public void parseByUrl(String projectUrl) {
final ProjectJson projectJson = HttpParse.request(projectUrl)
.header(ACCEPT)
.header(StringUtils.H_PRIVATE_TOKEN, personProperty.getToken())
.execute(ProjectJson.class)
.orElseThrow(convertException("Ошибка получения проекта"));
if (!projectService.existsById(projectJson.getId())) {
createNewPersons(List.of(projectJson));
final Project newProject = conversionService.convert(projectJson, Project.class);
projectService.create(newProject);
}
}
private void createNewPersons(List<ProjectJson> projectJsons) { private void createNewPersons(List<ProjectJson> projectJsons) {
final Set<Long> personCreatorId = projectJsons.stream() final Set<Long> personCreatorId = projectJsons.stream()
.map(ProjectJson::getCreatorId) .map(ProjectJson::getCreatorId)
@ -113,16 +130,4 @@ public class ProjectParser {
.executeList(ProjectJson.class); .executeList(ProjectJson.class);
} }
public void parseByUrl(String projectUrl) {
final Project project = HttpParse.request(projectUrl)
.header(ACCEPT)
.header(StringUtils.H_PRIVATE_TOKEN, personProperty.getToken())
.execute(ProjectJson.class)
.map(json -> conversionService.convert(json, Project.class))
.orElseThrow(convertException("Ошибка получения проекта"));
if (!projectService.existsById(project.getId())) {
projectService.create(project);
}
}
} }

View File

@ -32,7 +32,7 @@ gitlab-bot:
url-pull-request-close: "${GITLAB_URL}/api/v4/projects/{0,number,#}/merge_requests?state=closed&page={1, number, integer}&per_page=100" url-pull-request-close: "${GITLAB_URL}/api/v4/projects/{0,number,#}/merge_requests?state=closed&page={1, number, integer}&per_page=100"
url-pull-request-comment: "${GITLAB_URL}/api/v4/projects/{0,number,#}/merge_requests/{1,number,#}/notes?&page={2,number,#}&per_page=100" url-pull-request-comment: "${GITLAB_URL}/api/v4/projects/{0,number,#}/merge_requests/{1,number,#}/notes?&page={2,number,#}&per_page=100"
url-pull-request: "${GITLAB_URL}/api/v4/projects/{0,number,#}/merge_requests/{1,number,#}" url-pull-request: "${GITLAB_URL}/api/v4/projects/{0,number,#}/merge_requests/{1,number,#}"
url-merge-request-add: ${GITLAB_URL}/api/v4/projects/{0}%2F{1} url-merge-request-add: "${GITLAB_URL}/api/v4/projects/"
user-url: ${GITLAB_URL}/api/v4/user user-url: ${GITLAB_URL}/api/v4/user
users-url: ${GITLAB_URL}/api/v4/users users-url: ${GITLAB_URL}/api/v4/users
url-note: "{0}#note_{1,number,#}" url-note: "{0}#note_{1,number,#}"

View File

@ -1,8 +1,9 @@
<databaseChangeLog <databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.17.xsd">
<include file="v.1.0.0/changelog.xml" relativeToChangelogFile="true"/> <include file="v.1.0.0/changelog.xml" relativeToChangelogFile="true"/>
<include file="v.1.1.3/changelog.xml" relativeToChangelogFile="true"/>
</databaseChangeLog> </databaseChangeLog>

View File

@ -2,7 +2,7 @@
<databaseChangeLog <databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.6.xsd"> xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.17.xsd">
<changeSet id="2022-12-03-create-table-app-setting" author="uPagge"> <changeSet id="2022-12-03-create-table-app-setting" author="uPagge">
<insert tableName="app_setting"> <insert tableName="app_setting">

View File

@ -1,7 +1,7 @@
<databaseChangeLog <databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.17.xsd">
<changeSet id="2022-12-03-add-tab-v-1-0-0" author="uPagge"> <changeSet id="2022-12-03-add-tab-v-1-0-0" author="uPagge">
<tagDatabase tag="v.1.0.0"/> <tagDatabase tag="v.1.0.0"/>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.17.xsd">
<changeSet id="2022-12-05-create-table-reviewers" author="uPagge">
<createTable tableName="merge_request_reviewer">
<column name="merge_request_id" type="int">
<constraints nullable="false" foreignKeyName="fk_merge_request_reviewer_merge_request_id"
references="merge_request(id)" deleteCascade="true"/>
</column>
<column name="person_id" type="int">
<constraints nullable="false" foreignKeyName="fk_merge_request_reviewer_person_id"
references="person(id)" deleteCascade="true"/>
</column>
</createTable>
<addPrimaryKey tableName="merge_request_reviewer" columnNames="merge_request_id, person_id"/>
</changeSet>
</databaseChangeLog>

View File

@ -0,0 +1,12 @@
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.17.xsd">
<changeSet id="2022-12-05-add-tab-v-1-0-0" author="uPagge">
<tagDatabase tag="v.1.1.3"/>
</changeSet>
<include file="2022-12-05-add-reviewers.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@ -8,6 +8,7 @@ import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import lombok.Data; import lombok.Data;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
import java.util.Set; import java.util.Set;
/** /**
@ -40,6 +41,8 @@ public class MergeRequestJson {
private PersonJson author; private PersonJson author;
private PersonJson assignee; private PersonJson assignee;
private List<PersonJson> reviewers;
@JsonProperty("web_url") @JsonProperty("web_url")
private String webUrl; private String webUrl;

View File

@ -19,7 +19,6 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -92,9 +91,10 @@ public class MenuConfig {
public AnswerText<Mail> addNewProject() { public AnswerText<Mail> addNewProject() {
return AnswerText.<Mail>builder() return AnswerText.<Mail>builder()
.answer(mail -> { .answer(mail -> {
final List<String> urlList = Arrays.stream(mail.getText().split("/")).toList(); final String mailText = mail.getText();
int lastElement = urlList.size() - 1; final String projectUrl = gitlabProperty.getUrlMergeRequestAdd() + mailText.replace(gitlabProperty.getBaseUrl(), "")
final String projectUrl = MessageFormat.format(gitlabProperty.getUrlMergeRequestAdd(), urlList.get(lastElement - 1), urlList.get(lastElement)); .substring(1)
.replace("/", "%2F");
projectParser.parseByUrl(projectUrl); projectParser.parseByUrl(projectUrl);
return boxAnswer("Project added successfully"); return boxAnswer("Project added successfully");
}) })