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

This commit is contained in:
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();
final Person assignee = savedMergeRequest.getAssignee();
final Person author = savedMergeRequest.getAuthor();
if (checkNotNull(assignee)) {
if (gitlabUserId.equals(assignee.getId()) && !isAuthorSameAssignee(author, assignee)) {
final String projectName = projectService.getByIdOrThrow(savedMergeRequest.getProjectId()).getName();
if (!savedMergeRequest.isConflict()) {
//TODO [05.12.2022|uPagge]: Заменить уведомление. Нужно создать новое уведомление, если пользователя назначали ответственным
notifyService.send( notifyService.send(
NewPrNotify.builder() NewPrNotify.builder()
.projectName(projectName) .projectName(projectName)
.labels(newMergeRequest.getLabels()) .labels(savedMergeRequest.getLabels())
.author(newMergeRequest.getAuthor().getName()) .author(author.getName())
.description(newMergeRequest.getDescription()) .description(savedMergeRequest.getDescription())
.title(newMergeRequest.getTitle()) .title(savedMergeRequest.getTitle())
.url(newMergeRequest.getWebUrl()) .url(savedMergeRequest.getWebUrl())
.targetBranch(newMergeRequest.getTargetBranch()) .targetBranch(savedMergeRequest.getTargetBranch())
.sourceBranch(newMergeRequest.getSourceBranch()) .sourceBranch(savedMergeRequest.getSourceBranch())
.build() .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())
.execute(MergeRequestJson.class);
final Optional<MergeRequest> mergeRequest = json
.map(mergeRequestJson -> { .map(mergeRequestJson -> {
final MergeRequest newMergeRequest = conversionService.convert(mergeRequestJson, MergeRequest.class); final MergeRequest newMergeRequest = conversionService.convert(mergeRequestJson, MergeRequest.class);
parsingCommits(newMergeRequest); parsingCommits(newMergeRequest);
return newMergeRequest; return newMergeRequest;
}); })
mergeRequest.ifPresent(mergeRequestsService::update); .collect(Collectors.toList());
if (checkNotEmpty(mergeRequests)) {
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");
}) })