Merge pull request #27 from uPagge/develop

Develop
This commit is contained in:
Struchkov Mark 2022-12-09 11:02:44 +03:00 committed by GitHub
commit c798343973
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
57 changed files with 1011 additions and 471 deletions

View File

@ -2,7 +2,37 @@ stages:
- build - build
- deploy - deploy
build: build-develop:
image: maven:3.8.6-eclipse-temurin-17
stage: build
variables:
MAVEN_OPTS: "-Dmaven.repo.local=./.m2/repository"
only:
- develop
except:
- tags
script:
- 'mvn -U clean package'
artifacts:
paths:
- gitlab-app/target/gitlab-notification.jar
docker-build-develop:
image: upagge/docker-buildx:latest
stage: deploy
only:
- develop
except:
- tags
services:
- docker:dind
before_script:
- echo "$CI_REGISTRY_PASSWORD" | docker login $CI_REGISTRY --username $CI_REGISTRY_USER --password-stdin
script:
- docker buildx create --use
- docker buildx build --push --platform linux/amd64,linux/arm64/v8 -t "$CI_REGISTRY_IMAGE:develop" .
build-release:
image: maven:3.8.6-eclipse-temurin-17 image: maven:3.8.6-eclipse-temurin-17
stage: build stage: build
variables: variables:
@ -17,7 +47,7 @@ build:
paths: paths:
- gitlab-app/target/gitlab-notification.jar - gitlab-app/target/gitlab-notification.jar
docker-build: docker-build-release:
image: upagge/docker-buildx:latest image: upagge/docker-buildx:latest
stage: deploy stage: deploy
only: only:

View File

@ -34,4 +34,4 @@ COPY --from=app-build $BUILD_PATH/spring-boot-loader/ ./
COPY --from=app-build $BUILD_PATH/dependencies/ ./ COPY --from=app-build $BUILD_PATH/dependencies/ ./
COPY --from=app-build $BUILD_PATH/application/ ./ COPY --from=app-build $BUILD_PATH/application/ ./
ENTRYPOINT java -DTELEGRAM_BOT_USERNAME=$TELEGRAM_BOT_USERNAME -DTELEGRAM_BOT_TOKEN=$TELEGRAM_BOT_TOKEN -DTELEGRAM_PERSON_ID=$TELEGRAM_PERSON_ID -DDATASOURCE_URL=$DATASOURCE_URL -DDATASOURCE_PASSWORD=$DATASOURCE_PASSWORD -DDATASOURCE_USERNAME=$DATASOURCE_USERNAME -DGITLAB_PERSONAL_TOKEN=$GITLAB_PERSONAL_TOKEN -DGITLAB_URL=$GITLAB_URL -DGITLAB_REPLACE_URL=$GITLAB_REPLACE_URL org.springframework.boot.loader.JarLauncher ENTRYPOINT java -Dfile.encoding=UTF8 -Dconsole.encoding=UTF8 -DTELEGRAM_BOT_USERNAME=$TELEGRAM_BOT_USERNAME -DTELEGRAM_BOT_TOKEN=$TELEGRAM_BOT_TOKEN -DTELEGRAM_PERSON_ID=$TELEGRAM_PERSON_ID -DDATASOURCE_URL=$DATASOURCE_URL -DDATASOURCE_PASSWORD=$DATASOURCE_PASSWORD -DDATASOURCE_USERNAME=$DATASOURCE_USERNAME -DGITLAB_PERSONAL_TOKEN=$GITLAB_PERSONAL_TOKEN -DGITLAB_URL=$GITLAB_URL -DGITLAB_REPLACE_URL=$GITLAB_REPLACE_URL org.springframework.boot.loader.JarLauncher

View File

@ -0,0 +1,40 @@
package dev.struchkov.bot.gitlab.context.domain;
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
import static dev.struchkov.haiti.utils.Checker.checkNull;
@Getter
@RequiredArgsConstructor
public enum AssigneeChanged {
BECOME(true),
DELETED(true),
NOT_AFFECT_USER(true),
NOT_CHANGED(false);
private final boolean changed;
public static AssigneeChanged valueOf(Long gitlabUserId, Person oldAssignee, Person newAssignee) {
if (checkNull(oldAssignee) && checkNotNull(newAssignee) && gitlabUserId.equals(newAssignee.getId())) {
return AssigneeChanged.BECOME;
}
if (checkNotNull(oldAssignee) && checkNull(newAssignee) && gitlabUserId.equals(oldAssignee.getId())) {
return AssigneeChanged.DELETED;
}
if (checkNotNull(oldAssignee) && checkNotNull(newAssignee) && !oldAssignee.getId().equals(newAssignee.getId())) {
if (gitlabUserId.equals(oldAssignee.getId())) {
return AssigneeChanged.DELETED;
}
if (gitlabUserId.equals(newAssignee.getId())) {
return AssigneeChanged.BECOME;
}
return AssigneeChanged.NOT_AFFECT_USER;
}
return AssigneeChanged.NOT_CHANGED;
}
}

View File

@ -0,0 +1,41 @@
package dev.struchkov.bot.gitlab.context.domain;
import lombok.NonNull;
import java.util.Collections;
import java.util.List;
import java.util.Set;
public class ExistContainer<Entity, Key> {
protected final List<Entity> container;
protected final boolean allFound;
protected final Set<Key> idNoFound;
protected ExistContainer(List<Entity> container, boolean allFound, Set<Key> idNoFound) {
this.container = container;
this.allFound = allFound;
this.idNoFound = idNoFound;
}
public static <T, K> ExistContainer<T, K> allFind(@NonNull List<T> container) {
return new ExistContainer<>(container, true, Collections.emptySet());
}
public static <T, K> ExistContainer<T, K> notAllFind(@NonNull List<T> container, @NonNull Set<K> idNoFound) {
return new ExistContainer<>(container, false, idNoFound);
}
public List<Entity> getContainer() {
return container;
}
public boolean isAllFound() {
return allFound;
}
public Set<Key> getIdNoFound() {
return idNoFound;
}
}

View File

@ -1,40 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain;
import lombok.NonNull;
import java.util.Collection;
import java.util.Collections;
public class ExistsContainer<Entity, Key> {
protected final Collection<Entity> container;
protected final boolean allFound;
protected final Collection<Key> idNoFound;
protected ExistsContainer(Collection<Entity> container, boolean allFound, Collection<Key> idNoFound) {
this.container = container;
this.allFound = allFound;
this.idNoFound = idNoFound;
}
public static <T, K> ExistsContainer<T, K> allFind(@NonNull Collection<T> container) {
return new ExistsContainer<>(container, true, Collections.emptyList());
}
public static <T, K> ExistsContainer<T, K> notAllFind(@NonNull Collection<T> container, @NonNull Collection<K> idNoFound) {
return new ExistsContainer<>(container, false, idNoFound);
}
public Collection<Entity> getContainer() {
return container;
}
public boolean isAllFound() {
return allFound;
}
public Collection<Key> getIdNoFound() {
return idNoFound;
}
}

View File

@ -12,9 +12,10 @@ import lombok.Setter;
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@EqualsAndHashCode(of = "id") @EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class MessageSend { public class MessageSend {
@EqualsAndHashCode.Include
private Long id; private Long id;
private Long telegramId; private Long telegramId;
private String message; private String message;

View File

@ -0,0 +1,38 @@
package dev.struchkov.bot.gitlab.context.domain;
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Getter
@RequiredArgsConstructor
public enum ReviewerChanged {
BECOME(true),
DELETED(true),
NOT_AFFECT_USER(true),
NOT_CHANGED(false);
private final boolean changed;
public static ReviewerChanged valueOf(Long gitlabUserId, List<Person> oldReviewers, List<Person> newReviewers) {
final Map<Long, Person> oldMap = oldReviewers.stream().collect(Collectors.toMap(Person::getId, p -> p));
final Map<Long, Person> newMap = newReviewers.stream().collect(Collectors.toMap(Person::getId, p -> p));
if (!oldMap.keySet().equals(newMap.keySet())) {
if (oldMap.containsKey(gitlabUserId) && !newMap.containsKey(gitlabUserId)) {
return ReviewerChanged.DELETED;
}
if (!oldMap.containsKey(gitlabUserId) && newMap.containsKey(gitlabUserId)) {
return ReviewerChanged.BECOME;
}
return ReviewerChanged.NOT_AFFECT_USER;
}
return ReviewerChanged.NOT_CHANGED;
}
}

View File

@ -15,6 +15,7 @@ import javax.persistence.ManyToOne;
import javax.persistence.OneToMany; import javax.persistence.OneToMany;
import javax.persistence.Table; import javax.persistence.Table;
import java.util.List; import java.util.List;
import java.util.Optional;
/** /**
* @author upagge 11.02.2021 * @author upagge 11.02.2021
@ -30,14 +31,14 @@ public class Discussion {
@Column(name = "id") @Column(name = "id")
private String id; private String id;
@ManyToOne @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
@JoinColumn(name = "responsible_id") @JoinColumn(name = "responsible_id")
private Person responsible; private Person responsible;
@Column(name = "resolved") @Column(name = "resolved")
private Boolean resolved; private Boolean resolved;
@ManyToOne() @ManyToOne
@JoinTable( @JoinTable(
name = "discussion_merge_request", name = "discussion_merge_request",
joinColumns = @JoinColumn(name = "discussion_id"), joinColumns = @JoinColumn(name = "discussion_id"),
@ -50,7 +51,8 @@ public class Discussion {
fetch = FetchType.EAGER, fetch = FetchType.EAGER,
cascade = { cascade = {
CascadeType.PERSIST, CascadeType.PERSIST,
CascadeType.MERGE CascadeType.MERGE,
CascadeType.REFRESH
} }
) )
private List<Note> notes; private List<Note> notes;
@ -64,4 +66,13 @@ public class Discussion {
return this.notes.get(0); return this.notes.get(0);
} }
public Optional<Note> getPrevLastNote() {
final int size = notes.size();
if (size > 2) {
return Optional.of(notes.get(size - 2));
}
return Optional.empty();
}
} }

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,25 @@ public class MergeRequest {
@Column(name = "conflict") @Column(name = "conflict")
private boolean conflict; private boolean conflict;
@ManyToOne @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "author_id") @JoinColumn(name = "author_id")
private Person author; private Person author;
@ManyToOne @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "assignee_id") @JoinColumn(name = "assignee_id")
private Person assignee; private Person assignee;
@OneToMany(
fetch = FetchType.LAZY,
cascade = {CascadeType.PERSIST, CascadeType.MERGE}
)
@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

@ -12,6 +12,9 @@ import javax.persistence.ManyToOne;
import javax.persistence.Table; import javax.persistence.Table;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import static javax.persistence.CascadeType.MERGE;
import static javax.persistence.CascadeType.PERSIST;
@Getter @Getter
@Setter @Setter
@Entity @Entity
@ -20,7 +23,8 @@ import java.time.LocalDateTime;
public class Note { public class Note {
@Id @Id
@Column @Column(name = "id")
@EqualsAndHashCode.Include
private Long id; private Long id;
@Column(name = "type") @Column(name = "type")
@ -35,7 +39,7 @@ public class Note {
@Column(name = "updated_date") @Column(name = "updated_date")
private LocalDateTime updated; private LocalDateTime updated;
@ManyToOne @ManyToOne(cascade = {PERSIST, MERGE})
@JoinColumn(name = "author_id") @JoinColumn(name = "author_id")
private Person author; private Person author;
@ -57,7 +61,7 @@ public class Note {
@Column(name = "resolved") @Column(name = "resolved")
private Boolean resolved; private Boolean resolved;
@ManyToOne @ManyToOne(cascade = {PERSIST, MERGE})
@JoinColumn(name = "resolved_id") @JoinColumn(name = "resolved_id")
private Person resolvedBy; private Person resolvedBy;

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

@ -6,6 +6,7 @@ import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import javax.persistence.CascadeType;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.EnumType; import javax.persistence.EnumType;
@ -53,7 +54,7 @@ public class Pipeline {
@JoinColumn(name = "project_id") @JoinColumn(name = "project_id")
private Project project; private Project project;
@ManyToOne @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
@JoinColumn(name = "person_id") @JoinColumn(name = "person_id")
private Person person; private Person person;

View File

@ -2,7 +2,6 @@ package dev.struchkov.bot.gitlab.context.domain.notify.comment;
import dev.struchkov.bot.gitlab.context.domain.Answer; import dev.struchkov.bot.gitlab.context.domain.Answer;
import dev.struchkov.bot.gitlab.context.domain.notify.Notify; import dev.struchkov.bot.gitlab.context.domain.notify.Notify;
import dev.struchkov.bot.gitlab.context.service.AppSettingService;
import dev.struchkov.bot.gitlab.context.utils.Smile; import dev.struchkov.bot.gitlab.context.utils.Smile;
import dev.struchkov.haiti.utils.Strings; import dev.struchkov.haiti.utils.Strings;
import lombok.Builder; import lombok.Builder;

View File

@ -1,31 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.comment;
import dev.struchkov.bot.gitlab.context.domain.notify.Notify;
import dev.struchkov.bot.gitlab.context.utils.Smile;
import lombok.Builder;
import java.text.MessageFormat;
import static dev.struchkov.haiti.utils.Strings.escapeMarkdown;
public record CommentNotify(
String url,
String authorName,
String message
) implements Notify {
@Builder
public CommentNotify {
}
@Override
public String generateMessage() {
return MessageFormat.format(
"{0} *New mention* | [MR]({1}){2}*{3}*: {4}",
Smile.COMMENT.getValue(), url, Smile.HR.getValue(), authorName, escapeMarkdown(message)
);
}
}

View File

@ -0,0 +1,43 @@
package dev.struchkov.bot.gitlab.context.domain.notify.comment;
import dev.struchkov.bot.gitlab.context.domain.notify.Notify;
import dev.struchkov.bot.gitlab.context.utils.Smile;
import lombok.Builder;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
import static dev.struchkov.haiti.utils.Strings.escapeMarkdown;
@Builder
public record NewCommentNotify(
String url,
String discussionMessage,
String discussionAuthor,
String previousMessage,
String previousAuthor,
String authorName,
String message
) implements Notify {
@Override
public String generateMessage() {
final StringBuilder builder = new StringBuilder(Smile.COMMENT.getValue()).append(" [New answer in discussion](").append(url).append(")\n--- --- --- ---");
if (checkNotNull(discussionMessage)) {
builder.append("\n-- -- discussion first message -- --\n")
.append("*").append(discussionAuthor).append("*: ").append(escapeMarkdown(discussionMessage));
}
if (checkNotNull(previousMessage)) {
builder.append("\n-- -- -- previous message -- -- --\n")
.append("*").append(previousAuthor).append("*: ").append(escapeMarkdown(previousMessage));
}
builder.append("\n-- -- -- --- new answer --- -- -- --\n")
.append("*").append(authorName).append("*: ").append(escapeMarkdown(message));
return builder.toString();
}
}

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

@ -4,8 +4,6 @@ import dev.struchkov.bot.gitlab.context.utils.Smile;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import java.text.MessageFormat;
@Getter @Getter
public class UpdatePrNotify extends PrNotify { public class UpdatePrNotify extends PrNotify {
@ -36,10 +34,24 @@ public class UpdatePrNotify extends PrNotify {
@Override @Override
public String generateMessage() { public String generateMessage() {
return MessageFormat.format( final StringBuilder builder = new StringBuilder(Smile.UPDATE.getValue()).append(" *MergeRequest update | ").append(projectName).append("*")
"{0} *MergeRequest update | {6}*{3}[{1}]({2}){3}{4}: {5}", .append(Smile.HR.getValue())
Smile.UPDATE.getValue(), title, url, Smile.HR.getValue(), Smile.AUTHOR.getValue(), author, projectName, allTasks, allResolvedTasks, personTasks, personResolvedTasks .append("[").append(title).append("](").append(url).append(")");
);
if (allTasks > 0) {
builder.append(Smile.HR.getValue())
.append("All tasks: ").append(allResolvedTasks).append("/").append(allTasks);
if (personTasks > 0) {
builder.append("\nYour tasks: ").append(personResolvedTasks).append("/").append(personTasks);
}
}
builder.append(Smile.HR.getValue())
.append(Smile.AUTHOR.getValue()).append(": ").append(author);
return builder.toString();
} }
} }

View File

@ -0,0 +1,59 @@
package dev.struchkov.bot.gitlab.context.domain.notify.task;
import dev.struchkov.bot.gitlab.context.utils.Smile;
import dev.struchkov.haiti.utils.Pair;
import lombok.Builder;
import lombok.Getter;
import lombok.Singular;
import java.util.List;
import java.util.stream.Collectors;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
import static dev.struchkov.haiti.utils.Strings.escapeMarkdown;
/**
* @author upagge 10.09.2020
*/
@Getter
public class DiscussionNewNotify extends TaskNotify {
private final String mrName;
private final List<Pair<String, String>> notes;
@Builder
public DiscussionNewNotify(
String mrName,
String authorName,
String url,
String discussionMessage,
@Singular List<Pair<String, String>> notes
) {
super(authorName, url, discussionMessage);
this.mrName = mrName;
this.notes = notes;
}
@Override
public String generateMessage() {
final StringBuilder builder = new StringBuilder(Smile.TASK.getValue()).append(" [New discussion](").append(url).append(")")
.append(Smile.HR.getValue())
.append(escapeMarkdown(mrName))
.append(Smile.HR.getValue())
.append("*").append(authorName).append("*: ").append(escapeMarkdown(messageTask));
if (checkNotNull(notes)) {
builder.append("\n-- -- -- -- comments -- -- -- --\n")
.append(convertNotes(notes));
}
return builder.toString();
}
private String convertNotes(List<Pair<String, String>> notes) {
return notes.stream()
.map(note -> "*" + note.getKey() + "*: " + note.getValue())
.collect(Collectors.joining("\n"));
}
}

View File

@ -1,34 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.task;
import dev.struchkov.bot.gitlab.context.utils.Smile;
import lombok.Builder;
import lombok.Getter;
import java.text.MessageFormat;
import static dev.struchkov.haiti.utils.Strings.escapeMarkdown;
/**
* @author upagge 10.09.2020
*/
@Getter
public class TaskNewNotify extends TaskNotify {
@Builder
protected TaskNewNotify(
String authorName,
String url,
String messageTask
) {
super(authorName, url, messageTask);
}
@Override
public String generateMessage() {
return MessageFormat.format(
"{0} *New [task]({1}) assigned{2}*{3}*: {4}",
Smile.TASK.getValue(), url, Smile.HR.getValue(), authorName, escapeMarkdown(messageTask)
);
}
}

View File

@ -30,4 +30,7 @@ public interface MergeRequestRepository {
void deleteByIds(Set<Long> mergeRequestIds); void deleteByIds(Set<Long> mergeRequestIds);
Page<MergeRequest> filter(Filter filter, Pageable pageable); Page<MergeRequest> filter(Filter filter, Pageable pageable);
List<MergeRequest> findAllByReviewerId(Long personId);
} }

View File

@ -1,6 +1,6 @@
package dev.struchkov.bot.gitlab.context.service; package dev.struchkov.bot.gitlab.context.service;
import dev.struchkov.bot.gitlab.context.domain.ExistsContainer; import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
import dev.struchkov.bot.gitlab.context.domain.entity.Discussion; import dev.struchkov.bot.gitlab.context.domain.entity.Discussion;
import lombok.NonNull; import lombok.NonNull;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
@ -18,6 +18,8 @@ public interface DiscussionService {
Discussion update(@NonNull Discussion discussion); Discussion update(@NonNull Discussion discussion);
List<Discussion> updateAll(@NonNull List<Discussion> discussions);
/** /**
* Метод отправляющий коментарий в дискуссию. * Метод отправляющий коментарий в дискуссию.
* *
@ -31,7 +33,7 @@ public interface DiscussionService {
*/ */
List<Discussion> getAllByMergeRequestId(@NonNull Long mergeRequestId); List<Discussion> getAllByMergeRequestId(@NonNull Long mergeRequestId);
ExistsContainer<Discussion, String> existsById(@NonNull Set<String> discussionIds); ExistContainer<Discussion, String> existsById(@NonNull Set<String> discussionIds);
List<Discussion> createAll(@NonNull List<Discussion> newDiscussions); List<Discussion> createAll(@NonNull List<Discussion> newDiscussions);

View File

@ -1,6 +1,6 @@
package dev.struchkov.bot.gitlab.context.service; package dev.struchkov.bot.gitlab.context.service;
import dev.struchkov.bot.gitlab.context.domain.ExistsContainer; import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
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;
@ -18,6 +18,8 @@ public interface MergeRequestsService {
MergeRequest update(@NonNull MergeRequest mergeRequest); MergeRequest update(@NonNull MergeRequest mergeRequest);
List<MergeRequest> updateAll(@NonNull List<MergeRequest> mergeRequests);
/** /**
* Получить все идентификаторы вместе со статусами. * Получить все идентификаторы вместе со статусами.
* *
@ -30,10 +32,12 @@ public interface MergeRequestsService {
Page<MergeRequest> getAll(@NonNull MergeRequestFilter filter, Pageable pagination); Page<MergeRequest> getAll(@NonNull MergeRequestFilter filter, Pageable pagination);
ExistsContainer<MergeRequest, Long> existsById(@NonNull Set<Long> mergeRequestIds); ExistContainer<MergeRequest, Long> existsById(@NonNull Set<Long> mergeRequestIds);
List<MergeRequest> createAll(List<MergeRequest> newMergeRequests); List<MergeRequest> createAll(List<MergeRequest> newMergeRequests);
void deleteAllById(@NonNull Set<Long> mergeRequestIds); void deleteAllById(@NonNull Set<Long> mergeRequestIds);
List<MergeRequest> getAllByReviewerId(@NonNull Long personId);
} }

View File

@ -1,6 +1,6 @@
package dev.struchkov.bot.gitlab.context.service; package dev.struchkov.bot.gitlab.context.service;
import dev.struchkov.bot.gitlab.context.domain.ExistsContainer; import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
import dev.struchkov.bot.gitlab.context.domain.entity.Person; import dev.struchkov.bot.gitlab.context.domain.entity.Person;
import lombok.NonNull; import lombok.NonNull;
@ -18,7 +18,7 @@ public interface PersonService {
Person getByIdOrThrown(@NonNull Long personId); Person getByIdOrThrown(@NonNull Long personId);
ExistsContainer<Person, Long> existsById(Set<Long> personIds); ExistContainer<Person, Long> existsById(Set<Long> personIds);
List<Person> createAll(List<Person> newPersons); List<Person> createAll(List<Person> newPersons);

View File

@ -1,9 +1,9 @@
package dev.struchkov.bot.gitlab.context.service; package dev.struchkov.bot.gitlab.context.service;
import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
import dev.struchkov.bot.gitlab.context.domain.PipelineStatus; import dev.struchkov.bot.gitlab.context.domain.PipelineStatus;
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.filter.PipelineFilter; import dev.struchkov.bot.gitlab.context.domain.filter.PipelineFilter;
import dev.struchkov.haiti.context.domain.ExistsContainer;
import lombok.NonNull; import lombok.NonNull;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
@ -25,7 +25,7 @@ public interface PipelineService {
Page<Pipeline> getAll(@NonNull PipelineFilter filter, @NonNull Pageable pagination); Page<Pipeline> getAll(@NonNull PipelineFilter filter, @NonNull Pageable pagination);
ExistsContainer<Pipeline, Long> existsById(@NonNull Set<Long> pipelineIds); ExistContainer<Pipeline, Long> existsById(@NonNull Set<Long> pipelineIds);
void deleteAllById(Set<Long> pipelineIds); void deleteAllById(Set<Long> pipelineIds);

View File

@ -1,6 +1,6 @@
package dev.struchkov.bot.gitlab.context.service; package dev.struchkov.bot.gitlab.context.service;
import dev.struchkov.bot.gitlab.context.domain.ExistsContainer; 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 lombok.NonNull; import lombok.NonNull;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
@ -26,6 +26,6 @@ public interface ProjectService {
boolean existsById(Long projectId); boolean existsById(Long projectId);
ExistsContainer<Project, Long> existsById(Set<Long> projectIds); ExistContainer<Project, Long> existsById(Set<Long> projectIds);
} }

View File

@ -33,7 +33,9 @@ public enum Smile {
DANGEROUS("⚠️"), DANGEROUS("⚠️"),
COMMENT("\uD83D\uDCAC"), COMMENT("\uD83D\uDCAC"),
ARROW(""), ARROW(""),
HR("\n -- -- -- -- --\n"), SHORT_HR("\n-- -- --\n"),
HR("\n-- -- -- -- --\n"),
HR2("\n-- -- -- -- -- -- -- -- -- --\n"),
FAILURE(""), FAILURE(""),
SUCCESS(""), SUCCESS(""),
BUILD("♻️"), BUILD("♻️"),

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

@ -1,20 +1,21 @@
package dev.struchkov.bot.gitlab.core.service.impl; package dev.struchkov.bot.gitlab.core.service.impl;
import dev.struchkov.bot.gitlab.context.domain.ExistsContainer; import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
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.Note; import dev.struchkov.bot.gitlab.context.domain.entity.Note;
import dev.struchkov.bot.gitlab.context.domain.notify.comment.CommentNotify; 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.task.DiscussionNewNotify;
import dev.struchkov.bot.gitlab.context.domain.notify.task.TaskCloseNotify; import dev.struchkov.bot.gitlab.context.domain.notify.task.TaskCloseNotify;
import dev.struchkov.bot.gitlab.context.domain.notify.task.TaskNewNotify;
import dev.struchkov.bot.gitlab.context.repository.DiscussionRepository; import dev.struchkov.bot.gitlab.context.repository.DiscussionRepository;
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.bot.gitlab.context.service.NotifyService;
import dev.struchkov.bot.gitlab.context.service.PersonService;
import dev.struchkov.bot.gitlab.core.config.properties.GitlabProperty; import dev.struchkov.bot.gitlab.core.config.properties.GitlabProperty;
import dev.struchkov.bot.gitlab.core.config.properties.PersonProperty; import dev.struchkov.bot.gitlab.core.config.properties.PersonProperty;
import dev.struchkov.bot.gitlab.core.utils.StringUtils; import dev.struchkov.bot.gitlab.core.utils.StringUtils;
import dev.struchkov.haiti.utils.Pair;
import lombok.NonNull; import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -25,6 +26,7 @@ import okhttp3.RequestBody;
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.io.IOException; import java.io.IOException;
import java.text.MessageFormat; import java.text.MessageFormat;
@ -32,12 +34,14 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; 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.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
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.checkNotNull;
import static java.lang.Boolean.FALSE; import static java.lang.Boolean.FALSE;
/** /**
@ -52,7 +56,6 @@ public class DiscussionServiceImpl implements DiscussionService {
protected static final Pattern PATTERN = Pattern.compile("@[\\w]+"); protected static final Pattern PATTERN = Pattern.compile("@[\\w]+");
private final PersonService personService;
private final DiscussionRepository repository; private final DiscussionRepository repository;
private final PersonInformation personInformation; private final PersonInformation personInformation;
@ -62,85 +65,147 @@ public class DiscussionServiceImpl implements DiscussionService {
private final NotifyService notifyService; private final NotifyService notifyService;
@Override @Override
@Transactional
public Discussion create(@NonNull Discussion discussion) { public Discussion create(@NonNull Discussion discussion) {
discussion.getNotes().forEach(note -> personService.create(note.getAuthor())); final List<Note> notes = discussion.getNotes();
discussion.getNotes().forEach(this::notificationPersonal);
discussion.getNotes().forEach(note -> notifyNewNote(note, discussion)); if (isNeedNotifyNewNote(discussion)) {
notifyNewDiscussion(discussion);
} else {
notes.forEach(this::notificationPersonal);
}
final boolean resolved = discussion.getNotes().stream() final boolean resolved = discussion.getNotes().stream()
.allMatch(note -> note.isResolvable() && note.getResolved()); .allMatch(note -> note.isResolvable() && note.getResolved());
discussion.setResolved(resolved); discussion.setResolved(resolved);
return repository.save(discussion); return repository.save(discussion);
} }
/** /**
* <p>Уведомляет пользователя, если появился новый комментарий</p> * <p>Уведомляет пользователя, если появился новый комментарий</p>
*/ */
private void notifyNewNote(Note note, Discussion discussion) { private void notifyNewDiscussion(Discussion discussion) {
if (isNeedNotifyNewNote(note, discussion)) { final Note firstNote = discussion.getFirstNote();
notifyService.send( final List<Note> notes = discussion.getNotes();
TaskNewNotify.builder()
.authorName(note.getAuthor().getName())
.messageTask(note.getBody()) final MergeRequest mergeRequest = discussion.getMergeRequest();
.url(note.getWebUrl()) final DiscussionNewNotify.DiscussionNewNotifyBuilder notifyBuilder = DiscussionNewNotify.builder()
.build() .mrName(mergeRequest.getTitle())
.authorName(firstNote.getAuthor().getName())
.discussionMessage(firstNote.getBody())
.url(firstNote.getWebUrl());
if (notes.size() > 1) {
for (int i = 1; i < notes.size(); i++) {
final Note note = notes.get(i);
notifyBuilder.note(
new Pair<>(note.getAuthor().getName(), note.getBody())
); );
} }
} }
private boolean isNeedNotifyNewNote(Note note, Discussion discussion) { notifyService.send(notifyBuilder.build());
final Long personId = personInformation.getId(); }
return note.isResolvable() // Тип комментария требует решения (Задачи)
&& personId.equals(discussion.getResponsible().getId()) // Создатель дискуссии пользователь приложения private boolean isNeedNotifyNewNote(Discussion discussion) {
&& !personId.equals(note.getAuthor().getId()) // Создатель комментария не пользователь системы final Note firstNote = discussion.getFirstNote();
&& FALSE.equals(note.getResolved()); // Комментарий не отмечен как решенный 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 Discussion update(@NonNull Discussion discussion) { public Discussion update(@NonNull Discussion discussion) {
final Discussion oldDiscussion = repository.findById(discussion.getId()) final Discussion oldDiscussion = repository.findById(discussion.getId())
.orElseThrow(notFoundException("Дискуссия не найдена")); .orElseThrow(notFoundException("Дискуссия не найдена"));
final Map<Long, Note> idAndNoteMap = oldDiscussion
.getNotes().stream()
.collect(Collectors.toMap(Note::getId, note -> note));
// Пользователь участвовал в обсуждении
final boolean userParticipatedInDiscussion = discussion.getNotes().stream()
.anyMatch(note -> personInformation.getId().equals(note.getAuthor().getId()));
discussion.setMergeRequest(oldDiscussion.getMergeRequest());
discussion.setResponsible(oldDiscussion.getResponsible()); discussion.setResponsible(oldDiscussion.getResponsible());
discussion.getNotes().forEach(note -> updateNote(note, idAndNoteMap, userParticipatedInDiscussion)); discussion.setMergeRequest(oldDiscussion.getMergeRequest());
final Person responsiblePerson = discussion.getResponsible();
if (checkNotNull(responsiblePerson)) {
for (Note note : discussion.getNotes()) {
if (responsiblePerson.getId().equals(note.getAuthor().getId())) {
note.setAuthor(responsiblePerson);
}
final Person resolvedBy = note.getResolvedBy();
if (checkNotNull(resolvedBy)) {
if (responsiblePerson.getId().equals(resolvedBy.getId())) {
note.setResolvedBy(responsiblePerson);
}
}
}
}
notifyUpdateNote(oldDiscussion, discussion);
final boolean resolved = discussion.getNotes().stream() final boolean resolved = discussion.getNotes().stream()
.allMatch(note -> note.isResolvable() && note.getResolved()); .allMatch(note -> note.isResolvable() && note.getResolved());
discussion.setResolved(resolved); discussion.setResolved(resolved);
return repository.save(discussion); return repository.save(discussion);
} }
private void updateNote(Note note, Map<Long, Note> noteMap, boolean inDiscussion) { @Override
if (noteMap.containsKey(note.getId())) { public List<Discussion> updateAll(@NonNull List<Discussion> discussions) {
final Note oldNote = noteMap.get(note.getId()); return discussions.stream()
.map(this::update)
.collect(Collectors.toList());
}
if (note.isResolvable()) { private void notifyUpdateNote(Discussion oldDiscussion, Discussion discussion) {
updateTask(note, oldNote); final Map<Long, Note> noteMap = oldDiscussion
.getNotes().stream()
.collect(Collectors.toMap(Note::getId, n -> n));
// Пользователь участвовал в обсуждении
final boolean userParticipatedInDiscussion = oldDiscussion.getNotes().stream()
.anyMatch(note -> personInformation.getId().equals(note.getAuthor().getId()));
for (Note newNote : discussion.getNotes()) {
final Long newNoteId = newNote.getId();
if (noteMap.containsKey(newNoteId)) {
final Note oldNote = noteMap.get(newNoteId);
if (newNote.isResolvable()) {
updateTask(newNote, oldNote);
} }
} else { } else {
if (inDiscussion) { if (userParticipatedInDiscussion) {
notifyNewAnswer(note); notifyNewAnswer(discussion, newNote);
} else { } else {
notificationPersonal(note); notificationPersonal(newNote);
} }
} }
} }
private void notifyNewAnswer(Note note) { }
private void notifyNewAnswer(Discussion discussion, Note note) {
if (!personInformation.getId().equals(note.getAuthor().getId())) { if (!personInformation.getId().equals(note.getAuthor().getId())) {
final Note firstNote = discussion.getFirstNote();
final Optional<Note> prevLastNote = discussion.getPrevLastNote();
final NewCommentNotify.NewCommentNotifyBuilder notifyBuilder = NewCommentNotify.builder();
if (prevLastNote.isPresent()) {
final Note prevNote = prevLastNote.get();
notifyBuilder.previousMessage(prevNote.getBody());
notifyBuilder.previousAuthor(prevNote.getAuthor().getName());
}
notifyService.send( notifyService.send(
CommentNotify.builder() notifyBuilder
.url(note.getWebUrl()) .url(note.getWebUrl())
.discussionMessage(firstNote.getBody())
.discussionAuthor(firstNote.getAuthor().getName())
.message(note.getBody()) .message(note.getBody())
.authorName(note.getAuthor().getName()) .authorName(note.getAuthor().getName())
.build() .build()
@ -212,16 +277,16 @@ public class DiscussionServiceImpl implements DiscussionService {
} }
@Override @Override
public ExistsContainer<Discussion, String> existsById(@NonNull Set<String> discussionIds) { public ExistContainer<Discussion, String> existsById(@NonNull Set<String> discussionIds) {
final List<Discussion> existsEntity = repository.findAllById(discussionIds); final List<Discussion> existsEntity = repository.findAllById(discussionIds);
final Set<String> existsIds = existsEntity.stream().map(Discussion::getId).collect(Collectors.toSet()); final Set<String> existsIds = existsEntity.stream().map(Discussion::getId).collect(Collectors.toSet());
if (existsIds.containsAll(discussionIds)) { if (existsIds.containsAll(discussionIds)) {
return dev.struchkov.bot.gitlab.context.domain.ExistsContainer.allFind(existsEntity); return ExistContainer.allFind(existsEntity);
} else { } else {
final Set<String> noExistsId = discussionIds.stream() final Set<String> noExistsId = discussionIds.stream()
.filter(id -> !existsIds.contains(id)) .filter(id -> !existsIds.contains(id))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
return ExistsContainer.notAllFind(existsEntity, noExistsId); return ExistContainer.notAllFind(existsEntity, noExistsId);
} }
} }
@ -254,7 +319,7 @@ public class DiscussionServiceImpl implements DiscussionService {
} }
if (recipientsLogins.contains(personInformation.getUsername())) { if (recipientsLogins.contains(personInformation.getUsername())) {
notifyService.send( notifyService.send(
CommentNotify.builder() NewCommentNotify.builder()
.authorName(note.getAuthor().getName()) .authorName(note.getAuthor().getName())
.message(note.getBody()) .message(note.getBody())
.url(note.getWebUrl()) .url(note.getWebUrl())

View File

@ -1,11 +1,14 @@
package dev.struchkov.bot.gitlab.core.service.impl; package dev.struchkov.bot.gitlab.core.service.impl;
import dev.struchkov.bot.gitlab.context.domain.ExistsContainer; import dev.struchkov.bot.gitlab.context.domain.AssigneeChanged;
import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
import dev.struchkov.bot.gitlab.context.domain.IdAndStatusPr; import dev.struchkov.bot.gitlab.context.domain.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.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 +19,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,13 +26,15 @@ 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.Set; 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 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,141 +50,156 @@ 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()
);
}
}
}
}
/**
* Создатель 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()) {
sendNotifyAboutNewMr(savedMergeRequest, projectName);
}
}
}
}
private void sendNotifyAboutNewMr(MergeRequest savedMergeRequest, String projectName) {
notifyService.send(
NewPrNotify.builder()
.projectName(projectName)
.labels(savedMergeRequest.getLabels())
.author(savedMergeRequest.getAuthor().getName())
.description(savedMergeRequest.getDescription())
.title(savedMergeRequest.getTitle())
.url(savedMergeRequest.getWebUrl())
.targetBranch(savedMergeRequest.getTargetBranch())
.sourceBranch(savedMergeRequest.getSourceBranch())
.build() .build()
); );
} }
}
}
@Override @Override
@Transactional
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 = oldMergeRequest.getNotification();
if (checkNotNull(notification)) {
mergeRequest.setNotification(oldMergeRequest.getNotification()); mergeRequest.setNotification(oldMergeRequest.getNotification());
} }
if (!oldMergeRequest.getUpdatedDate().equals(mergeRequest.getUpdatedDate()) || oldMergeRequest.isConflict() != mergeRequest.isConflict()) { final Long gitlabUserId = personInformation.getId();
final AssigneeChanged assigneeChanged = AssigneeChanged.valueOf(gitlabUserId, oldMergeRequest.getAssignee(), mergeRequest.getAssignee());
final ReviewerChanged reviewerChanged = ReviewerChanged.valueOf(gitlabUserId, oldMergeRequest.getReviewers(), mergeRequest.getReviewers());
final boolean isChangedMr =
!oldMergeRequest.getUpdatedDate().equals(mergeRequest.getUpdatedDate())
|| oldMergeRequest.isConflict() != mergeRequest.isConflict();
final boolean isChangedLinkedEntity = reviewerChanged.isChanged() || assigneeChanged.isChanged();
if (isChangedMr || isChangedLinkedEntity) {
final Project project = projectService.getByIdOrThrow(mergeRequest.getProjectId()); final Project project = projectService.getByIdOrThrow(mergeRequest.getProjectId());
if (TRUE.equals(oldMergeRequest.getNotification())) { if (TRUE.equals(notification) && isChangedMr) {
notifyStatus(oldMergeRequest, mergeRequest, project); notifyAboutStatus(oldMergeRequest, mergeRequest, project);
notifyConflict(oldMergeRequest, mergeRequest, project); notifyAboutConflict(oldMergeRequest, mergeRequest, project);
notifyUpdate(oldMergeRequest, mergeRequest, project); notifyAboutUpdate(oldMergeRequest, mergeRequest, project);
}
if (TRUE.equals(notification) && isChangedLinkedEntity) {
notifyReviewer(reviewerChanged, mergeRequest, project);
notifyAssignee(assigneeChanged, mergeRequest, project);
} }
return repository.save(mergeRequest); return repository.save(mergeRequest);
} }
return oldMergeRequest; return oldMergeRequest;
} }
private void notifyUpdate(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) {
if ( //TODO [05.12.2022|uPagge]: Добавить уведомление, если происходит удаление
!personInformation.getId().equals(mergeRequest.getAuthor().getId()) private void notifyAssignee(AssigneeChanged assigneeChanged, MergeRequest mergeRequest, Project project) {
&& !oldMergeRequest.getDateLastCommit().equals(mergeRequest.getDateLastCommit()) switch (assigneeChanged) {
&& !mergeRequest.isConflict() case BECOME -> sendNotifyAboutNewMr(mergeRequest, project.getName());
) {
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) { //TODO [05.12.2022|uPagge]: Добавить уведомление, если происходит удаление ревьювера
if ( //TODO [05.12.2022|uPagge]: Заменить тип уведомления на самостоятельный
!oldMergeRequest.isConflict() private void notifyReviewer(ReviewerChanged reviewerChanged, MergeRequest mergeRequest, Project project) {
&& mergeRequest.isConflict() switch (reviewerChanged) {
&& personInformation.getId().equals(oldMergeRequest.getAuthor().getId()) case BECOME -> sendNotifyAboutNewMr(mergeRequest, project.getName());
) {
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) { @Override
final MergeRequestState oldStatus = oldMergeRequest.getState(); @Transactional
final MergeRequestState newStatus = newMergeRequest.getState(); public List<MergeRequest> updateAll(@NonNull List<MergeRequest> mergeRequests) {
if ( return mergeRequests.stream()
!oldStatus.equals(newStatus) .map(this::update)
&& oldMergeRequest.getAuthor().getId().equals(personInformation.getId()) .collect(Collectors.toList());
) {
notifyService.send(
StatusPrNotify.builder()
.name(newMergeRequest.getTitle())
.url(oldMergeRequest.getWebUrl())
.projectName(project.getName())
.newStatus(newStatus)
.oldStatus(oldStatus)
.build()
);
}
} }
@Override @Override
@ -200,16 +218,16 @@ public class MergeRequestsServiceImpl implements MergeRequestsService {
} }
@Override @Override
public ExistsContainer<MergeRequest, Long> existsById(@NonNull Set<Long> mergeRequestIds) { public ExistContainer<MergeRequest, Long> existsById(@NonNull Set<Long> mergeRequestIds) {
final List<MergeRequest> existsEntity = repository.findAllById(mergeRequestIds); final List<MergeRequest> existsEntity = repository.findAllById(mergeRequestIds);
final Set<Long> existsIds = existsEntity.stream().map(MergeRequest::getId).collect(Collectors.toSet()); final Set<Long> existsIds = existsEntity.stream().map(MergeRequest::getId).collect(Collectors.toSet());
if (existsIds.containsAll(mergeRequestIds)) { if (existsIds.containsAll(mergeRequestIds)) {
return ExistsContainer.allFind(existsEntity); return ExistContainer.allFind(existsEntity);
} else { } else {
final Set<Long> noExistsId = mergeRequestIds.stream() final Set<Long> noExistsId = mergeRequestIds.stream()
.filter(id -> !existsIds.contains(id)) .filter(id -> !existsIds.contains(id))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
return ExistsContainer.notAllFind(existsEntity, noExistsId); return ExistContainer.notAllFind(existsEntity, noExistsId);
} }
} }
@ -221,8 +239,96 @@ public class MergeRequestsServiceImpl implements MergeRequestsService {
} }
@Override @Override
@Transactional
public void deleteAllById(@NonNull Set<Long> mergeRequestIds) { public void deleteAllById(@NonNull Set<Long> mergeRequestIds) {
repository.deleteByIds(mergeRequestIds); repository.deleteByIds(mergeRequestIds);
} }
@Override
public List<MergeRequest> getAllByReviewerId(@NonNull Long personId) {
return repository.findAllByReviewerId(personId);
}
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 не находится в состоянии конфликта
) {
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;
}
}
}
}
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) {
final Long gitlabUserId = personInformation.getId();
if (
!oldMergeRequest.isConflict() // У старого MR не было конфликта
&& mergeRequest.isConflict() // А у нового есть
&& gitlabUserId.equals(oldMergeRequest.getAuthor().getId()) // и MR создан пользователем бота
) {
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();
final Long gitlabUserId = personInformation.getId();
if (
!oldStatus.equals(newStatus) // статус изменился
&& gitlabUserId.equals(oldMergeRequest.getAuthor().getId()) // создатель MR является пользователем бота
) {
notifyService.send(
StatusPrNotify.builder()
.name(newMergeRequest.getTitle())
.url(oldMergeRequest.getWebUrl())
.projectName(project.getName())
.newStatus(newStatus)
.oldStatus(oldStatus)
.build()
);
}
}
} }

View File

@ -1,6 +1,6 @@
package dev.struchkov.bot.gitlab.core.service.impl; package dev.struchkov.bot.gitlab.core.service.impl;
import dev.struchkov.bot.gitlab.context.domain.ExistsContainer; import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
import dev.struchkov.bot.gitlab.context.domain.entity.Person; import dev.struchkov.bot.gitlab.context.domain.entity.Person;
import dev.struchkov.bot.gitlab.context.repository.PersonRepository; import dev.struchkov.bot.gitlab.context.repository.PersonRepository;
import dev.struchkov.bot.gitlab.context.service.PersonService; import dev.struchkov.bot.gitlab.context.service.PersonService;
@ -40,16 +40,16 @@ public class PersonServiceImpl implements PersonService {
} }
@Override @Override
public ExistsContainer<Person, Long> existsById(Set<Long> personIds) { public ExistContainer<Person, Long> existsById(Set<Long> personIds) {
final List<Person> existsEntity = repository.findAllById(personIds); final List<Person> existsEntity = repository.findAllById(personIds);
final Set<Long> existsIds = existsEntity.stream().map(Person::getId).collect(Collectors.toSet()); final Set<Long> existsIds = existsEntity.stream().map(Person::getId).collect(Collectors.toSet());
if (existsIds.containsAll(personIds)) { if (existsIds.containsAll(personIds)) {
return ExistsContainer.allFind(existsEntity); return ExistContainer.allFind(existsEntity);
} else { } else {
final Set<Long> noExistsId = personIds.stream() final Set<Long> noExistsId = personIds.stream()
.filter(id -> !existsIds.contains(id)) .filter(id -> !existsIds.contains(id))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
return ExistsContainer.notAllFind(existsEntity, noExistsId); return ExistContainer.notAllFind(existsEntity, noExistsId);
} }
} }

View File

@ -1,5 +1,6 @@
package dev.struchkov.bot.gitlab.core.service.impl; package dev.struchkov.bot.gitlab.core.service.impl;
import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
import dev.struchkov.bot.gitlab.context.domain.PersonInformation; 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.Person;
@ -8,15 +9,14 @@ import dev.struchkov.bot.gitlab.context.domain.filter.PipelineFilter;
import dev.struchkov.bot.gitlab.context.domain.notify.pipeline.PipelineNotify; 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.NotifyService;
import dev.struchkov.bot.gitlab.context.service.PersonService;
import dev.struchkov.bot.gitlab.context.service.PipelineService; import dev.struchkov.bot.gitlab.context.service.PipelineService;
import dev.struchkov.bot.gitlab.core.service.impl.filter.PipelineFilterService; import dev.struchkov.bot.gitlab.core.service.impl.filter.PipelineFilterService;
import dev.struchkov.haiti.context.domain.ExistsContainer;
import lombok.NonNull; import lombok.NonNull;
import lombok.RequiredArgsConstructor; 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;
@ -27,6 +27,7 @@ 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.SKIPPED;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.SUCCESS; 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;
/** /**
* Реализация сервиса для работы с пайплайнами. * Реализация сервиса для работы с пайплайнами.
@ -42,14 +43,13 @@ public class PipelineServiceImpl implements PipelineService {
private final NotifyService notifyService; private final NotifyService notifyService;
private final PipelineRepository repository; private final PipelineRepository repository;
private final PersonService personService;
private final PipelineFilterService pipelineFilterService; private final PipelineFilterService pipelineFilterService;
private final PersonInformation personInformation; private final PersonInformation personInformation;
@Override @Override
@Transactional
public Pipeline create(@NonNull Pipeline pipeline) { public Pipeline create(@NonNull Pipeline pipeline) {
personService.create(pipeline.getPerson());
final Pipeline newPipeline = repository.save(pipeline); final Pipeline newPipeline = repository.save(pipeline);
notifyNewPipeline(pipeline, "n/a"); notifyNewPipeline(pipeline, "n/a");
return newPipeline; return newPipeline;
@ -87,7 +87,7 @@ public class PipelineServiceImpl implements PipelineService {
private boolean isNeedNotifyNewPipeline(@NonNull Pipeline pipeline) { private boolean isNeedNotifyNewPipeline(@NonNull Pipeline pipeline) {
final Person personPipelineCreator = pipeline.getPerson(); final Person personPipelineCreator = pipeline.getPerson();
return notificationStatus.contains(pipeline.getStatus()) // Пайплайн имеет статус необходимый для уведомления return notificationStatus.contains(pipeline.getStatus()) // Пайплайн имеет статус необходимый для уведомления
&& personPipelineCreator != null && checkNotNull(personPipelineCreator) // Создатель пайплайна не null
&& personInformation.getId().equals(personPipelineCreator.getId()); // Пользователь приложения является инициатором пайплайна && personInformation.getId().equals(personPipelineCreator.getId()); // Пользователь приложения является инициатором пайплайна
} }
@ -102,16 +102,16 @@ public class PipelineServiceImpl implements PipelineService {
} }
@Override @Override
public ExistsContainer<Pipeline, Long> existsById(@NonNull Set<Long> pipelineIds) { public ExistContainer<Pipeline, Long> existsById(@NonNull Set<Long> pipelineIds) {
final List<Pipeline> existsEntity = repository.findAllById(pipelineIds); final List<Pipeline> existsEntity = repository.findAllById(pipelineIds);
final Set<Long> existsIds = existsEntity.stream().map(Pipeline::getId).collect(Collectors.toSet()); final Set<Long> existsIds = existsEntity.stream().map(Pipeline::getId).collect(Collectors.toSet());
if (existsIds.containsAll(pipelineIds)) { if (existsIds.containsAll(pipelineIds)) {
return ExistsContainer.allFind(existsEntity); return ExistContainer.allFind(existsEntity);
} else { } else {
final Set<Long> noExistsId = pipelineIds.stream() final Set<Long> noExistsId = pipelineIds.stream()
.filter(id -> !existsIds.contains(id)) .filter(id -> !existsIds.contains(id))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
return ExistsContainer.notAllFind(existsEntity, noExistsId); return ExistContainer.notAllFind(existsEntity, noExistsId);
} }
} }

View File

@ -1,6 +1,6 @@
package dev.struchkov.bot.gitlab.core.service.impl; package dev.struchkov.bot.gitlab.core.service.impl;
import dev.struchkov.bot.gitlab.context.domain.ExistsContainer; import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
import dev.struchkov.bot.gitlab.context.domain.PersonInformation; import dev.struchkov.bot.gitlab.context.domain.PersonInformation;
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.NewProjectNotify; import dev.struchkov.bot.gitlab.context.domain.notify.NewProjectNotify;
@ -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;
@ -74,20 +78,20 @@ public class ProjectServiceImpl implements ProjectService {
} }
@Override @Override
public ExistsContainer<Project, Long> existsById(Set<Long> projectIds) { public ExistContainer<Project, Long> existsById(Set<Long> projectIds) {
final List<Project> existsEntity = repository.findAllById(projectIds); final List<Project> existsEntity = repository.findAllById(projectIds);
final Set<Long> existsIds = existsEntity.stream().map(Project::getId).collect(Collectors.toSet()); final Set<Long> existsIds = existsEntity.stream().map(Project::getId).collect(Collectors.toSet());
if (existsIds.containsAll(projectIds)) { if (existsIds.containsAll(projectIds)) {
return ExistsContainer.allFind(existsEntity); return ExistContainer.allFind(existsEntity);
} else { } else {
final Set<Long> noExistsId = projectIds.stream() final Set<Long> noExistsId = projectIds.stream()
.filter(id -> !existsIds.contains(id)) .filter(id -> !existsIds.contains(id))
.collect(Collectors.toSet()); .collect(Collectors.toSet());
return ExistsContainer.notAllFind(existsEntity, noExistsId); return ExistContainer.notAllFind(existsEntity, noExistsId);
} }
} }
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

@ -1,9 +1,10 @@
package dev.struchkov.bot.gitlab.core.service.parser; package dev.struchkov.bot.gitlab.core.service.parser;
import dev.struchkov.bot.gitlab.context.domain.ExistsContainer; import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
import dev.struchkov.bot.gitlab.context.domain.entity.Discussion; import dev.struchkov.bot.gitlab.context.domain.entity.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.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.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.core.config.properties.GitlabProperty; import dev.struchkov.bot.gitlab.core.config.properties.GitlabProperty;
@ -17,13 +18,20 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.ArrayList;
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.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import static dev.struchkov.bot.gitlab.core.utils.StringUtils.H_PRIVATE_TOKEN; import static dev.struchkov.bot.gitlab.core.utils.StringUtils.H_PRIVATE_TOKEN;
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
import static dev.struchkov.haiti.utils.Checker.checkNull;
import static dev.struchkov.haiti.utils.network.HttpParse.ACCEPT; import static dev.struchkov.haiti.utils.network.HttpParse.ACCEPT;
/** /**
@ -52,8 +60,12 @@ public class DiscussionParser {
Page<MergeRequest> mergeRequestSheet = mergeRequestsService.getAll(PageRequest.of(page, COUNT)); Page<MergeRequest> mergeRequestSheet = mergeRequestsService.getAll(PageRequest.of(page, COUNT));
while (mergeRequestSheet.hasContent()) { while (mergeRequestSheet.hasContent()) {
mergeRequestSheet.getContent() final List<MergeRequest> mergeRequests = mergeRequestSheet.getContent();
.forEach(this::processingMergeRequest);
for (MergeRequest mergeRequest : mergeRequests) {
processingMergeRequest(mergeRequest);
}
mergeRequestSheet = mergeRequestsService.getAll(PageRequest.of(++page, COUNT)); mergeRequestSheet = mergeRequestsService.getAll(PageRequest.of(++page, COUNT));
} }
} }
@ -75,10 +87,10 @@ public class DiscussionParser {
.map(DiscussionJson::getId) .map(DiscussionJson::getId)
.collect(Collectors.toUnmodifiableSet()); .collect(Collectors.toUnmodifiableSet());
final ExistsContainer<Discussion, String> existsContainer = discussionService.existsById(discussionIds); final ExistContainer<Discussion, String> existContainer = discussionService.existsById(discussionIds);
if (!existsContainer.isAllFound()) { if (!existContainer.isAllFound()) {
final List<Discussion> newDiscussions = discussionJson.stream() final List<Discussion> newDiscussions = discussionJson.stream()
.filter(json -> existsContainer.getIdNoFound().contains(json.getId())) .filter(json -> existContainer.getIdNoFound().contains(json.getId()))
.map(json -> { .map(json -> {
final Discussion discussion = conversionService.convert(json, Discussion.class); final Discussion discussion = conversionService.convert(json, Discussion.class);
discussion.setMergeRequest(mergeRequest); discussion.setMergeRequest(mergeRequest);
@ -86,10 +98,53 @@ public class DiscussionParser {
discussion.getNotes().forEach(createNoteLink(mergeRequest)); discussion.getNotes().forEach(createNoteLink(mergeRequest));
return discussion; return discussion;
}) })
.filter(discussion -> discussion.getNotes() != null && !discussion.getNotes().isEmpty()) // Фильтрация специально стоит после map(). Таким образом отбрасываются системные уведомления
.filter(discussion -> checkNotEmpty(discussion.getNotes()))
.toList(); .toList();
if (checkNotEmpty(newDiscussions)) {
personMapping(newDiscussions);
discussionService.createAll(newDiscussions); discussionService.createAll(newDiscussions);
} }
}
}
private void personMapping(List<Discussion> newDiscussions) {
final Stream<Person> firstStream = Stream.concat(
newDiscussions.stream()
.flatMap(discussion -> discussion.getNotes().stream())
.map(Note::getResolvedBy)
.filter(Objects::nonNull),
newDiscussions.stream()
.flatMap(discussion -> discussion.getNotes().stream())
.map(Note::getAuthor)
.filter(Objects::nonNull)
);
final Map<Long, Person> personMap = Stream.concat(
firstStream,
newDiscussions.stream()
.map(Discussion::getResponsible)
.filter(Objects::nonNull)
).distinct()
.collect(Collectors.toMap(Person::getId, p -> p));
for (Discussion newDiscussion : newDiscussions) {
final Person responsible = newDiscussion.getResponsible();
if (checkNotNull(responsible)) {
newDiscussion.setResponsible(personMap.get(responsible.getId()));
}
for (Note note : newDiscussion.getNotes()) {
note.setAuthor(personMap.get(note.getAuthor().getId()));
final Person resolvedBy = note.getResolvedBy();
if (checkNotNull(resolvedBy)) {
note.setResolvedBy(personMap.get(resolvedBy.getId()));
}
}
}
} }
/** /**
@ -97,31 +152,45 @@ public class DiscussionParser {
*/ */
public void scanOldDiscussions() { public void scanOldDiscussions() {
int page = 0; int page = 0;
Page<Discussion> discussionSheet = discussionService.getAll(PageRequest.of(page, COUNT)); Page<Discussion> discussionPage = discussionService.getAll(PageRequest.of(page, COUNT));
while (discussionSheet.hasContent()) { while (discussionPage.hasContent()) {
final List<Discussion> discussions = discussionSheet.getContent(); final List<Discussion> discussions = discussionPage.getContent();
// Удаляем обсуждения, которые потеряли свои MR
//TODO [05.12.2022|uPagge]: Проверить целесообразность этого действия
discussions.stream()
.filter(discussion -> checkNull(discussion.getMergeRequest()))
.map(Discussion::getId)
.forEach(discussionService::deleteById);
final List<Discussion> newDiscussions = new ArrayList<>();
for (Discussion discussion : discussions) { for (Discussion discussion : discussions) {
if (discussion.getMergeRequest() != null) { if (checkNotNull(discussion.getMergeRequest())) {
final Optional<Discussion> optNewDiscussion = HttpParse.request(createLinkOldDiscussion(discussion)) getOldDiscussionJson(discussion)
.header(ACCEPT)
.header(H_PRIVATE_TOKEN, personProperty.getToken())
.execute(DiscussionJson.class)
.map(json -> { .map(json -> {
final Discussion newDiscussion = conversionService.convert(json, Discussion.class); final Discussion newDiscussion = conversionService.convert(json, Discussion.class);
newDiscussion.getNotes().forEach(createNoteLink(discussion.getMergeRequest())); newDiscussion.getNotes().forEach(createNoteLink(discussion.getMergeRequest()));
return newDiscussion; return newDiscussion;
}); }).ifPresent(newDiscussions::add);
optNewDiscussion.ifPresent(discussionService::update);
} else {
discussionService.deleteById(discussion.getId());
} }
} }
discussionSheet = discussionService.getAll(PageRequest.of(++page, COUNT)); if (checkNotEmpty(newDiscussions)) {
personMapping(newDiscussions);
discussionService.updateAll(newDiscussions);
} }
discussionPage = discussionService.getAll(PageRequest.of(++page, COUNT));
}
}
private Optional<DiscussionJson> getOldDiscussionJson(Discussion discussion) {
return HttpParse.request(createLinkOldDiscussion(discussion))
.header(ACCEPT)
.header(H_PRIVATE_TOKEN, personProperty.getToken())
.execute(DiscussionJson.class);
} }
private String createLinkOldDiscussion(Discussion discussion) { private String createLinkOldDiscussion(Discussion discussion) {
@ -142,7 +211,11 @@ public class DiscussionParser {
private Consumer<Note> createNoteLink(MergeRequest mergeRequest) { private Consumer<Note> createNoteLink(MergeRequest mergeRequest) {
return note -> { return note -> {
final String url = MessageFormat.format(gitlabProperty.getUrlNote(), mergeRequest.getWebUrl(), note.getId()); final String url = MessageFormat.format(
gitlabProperty.getUrlNote(),
mergeRequest.getWebUrl(),
note.getId()
);
note.setWebUrl(url); note.setWebUrl(url);
}; };
} }

View File

@ -1,9 +1,10 @@
package dev.struchkov.bot.gitlab.core.service.parser; package dev.struchkov.bot.gitlab.core.service.parser;
import dev.struchkov.bot.gitlab.context.domain.ExistsContainer; import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
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,22 +90,25 @@ 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)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
final ExistsContainer<MergeRequest, Long> existsContainer = mergeRequestsService.existsById(jsonIds); final ExistContainer<MergeRequest, Long> existContainer = mergeRequestsService.existsById(jsonIds);
if (!existsContainer.isAllFound()) { if (!existContainer.isAllFound()) {
final List<MergeRequest> newMergeRequests = mergeRequestJsons.stream() final List<MergeRequest> newMergeRequests = mergeRequestJsons.stream()
.filter(json -> existsContainer.getIdNoFound().contains(json.getId())) .filter(json -> existContainer.getIdNoFound().contains(json.getId()))
.map(json -> { .map(json -> {
final MergeRequest mergeRequest = conversionService.convert(json, MergeRequest.class); final MergeRequest mergeRequest = conversionService.convert(json, MergeRequest.class);
parsingCommits(mergeRequest); parsingCommits(mergeRequest);
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

@ -1,5 +1,6 @@
package dev.struchkov.bot.gitlab.core.service.parser; package dev.struchkov.bot.gitlab.core.service.parser;
import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
import dev.struchkov.bot.gitlab.context.domain.PipelineStatus; import dev.struchkov.bot.gitlab.context.domain.PipelineStatus;
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.entity.Project; import dev.struchkov.bot.gitlab.context.domain.entity.Project;
@ -9,7 +10,6 @@ import dev.struchkov.bot.gitlab.core.config.properties.GitlabProperty;
import dev.struchkov.bot.gitlab.core.config.properties.PersonProperty; import dev.struchkov.bot.gitlab.core.config.properties.PersonProperty;
import dev.struchkov.bot.gitlab.core.utils.StringUtils; import dev.struchkov.bot.gitlab.core.utils.StringUtils;
import dev.struchkov.bot.gitlab.sdk.domain.PipelineJson; import dev.struchkov.bot.gitlab.sdk.domain.PipelineJson;
import dev.struchkov.haiti.context.domain.ExistsContainer;
import dev.struchkov.haiti.utils.network.HttpParse; import dev.struchkov.haiti.utils.network.HttpParse;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
@ -19,7 +19,6 @@ import org.springframework.stereotype.Service;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -31,6 +30,7 @@ import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.PREPARING;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.RUNNING; import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.RUNNING;
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.WAITING_FOR_RESOURCE; import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.WAITING_FOR_RESOURCE;
import static dev.struchkov.haiti.context.exception.ConvertException.convertException; import static dev.struchkov.haiti.context.exception.ConvertException.convertException;
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
import static dev.struchkov.haiti.utils.network.HttpParse.ACCEPT; import static dev.struchkov.haiti.utils.network.HttpParse.ACCEPT;
/** /**
@ -75,17 +75,17 @@ public class PipelineParser {
LocalDateTime newLastUpdate = LocalDateTime.now(); LocalDateTime newLastUpdate = LocalDateTime.now();
List<PipelineJson> pipelineJsons = getPipelineJsons(project.getId(), page, lastUpdate); List<PipelineJson> pipelineJsons = getPipelineJsons(project.getId(), page, lastUpdate);
while (!pipelineJsons.isEmpty()) { while (checkNotEmpty(pipelineJsons)) {
final Set<Long> jsonIds = pipelineJsons.stream() final Set<Long> jsonIds = pipelineJsons.stream()
.map(PipelineJson::getId) .map(PipelineJson::getId)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
final ExistsContainer<Pipeline, Long> existsContainer = pipelineService.existsById(jsonIds); final ExistContainer<Pipeline, Long> existContainer = pipelineService.existsById(jsonIds);
if (!existsContainer.isAllFound()) { if (!existContainer.isAllFound()) {
final Collection<Long> idsNotFound = existsContainer.getIdNoFound(); final Set<Long> idsNotFound = existContainer.getIdNoFound();
for (Long newId : idsNotFound) { for (Long newId : idsNotFound) {
final Pipeline newPipeline = HttpParse.request( final Pipeline newPipeline = HttpParse.request(

View File

@ -1,6 +1,6 @@
package dev.struchkov.bot.gitlab.core.service.parser; package dev.struchkov.bot.gitlab.core.service.parser;
import dev.struchkov.bot.gitlab.context.domain.ExistsContainer; import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
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.entity.Project;
import dev.struchkov.bot.gitlab.context.service.PersonService; import dev.struchkov.bot.gitlab.context.service.PersonService;
@ -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);
} }
@ -66,9 +69,9 @@ public class ProjectParser {
createNewPersons(projectJsons); createNewPersons(projectJsons);
final ExistsContainer<Project, Long> existsContainer = projectService.existsById(projectIds); final ExistContainer<Project, Long> existContainer = projectService.existsById(projectIds);
final List<Project> newProjects = projectJsons.stream() final List<Project> newProjects = projectJsons.stream()
.filter(json -> existsContainer.getIdNoFound().contains(json.getId())) .filter(json -> existContainer.getIdNoFound().contains(json.getId()))
.map(json -> conversionService.convert(json, Project.class)) .map(json -> conversionService.convert(json, Project.class))
.toList(); .toList();
@ -80,15 +83,29 @@ 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)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
final ExistsContainer<Person, Long> existsContainer = personService.existsById(personCreatorId); final ExistContainer<Person, Long> existContainer = personService.existsById(personCreatorId);
if (!existsContainer.isAllFound()) { if (!existContainer.isAllFound()) {
final Collection<Long> notFoundId = existsContainer.getIdNoFound(); final Collection<Long> notFoundId = existContainer.getIdNoFound();
final List<Person> newPersons = notFoundId.stream() final List<Person> newPersons = notFoundId.stream()
.map( .map(
@ -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

@ -21,8 +21,12 @@
<artifactId>bot-context</artifactId> <artifactId>bot-context</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.data</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-data-jpa</artifactId> <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@ -5,6 +5,7 @@ import dev.struchkov.bot.gitlab.context.repository.DiscussionRepository;
import dev.struchkov.bot.gitlab.data.jpa.DiscussionJpaRepository; import dev.struchkov.bot.gitlab.data.jpa.DiscussionJpaRepository;
import lombok.NonNull; import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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.Repository; import org.springframework.stereotype.Repository;
@ -16,6 +17,7 @@ import java.util.Set;
/** /**
* @author upagge 11.02.2021 * @author upagge 11.02.2021
*/ */
@Slf4j
@Repository @Repository
@RequiredArgsConstructor @RequiredArgsConstructor
public class DiscussionRepositoryImpl implements DiscussionRepository { public class DiscussionRepositoryImpl implements DiscussionRepository {

View File

@ -63,4 +63,9 @@ public class MergeRequestRepositoryImpl implements MergeRequestRepository {
return jpaRepository.findAll(filter.<Specification<MergeRequest>>build(), pageable); return jpaRepository.findAll(filter.<Specification<MergeRequest>>build(), pageable);
} }
@Override
public List<MergeRequest> findAllByReviewerId(Long personId) {
return jpaRepository.findAllByReviewersIn(personId);
}
} }

View File

@ -18,19 +18,20 @@ import java.util.Set;
public interface MergeRequestJpaRepository extends JpaRepositoryImplementation<MergeRequest, Long> { public interface MergeRequestJpaRepository extends JpaRepositoryImplementation<MergeRequest, Long> {
Set<MergeRequest> findAllByIdIn(Set<Long> ids);
void deleteAllByIdIn(Collection<Long> id); void deleteAllByIdIn(Collection<Long> id);
@Query("SELECT new dev.struchkov.bot.gitlab.context.domain.IdAndStatusPr(p.id, p.twoId, p.projectId, p.state) FROM MergeRequest p WHERE p.state IN :states") @Query("SELECT new dev.struchkov.bot.gitlab.context.domain.IdAndStatusPr(p.id, p.twoId, p.projectId, p.state) FROM MergeRequest p WHERE p.state IN :states")
Set<IdAndStatusPr> findAllIdByStateIn(@Param("states") Set<MergeRequestState> states); Set<IdAndStatusPr> findAllIdByStateIn(@Param("states") Set<MergeRequestState> states);
@Query("SELECT p.id from MergeRequest p") @Query("SELECT p.id FROM MergeRequest p")
Set<Long> findAllIds(); Set<Long> findAllIds();
@Query("SELECT p.author.id from MergeRequest p WHERE p.id = :id") @Query("SELECT p.author.id FROM MergeRequest p WHERE p.id = :id")
Optional<String> findAuthorById(@Param("id") Long id); Optional<String> findAuthorById(@Param("id") Long id);
List<MergeRequest> findAllByAssigneeId(Long userId); List<MergeRequest> findAllByAssigneeId(Long userId);
@Query("SELECT mr FROM MergeRequest mr LEFT JOIN mr.reviewers r WHERE r.id = :reviewerId")
List<MergeRequest> findAllByReviewersIn(@Param("reviewerId") Long reviewerId);
} }

View File

@ -1,23 +0,0 @@
FROM openjdk:17.0.2-jdk-slim-buster
MAINTAINER uPagge <me@upagge.ru>
RUN apt upgrade && addgroup gitlabbot --disabled-password && \
adduser gitlabbot --ingroup gitlabbot && \
mkdir -p /bot && \
chown -R gitlabbot:gitlabbot /bot
WORKDIR /bot
USER gitlabbot:gitlabbot
COPY target/gitlab-notification.jar app.jar
ENV TELEGRAM_PERSON_ID=TELEGRAM_PERSON_ID DATASOURCE_URL=DATASOURCE_URL \
DATASOURCE_PASSWORD=DATASOURCE_PASSWORD DATASOURCE_USERNAME=DATASOURCE_USERNAME \
GITLAB_PERSONAL_TOKEN=GITLAB_PERSONAL_TOKEN TELEGRAM_BOT_TOKEN=TELEGRAM_BOT_TOKEN \
TELEGRAM_BOT_USERNAME=TELEGRAM_BOT_USERNAME GITLAB_URL=GITLAB_URL GITLAB_REPLACE_URL=GITLAB_REPLACE_URL
ENTRYPOINT java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -DTELEGRAM_BOT_USERNAME=${TELEGRAM_BOT_USERNAME} \
-DTELEGRAM_BOT_TOKEN=$TELEGRAM_BOT_TOKEN \
-DTELEGRAM_PERSON_ID=$TELEGRAM_PERSON_ID \
-DDATASOURCE_URL=$DATASOURCE_URL \
-DDATASOURCE_PASSWORD=$DATASOURCE_PASSWORD \
-DDATASOURCE_USERNAME=$DATASOURCE_USERNAME \
-DGITLAB_PERSONAL_TOKEN=$GITLAB_PERSONAL_TOKEN \
-DGITLAB_URL=$GITLAB_URL \
-DGITLAB_REPLACE_URL=$GITLAB_REPLACE_URL \
-jar app.jar

View File

@ -0,0 +1,13 @@
package dev.struchkov.bot.gitlab;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GitLabBotApplication {
public static void main(String[] args) {
SpringApplication.run(GitLabBotApplication.class, args);
}
}

View File

@ -1,17 +0,0 @@
package dev.struchkov.bot.gitlab.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@EnableJpaRepositories(basePackages = {"dev.struchkov.bot.gitlab.data.jpa"})
@SpringBootApplication(scanBasePackages = "dev.struchkov.bot.gitlab")
@EntityScan(basePackages = {"dev.struchkov.bot.gitlab.context.domain.entity"})
public class GitLabBotApplication {
public static void main(String[] args) {
SpringApplication.run(GitLabBotApplication.class, args);
}
}

View File

@ -1,4 +1,4 @@
package dev.struchkov.bot.gitlab.app.config; package dev.struchkov.bot.gitlab.config;
import dev.struchkov.bot.gitlab.context.domain.PersonInformation; import dev.struchkov.bot.gitlab.context.domain.PersonInformation;
import dev.struchkov.bot.gitlab.core.config.properties.GitlabProperty; import dev.struchkov.bot.gitlab.core.config.properties.GitlabProperty;

View File

@ -1,4 +1,4 @@
package dev.struchkov.bot.gitlab.app.scheduler; package dev.struchkov.bot.gitlab.scheduler;
import dev.struchkov.bot.gitlab.context.service.CleanService; import dev.struchkov.bot.gitlab.context.service.CleanService;
import dev.struchkov.bot.gitlab.core.service.parser.DiscussionParser; import dev.struchkov.bot.gitlab.core.service.parser.DiscussionParser;

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

@ -0,0 +1,11 @@
.d8888b. d8b 888 888 888 888b 888 888 d8b .d888 d8b
d88P Y88b Y8P 888 888 888 8888b 888 888 Y8P d88P" Y8P
888 888 888 888 888 88888b 888 888 888
888 888 888888 888 8888b. 88888b. 888Y88b 888 .d88b. 888888 888 888888 888 .d88b. 888d888
888 88888 888 888 888 "88b 888 "88b 888 Y88b888 d88""88b 888 888 888 888 d8P Y8b 888P"
888 888 888 888 888 .d888888 888 888 888 Y88888 888 888 888 888 888 888 88888888 888
Y88b d88P 888 Y88b. 888 888 888 888 d88P 888 Y8888 Y88..88P Y88b. 888 888 888 Y8b. 888
"Y8888P88 888 "Y888 88888888 "Y888888 88888P" 888 Y888 "Y88P" "Y888 888 888 888 "Y8888 888
.................................................................................................................
..................................................................................... SpringBoot : 2.6.14 .......
.................................................................................................................

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;

22
pom.xml
View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.2</version> <version>2.6.14</version>
<relativePath/> <!-- lookup parent from repository --> <relativePath/> <!-- lookup parent from repository -->
</parent> </parent>
@ -44,7 +44,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<godfather.telegram.core.version>0.0.38</godfather.telegram.core.version> <godfather.telegram.core.version>0.0.39</godfather.telegram.core.version>
<javax.persistance.version>2.2</javax.persistance.version> <javax.persistance.version>2.2</javax.persistance.version>
@ -152,12 +152,6 @@
<version>${postgresql.version}</version> <version>${postgresql.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<version>${liquibase.version}</version>
</dependency>
<dependency> <dependency>
<groupId>javax.persistence</groupId> <groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId> <artifactId>javax.persistence-api</artifactId>
@ -182,18 +176,6 @@
<!-- /утилиты --> <!-- /утилиты -->
<!-- spring --> <!-- spring -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.2.4.RELEASE</version>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- /spring --> <!-- /spring -->
<!-- http --> <!-- http -->

View File

@ -25,7 +25,7 @@ public class StartNotify {
if (!settingService.isFirstStart()) { if (!settingService.isFirstStart()) {
notifyService.send( notifyService.send(
SimpleTextNotify.builder() SimpleTextNotify.builder()
.message("Привет. Желаю продуктивного дня :)" + .message("Hello. I wish you a productive day :)" +
"\n-- -- -- -- --\n" + "\n-- -- -- -- --\n" +
"Version " + appProperty.getVersion() + " | Developer: [uPagge](https://mark.struchkov.dev)") "Version " + appProperty.getVersion() + " | Developer: [uPagge](https://mark.struchkov.dev)")
.build() .build()

View File

@ -13,13 +13,11 @@ import dev.struchkov.godfather.main.domain.annotation.Unit;
import dev.struchkov.godfather.main.domain.content.Mail; import dev.struchkov.godfather.main.domain.content.Mail;
import dev.struchkov.godfather.simple.core.unit.AnswerText; import dev.struchkov.godfather.simple.core.unit.AnswerText;
import dev.struchkov.godfather.simple.core.unit.MainUnit; import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.haiti.utils.Checker;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
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 +90,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");
}) })
@ -136,10 +135,9 @@ public class MenuConfig {
return AnswerText.<Mail>builder() return AnswerText.<Mail>builder()
.triggerPhrase(GET_ASSIGNEE_MERGE_REQUEST) .triggerPhrase(GET_ASSIGNEE_MERGE_REQUEST)
.answer(() -> { .answer(() -> {
final Long userId = personInformation.getId(); final Long gitlabUserId = personInformation.getId();
final Page<MergeRequest> sheet = mergeRequestsService.getAll(getAssigneeFilter(userId), PageRequest.of(0, 20)); final List<MergeRequest> mergeRequests = mergeRequestsService.getAllByReviewerId(gitlabUserId);
if (sheet.hasContent()) { if (Checker.checkNotEmpty(mergeRequests)) {
final List<MergeRequest> mergeRequests = sheet.getContent();
final String text = mergeRequests.stream() final String text = mergeRequests.stream()
.map(mergeRequest -> MessageFormat.format("[{0}]({1})", mergeRequest.getTitle(), mergeRequest.getWebUrl())) .map(mergeRequest -> MessageFormat.format("[{0}]({1})", mergeRequest.getTitle(), mergeRequest.getWebUrl()))
.collect(Collectors.joining("\n")); .collect(Collectors.joining("\n"));
@ -150,6 +148,7 @@ public class MenuConfig {
.build(); .build();
} }
private MergeRequestFilter getAssigneeFilter(Long userId) { private MergeRequestFilter getAssigneeFilter(Long userId) {
final MergeRequestFilter mergeRequestFilter = new MergeRequestFilter(); final MergeRequestFilter mergeRequestFilter = new MergeRequestFilter();
mergeRequestFilter.setAssignee(userId); mergeRequestFilter.setAssignee(userId);