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
- 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
stage: build
variables:
@ -17,7 +47,7 @@ build:
paths:
- gitlab-app/target/gitlab-notification.jar
docker-build:
docker-build-release:
image: upagge/docker-buildx:latest
stage: deploy
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/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
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(of = "id")
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class MessageSend {
@EqualsAndHashCode.Include
private Long id;
private Long telegramId;
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.Table;
import java.util.List;
import java.util.Optional;
/**
* @author upagge 11.02.2021
@ -30,14 +31,14 @@ public class Discussion {
@Column(name = "id")
private String id;
@ManyToOne
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
@JoinColumn(name = "responsible_id")
private Person responsible;
@Column(name = "resolved")
private Boolean resolved;
@ManyToOne()
@ManyToOne
@JoinTable(
name = "discussion_merge_request",
joinColumns = @JoinColumn(name = "discussion_id"),
@ -50,7 +51,8 @@ public class Discussion {
fetch = FetchType.EAGER,
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
CascadeType.MERGE,
CascadeType.REFRESH
}
)
private List<Note> notes;
@ -64,4 +66,13 @@ public class Discussion {
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.haiti.utils.fieldconstants.annotation.FieldNames;
import dev.struchkov.haiti.utils.fieldconstants.domain.Mode;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.CascadeType;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
@ -28,7 +35,7 @@ import java.util.Set;
@Getter
@Setter
@Entity
@FieldNames
@FieldNames(mode = {Mode.TABLE, Mode.SIMPLE})
@Table(name = "merge_request")
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class MergeRequest {
@ -66,14 +73,25 @@ public class MergeRequest {
@Column(name = "conflict")
private boolean conflict;
@ManyToOne
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "author_id")
private Person author;
@ManyToOne
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "assignee_id")
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")
private String targetBranch;

View File

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

View File

@ -1,5 +1,8 @@
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.Setter;
@ -14,10 +17,13 @@ import javax.persistence.Table;
@Entity
@Getter
@Setter
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Table(name = "person")
@FieldNames(mode = {Mode.TABLE, Mode.SIMPLE})
public class Person {
@Id
@EqualsAndHashCode.Include
@Column(name = "id")
private Long id;

View File

@ -6,6 +6,7 @@ import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
@ -53,7 +54,7 @@ public class Pipeline {
@JoinColumn(name = "project_id")
private Project project;
@ManyToOne
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
@JoinColumn(name = "person_id")
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.notify.Notify;
import dev.struchkov.bot.gitlab.context.service.AppSettingService;
import dev.struchkov.bot.gitlab.context.utils.Smile;
import dev.struchkov.haiti.utils.Strings;
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;
}
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(),
projectName,
Smile.HR.getValue(),

View File

@ -4,8 +4,6 @@ import dev.struchkov.bot.gitlab.context.utils.Smile;
import lombok.Builder;
import lombok.Getter;
import java.text.MessageFormat;
@Getter
public class UpdatePrNotify extends PrNotify {
@ -36,10 +34,24 @@ public class UpdatePrNotify extends PrNotify {
@Override
public String generateMessage() {
return MessageFormat.format(
"{0} *MergeRequest update | {6}*{3}[{1}]({2}){3}{4}: {5}",
Smile.UPDATE.getValue(), title, url, Smile.HR.getValue(), Smile.AUTHOR.getValue(), author, projectName, allTasks, allResolvedTasks, personTasks, personResolvedTasks
);
final StringBuilder builder = new StringBuilder(Smile.UPDATE.getValue()).append(" *MergeRequest update | ").append(projectName).append("*")
.append(Smile.HR.getValue())
.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);
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;
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 lombok.NonNull;
import org.springframework.data.domain.Page;
@ -18,6 +18,8 @@ public interface DiscussionService {
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);
ExistsContainer<Discussion, String> existsById(@NonNull Set<String> discussionIds);
ExistContainer<Discussion, String> existsById(@NonNull Set<String> discussionIds);
List<Discussion> createAll(@NonNull List<Discussion> newDiscussions);

View File

@ -1,6 +1,6 @@
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.MergeRequestState;
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequest;
@ -18,6 +18,8 @@ public interface MergeRequestsService {
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);
ExistsContainer<MergeRequest, Long> existsById(@NonNull Set<Long> mergeRequestIds);
ExistContainer<MergeRequest, Long> existsById(@NonNull Set<Long> mergeRequestIds);
List<MergeRequest> createAll(List<MergeRequest> newMergeRequests);
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;
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 lombok.NonNull;
@ -18,7 +18,7 @@ public interface PersonService {
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);

View File

@ -1,9 +1,9 @@
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.entity.Pipeline;
import dev.struchkov.bot.gitlab.context.domain.filter.PipelineFilter;
import dev.struchkov.haiti.context.domain.ExistsContainer;
import lombok.NonNull;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
@ -25,7 +25,7 @@ public interface PipelineService {
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);

View File

@ -1,6 +1,6 @@
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 lombok.NonNull;
import org.springframework.data.domain.Page;
@ -26,6 +26,6 @@ public interface ProjectService {
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("⚠️"),
COMMENT("\uD83D\uDCAC"),
ARROW(""),
HR("\n -- -- -- -- --\n"),
SHORT_HR("\n-- -- --\n"),
HR("\n-- -- -- -- --\n"),
HR2("\n-- -- -- -- -- -- -- -- -- --\n"),
FAILURE(""),
SUCCESS(""),
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.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.MergeRequestStateJson;
import dev.struchkov.bot.gitlab.sdk.domain.PersonJson;
import lombok.RequiredArgsConstructor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
/**
* @author upagge 15.01.2021
@ -35,23 +39,36 @@ public class MergeRequestJsonConverter implements Converter<MergeRequestJson, Me
mergeRequest.setState(convertState(source.getState()));
mergeRequest.setProjectId(source.getProjectId());
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.setAuthor(convertPerson.convert(source.getAuthor()));
mergeRequest.setSourceBranch(source.getSourceBranch());
mergeRequest.setTargetBranch(source.getTargetBranch());
return mergeRequest;
}
private static Set<String> convertLabels(Set<String> source) {
if (checkNotEmpty(source)) {
return source.stream()
.map(label -> label.replaceAll("-", "_"))
.collect(Collectors.toSet());
private void convertReviewers(MergeRequest mergeRequest, List<PersonJson> jsonReviewers) {
if (checkNotEmpty(jsonReviewers)) {
final List<Person> reviewers = jsonReviewers.stream()
.map(convertPerson::convert)
.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) {

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.sdk.domain.ProjectJson;
import lombok.RequiredArgsConstructor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
@ -9,6 +10,7 @@ import org.springframework.stereotype.Component;
* @author upagge 14.01.2021
*/
@Component
@RequiredArgsConstructor
public class ProjectJsonConverter implements Converter<ProjectJson, Project> {
@Override

View File

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

View File

@ -1,11 +1,14 @@
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.MergeRequestState;
import dev.struchkov.bot.gitlab.context.domain.PersonInformation;
import dev.struchkov.bot.gitlab.context.domain.ReviewerChanged;
import dev.struchkov.bot.gitlab.context.domain.entity.Discussion;
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequest;
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
import dev.struchkov.bot.gitlab.context.domain.entity.Project;
import dev.struchkov.bot.gitlab.context.domain.filter.MergeRequestFilter;
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.MergeRequestsService;
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.core.service.impl.filter.MergeRequestFilterService;
import lombok.NonNull;
@ -24,13 +26,15 @@ import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
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;
@Service
@ -39,7 +43,6 @@ public class MergeRequestsServiceImpl implements MergeRequestsService {
private final NotifyService notifyService;
private final MergeRequestRepository repository;
private final PersonService personService;
private final MergeRequestFilterService filterService;
private final ProjectService projectService;
private final DiscussionService discussionService;
@ -47,141 +50,156 @@ public class MergeRequestsServiceImpl implements MergeRequestsService {
private final PersonInformation personInformation;
@Override
@Transactional
public MergeRequest create(@NonNull MergeRequest mergeRequest) {
if (mergeRequest.getAssignee() != null) {
personService.create(mergeRequest.getAssignee());
}
personService.create(mergeRequest.getAuthor());
mergeRequest.setNotification(true);
final MergeRequest newMergeRequest = repository.save(mergeRequest);
notifyNewPr(newMergeRequest);
notifyNewMergeRequest(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();
if (!newMergeRequest.isConflict()) {
notifyService.send(
NewPrNotify.builder()
.projectName(projectName)
.labels(newMergeRequest.getLabels())
.author(newMergeRequest.getAuthor().getName())
.description(newMergeRequest.getDescription())
.title(newMergeRequest.getTitle())
.url(newMergeRequest.getWebUrl())
.targetBranch(newMergeRequest.getTargetBranch())
.sourceBranch(newMergeRequest.getSourceBranch())
.build()
);
private void notifyUserAboutNewPullRequestIfHeIsAssignee(MergeRequest savedMergeRequest) {
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(
NewPrNotify.builder()
.projectName(projectName)
.labels(savedMergeRequest.getLabels())
.author(author.getName())
.description(savedMergeRequest.getDescription())
.title(savedMergeRequest.getTitle())
.url(savedMergeRequest.getWebUrl())
.targetBranch(savedMergeRequest.getTargetBranch())
.sourceBranch(savedMergeRequest.getSourceBranch())
.build()
);
}
}
}
}
@Override
public MergeRequest update(@NonNull MergeRequest mergeRequest) {
if (mergeRequest.getAssignee() != null) {
personService.create(mergeRequest.getAssignee());
/**
* Создатель 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);
}
}
}
personService.create(mergeRequest.getAuthor());
}
private void sendNotifyAboutNewMr(MergeRequest savedMergeRequest, String projectName) {
notifyService.send(
NewPrNotify.builder()
.projectName(projectName)
.labels(savedMergeRequest.getLabels())
.author(savedMergeRequest.getAuthor().getName())
.description(savedMergeRequest.getDescription())
.title(savedMergeRequest.getTitle())
.url(savedMergeRequest.getWebUrl())
.targetBranch(savedMergeRequest.getTargetBranch())
.sourceBranch(savedMergeRequest.getSourceBranch())
.build()
);
}
@Override
@Transactional
public MergeRequest update(@NonNull MergeRequest mergeRequest) {
final MergeRequest oldMergeRequest = repository.findById(mergeRequest.getId())
.orElseThrow(notFoundException("МержРеквест не найден"));
.orElseThrow(notFoundException("MergeRequest не найден"));
if (mergeRequest.getNotification() == null) {
final Boolean notification = oldMergeRequest.getNotification();
if (checkNotNull(notification)) {
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());
if (TRUE.equals(oldMergeRequest.getNotification())) {
notifyStatus(oldMergeRequest, mergeRequest, project);
notifyConflict(oldMergeRequest, mergeRequest, project);
notifyUpdate(oldMergeRequest, mergeRequest, project);
if (TRUE.equals(notification) && isChangedMr) {
notifyAboutStatus(oldMergeRequest, mergeRequest, project);
notifyAboutConflict(oldMergeRequest, mergeRequest, project);
notifyAboutUpdate(oldMergeRequest, mergeRequest, project);
}
if (TRUE.equals(notification) && isChangedLinkedEntity) {
notifyReviewer(reviewerChanged, mergeRequest, project);
notifyAssignee(assigneeChanged, mergeRequest, project);
}
return repository.save(mergeRequest);
}
return oldMergeRequest;
}
private void notifyUpdate(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) {
if (
!personInformation.getId().equals(mergeRequest.getAuthor().getId())
&& !oldMergeRequest.getDateLastCommit().equals(mergeRequest.getDateLastCommit())
&& !mergeRequest.isConflict()
) {
final List<Discussion> discussions = discussionService.getAllByMergeRequestId(oldMergeRequest.getId())
.stream()
.filter(discussion -> Objects.nonNull(discussion.getResponsible()))
.toList();
final long allTask = discussions.size();
final long resolvedTask = discussions.stream()
.filter(Discussion::getResolved)
.count();
final long allYouTasks = discussions.stream()
.filter(discussion -> personInformation.getId().equals(discussion.getFirstNote().getAuthor().getId()))
.count();
final long resolvedYouTask = discussions.stream()
.filter(discussion -> personInformation.getId().equals(discussion.getFirstNote().getAuthor().getId()) && discussion.getResolved())
.count();
notifyService.send(
UpdatePrNotify.builder()
.author(oldMergeRequest.getAuthor().getName())
.name(oldMergeRequest.getTitle())
.projectKey(project.getName())
.url(oldMergeRequest.getWebUrl())
.allTasks(allTask)
.allResolvedTasks(resolvedTask)
.personTasks(allYouTasks)
.personResolvedTasks(resolvedYouTask)
.build()
);
//TODO [05.12.2022|uPagge]: Добавить уведомление, если происходит удаление
private void notifyAssignee(AssigneeChanged assigneeChanged, MergeRequest mergeRequest, Project project) {
switch (assigneeChanged) {
case BECOME -> sendNotifyAboutNewMr(mergeRequest, project.getName());
}
}
protected void notifyConflict(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) {
if (
!oldMergeRequest.isConflict()
&& mergeRequest.isConflict()
&& personInformation.getId().equals(oldMergeRequest.getAuthor().getId())
) {
notifyService.send(
ConflictPrNotify.builder()
.sourceBranch(oldMergeRequest.getSourceBranch())
.name(mergeRequest.getTitle())
.url(mergeRequest.getWebUrl())
.projectKey(project.getName())
.build()
);
//TODO [05.12.2022|uPagge]: Добавить уведомление, если происходит удаление ревьювера
//TODO [05.12.2022|uPagge]: Заменить тип уведомления на самостоятельный
private void notifyReviewer(ReviewerChanged reviewerChanged, MergeRequest mergeRequest, Project project) {
switch (reviewerChanged) {
case BECOME -> sendNotifyAboutNewMr(mergeRequest, project.getName());
}
}
protected void notifyStatus(MergeRequest oldMergeRequest, MergeRequest newMergeRequest, Project project) {
final MergeRequestState oldStatus = oldMergeRequest.getState();
final MergeRequestState newStatus = newMergeRequest.getState();
if (
!oldStatus.equals(newStatus)
&& oldMergeRequest.getAuthor().getId().equals(personInformation.getId())
) {
notifyService.send(
StatusPrNotify.builder()
.name(newMergeRequest.getTitle())
.url(oldMergeRequest.getWebUrl())
.projectName(project.getName())
.newStatus(newStatus)
.oldStatus(oldStatus)
.build()
);
}
@Override
@Transactional
public List<MergeRequest> updateAll(@NonNull List<MergeRequest> mergeRequests) {
return mergeRequests.stream()
.map(this::update)
.collect(Collectors.toList());
}
@Override
@ -200,16 +218,16 @@ public class MergeRequestsServiceImpl implements MergeRequestsService {
}
@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 Set<Long> existsIds = existsEntity.stream().map(MergeRequest::getId).collect(Collectors.toSet());
if (existsIds.containsAll(mergeRequestIds)) {
return ExistsContainer.allFind(existsEntity);
return ExistContainer.allFind(existsEntity);
} else {
final Set<Long> noExistsId = mergeRequestIds.stream()
.filter(id -> !existsIds.contains(id))
.collect(Collectors.toSet());
return ExistsContainer.notAllFind(existsEntity, noExistsId);
return ExistContainer.notAllFind(existsEntity, noExistsId);
}
}
@ -221,8 +239,96 @@ public class MergeRequestsServiceImpl implements MergeRequestsService {
}
@Override
@Transactional
public void deleteAllById(@NonNull Set<Long> 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;
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.repository.PersonRepository;
import dev.struchkov.bot.gitlab.context.service.PersonService;
@ -40,16 +40,16 @@ public class PersonServiceImpl implements PersonService {
}
@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 Set<Long> existsIds = existsEntity.stream().map(Person::getId).collect(Collectors.toSet());
if (existsIds.containsAll(personIds)) {
return ExistsContainer.allFind(existsEntity);
return ExistContainer.allFind(existsEntity);
} else {
final Set<Long> noExistsId = personIds.stream()
.filter(id -> !existsIds.contains(id))
.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;
import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
import dev.struchkov.bot.gitlab.context.domain.PersonInformation;
import dev.struchkov.bot.gitlab.context.domain.PipelineStatus;
import dev.struchkov.bot.gitlab.context.domain.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.repository.PipelineRepository;
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.core.service.impl.filter.PipelineFilterService;
import dev.struchkov.haiti.context.domain.ExistsContainer;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
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.SUCCESS;
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 PipelineRepository repository;
private final PersonService personService;
private final PipelineFilterService pipelineFilterService;
private final PersonInformation personInformation;
@Override
@Transactional
public Pipeline create(@NonNull Pipeline pipeline) {
personService.create(pipeline.getPerson());
final Pipeline newPipeline = repository.save(pipeline);
notifyNewPipeline(pipeline, "n/a");
return newPipeline;
@ -87,7 +87,7 @@ public class PipelineServiceImpl implements PipelineService {
private boolean isNeedNotifyNewPipeline(@NonNull Pipeline pipeline) {
final Person personPipelineCreator = pipeline.getPerson();
return notificationStatus.contains(pipeline.getStatus()) // Пайплайн имеет статус необходимый для уведомления
&& personPipelineCreator != null
&& checkNotNull(personPipelineCreator) // Создатель пайплайна не null
&& personInformation.getId().equals(personPipelineCreator.getId()); // Пользователь приложения является инициатором пайплайна
}
@ -102,16 +102,16 @@ public class PipelineServiceImpl implements PipelineService {
}
@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 Set<Long> existsIds = existsEntity.stream().map(Pipeline::getId).collect(Collectors.toSet());
if (existsIds.containsAll(pipelineIds)) {
return ExistsContainer.allFind(existsEntity);
return ExistContainer.allFind(existsEntity);
} else {
final Set<Long> noExistsId = pipelineIds.stream()
.filter(id -> !existsIds.contains(id))
.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;
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.entity.Project;
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.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Set;
@ -34,12 +35,15 @@ public class ProjectServiceImpl implements ProjectService {
private final PersonInformation personInformation;
@Override
@Transactional
public Project create(@NonNull Project 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();
sendNotifyNewProject(newProject, authorName);
notifyAboutNewProject(newProject, authorName);
}
return newProject;
@ -74,20 +78,20 @@ public class ProjectServiceImpl implements ProjectService {
}
@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 Set<Long> existsIds = existsEntity.stream().map(Project::getId).collect(Collectors.toSet());
if (existsIds.containsAll(projectIds)) {
return ExistsContainer.allFind(existsEntity);
return ExistContainer.allFind(existsEntity);
} else {
final Set<Long> noExistsId = projectIds.stream()
.filter(id -> !existsIds.contains(id))
.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(
NewProjectNotify.builder()
.projectDescription(newProject.getDescription())

View File

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

View File

@ -1,9 +1,10 @@
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.MergeRequestState;
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.service.MergeRequestsService;
import dev.struchkov.bot.gitlab.context.service.ProjectService;
@ -22,10 +23,15 @@ import org.springframework.stereotype.Service;
import java.text.MessageFormat;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
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;
@Slf4j
@ -47,19 +53,20 @@ public class MergeRequestParser {
public void parsingOldMergeRequest() {
final Set<IdAndStatusPr> existIds = mergeRequestsService.getAllId(OLD_STATUSES);
for (IdAndStatusPr existId : existIds) {
final String mrUrl = MessageFormat.format(gitlabProperty.getUrlPullRequest(), existId.getProjectId(), existId.getTwoId());
final Optional<MergeRequestJson> json = HttpParse.request(mrUrl)
.header(ACCEPT)
.header(StringUtils.H_PRIVATE_TOKEN, personProperty.getToken())
.execute(MergeRequestJson.class);
final Optional<MergeRequest> mergeRequest = json
.map(mergeRequestJson -> {
final MergeRequest newMergeRequest = conversionService.convert(mergeRequestJson, MergeRequest.class);
parsingCommits(newMergeRequest);
return newMergeRequest;
});
mergeRequest.ifPresent(mergeRequestsService::update);
final List<MergeRequest> mergeRequests = existIds.stream()
.map(this::getMergeRequest)
.filter(Optional::isPresent)
.map(Optional::get)
.map(mergeRequestJson -> {
final MergeRequest newMergeRequest = conversionService.convert(mergeRequestJson, MergeRequest.class);
parsingCommits(newMergeRequest);
return newMergeRequest;
})
.collect(Collectors.toList());
if (checkNotEmpty(mergeRequests)) {
personMapping(mergeRequests);
mergeRequestsService.updateAll(mergeRequests);
}
}
@ -83,22 +90,25 @@ public class MergeRequestParser {
int page = 1;
List<MergeRequestJson> mergeRequestJsons = getMergeRequestJsons(project, page);
while (!mergeRequestJsons.isEmpty()) {
while (checkNotEmpty(mergeRequestJsons)) {
final Set<Long> jsonIds = mergeRequestJsons.stream()
.map(MergeRequestJson::getId)
.collect(Collectors.toSet());
final ExistsContainer<MergeRequest, Long> existsContainer = mergeRequestsService.existsById(jsonIds);
if (!existsContainer.isAllFound()) {
final ExistContainer<MergeRequest, Long> existContainer = mergeRequestsService.existsById(jsonIds);
if (!existContainer.isAllFound()) {
final List<MergeRequest> newMergeRequests = mergeRequestJsons.stream()
.filter(json -> existsContainer.getIdNoFound().contains(json.getId()))
.filter(json -> existContainer.getIdNoFound().contains(json.getId()))
.map(json -> {
final MergeRequest mergeRequest = conversionService.convert(json, MergeRequest.class);
parsingCommits(mergeRequest);
return mergeRequest;
})
.toList();
personMapping(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) {
final List<CommitJson> commitJson = HttpParse.request(
MessageFormat.format(gitlabProperty.getUrlCommit(), mergeRequest.getProjectId(), mergeRequest.getTwoId())
@ -125,4 +161,12 @@ public class MergeRequestParser {
.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;
import dev.struchkov.bot.gitlab.context.domain.ExistContainer;
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.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.utils.StringUtils;
import dev.struchkov.bot.gitlab.sdk.domain.PipelineJson;
import dev.struchkov.haiti.context.domain.ExistsContainer;
import dev.struchkov.haiti.utils.network.HttpParse;
import lombok.RequiredArgsConstructor;
import org.springframework.core.convert.ConversionService;
@ -19,7 +19,6 @@ import org.springframework.stereotype.Service;
import java.text.MessageFormat;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Set;
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.WAITING_FOR_RESOURCE;
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;
/**
@ -75,17 +75,17 @@ public class PipelineParser {
LocalDateTime newLastUpdate = LocalDateTime.now();
List<PipelineJson> pipelineJsons = getPipelineJsons(project.getId(), page, lastUpdate);
while (!pipelineJsons.isEmpty()) {
while (checkNotEmpty(pipelineJsons)) {
final Set<Long> jsonIds = pipelineJsons.stream()
.map(PipelineJson::getId)
.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) {
final Pipeline newPipeline = HttpParse.request(

View File

@ -1,6 +1,6 @@
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.Project;
import dev.struchkov.bot.gitlab.context.service.PersonService;
@ -15,6 +15,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.text.MessageFormat;
import java.util.Collection;
@ -46,10 +47,12 @@ public class ProjectParser {
private final GitlabProperty gitlabProperty;
private final PersonProperty personProperty;
@Transactional
public void parseAllPrivateProject() {
parseProjects(PRIVATE);
}
@Transactional
public void parseAllProjectOwner() {
parseProjects(OWNER);
}
@ -66,9 +69,9 @@ public class ProjectParser {
createNewPersons(projectJsons);
final ExistsContainer<Project, Long> existsContainer = projectService.existsById(projectIds);
final ExistContainer<Project, Long> existContainer = projectService.existsById(projectIds);
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))
.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) {
final Set<Long> personCreatorId = projectJsons.stream()
.map(ProjectJson::getCreatorId)
.collect(Collectors.toSet());
final ExistsContainer<Person, Long> existsContainer = personService.existsById(personCreatorId);
final ExistContainer<Person, Long> existContainer = personService.existsById(personCreatorId);
if (!existsContainer.isAllFound()) {
final Collection<Long> notFoundId = existsContainer.getIdNoFound();
if (!existContainer.isAllFound()) {
final Collection<Long> notFoundId = existContainer.getIdNoFound();
final List<Person> newPersons = notFoundId.stream()
.map(
@ -113,16 +130,4 @@ public class ProjectParser {
.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>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
</dependencies>

View File

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

View File

@ -63,4 +63,9 @@ public class MergeRequestRepositoryImpl implements MergeRequestRepository {
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> {
Set<MergeRequest> findAllByIdIn(Set<Long> ids);
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")
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();
@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);
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.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.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-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-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
users-url: ${GITLAB_URL}/api/v4/users
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
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-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.1.3/changelog.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@ -2,7 +2,7 @@
<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.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">
<insert tableName="app_setting">

View File

@ -1,7 +1,7 @@
<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-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">
<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 java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
/**
@ -40,6 +41,8 @@ public class MergeRequestJson {
private PersonJson author;
private PersonJson assignee;
private List<PersonJson> reviewers;
@JsonProperty("web_url")
private String webUrl;

22
pom.xml
View File

@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.2</version>
<version>2.6.14</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
@ -44,7 +44,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<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>
@ -152,12 +152,6 @@
<version>${postgresql.version}</version>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<version>${liquibase.version}</version>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
@ -182,18 +176,6 @@
<!-- /утилиты -->
<!-- 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 -->
<!-- http -->

View File

@ -25,7 +25,7 @@ public class StartNotify {
if (!settingService.isFirstStart()) {
notifyService.send(
SimpleTextNotify.builder()
.message("Привет. Желаю продуктивного дня :)" +
.message("Hello. I wish you a productive day :)" +
"\n-- -- -- -- --\n" +
"Version " + appProperty.getVersion() + " | Developer: [uPagge](https://mark.struchkov.dev)")
.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.simple.core.unit.AnswerText;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.haiti.utils.Checker;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Component;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@ -92,9 +90,10 @@ public class MenuConfig {
public AnswerText<Mail> addNewProject() {
return AnswerText.<Mail>builder()
.answer(mail -> {
final List<String> urlList = Arrays.stream(mail.getText().split("/")).toList();
int lastElement = urlList.size() - 1;
final String projectUrl = MessageFormat.format(gitlabProperty.getUrlMergeRequestAdd(), urlList.get(lastElement - 1), urlList.get(lastElement));
final String mailText = mail.getText();
final String projectUrl = gitlabProperty.getUrlMergeRequestAdd() + mailText.replace(gitlabProperty.getBaseUrl(), "")
.substring(1)
.replace("/", "%2F");
projectParser.parseByUrl(projectUrl);
return boxAnswer("Project added successfully");
})
@ -136,10 +135,9 @@ public class MenuConfig {
return AnswerText.<Mail>builder()
.triggerPhrase(GET_ASSIGNEE_MERGE_REQUEST)
.answer(() -> {
final Long userId = personInformation.getId();
final Page<MergeRequest> sheet = mergeRequestsService.getAll(getAssigneeFilter(userId), PageRequest.of(0, 20));
if (sheet.hasContent()) {
final List<MergeRequest> mergeRequests = sheet.getContent();
final Long gitlabUserId = personInformation.getId();
final List<MergeRequest> mergeRequests = mergeRequestsService.getAllByReviewerId(gitlabUserId);
if (Checker.checkNotEmpty(mergeRequests)) {
final String text = mergeRequests.stream()
.map(mergeRequest -> MessageFormat.format("[{0}]({1})", mergeRequest.getTitle(), mergeRequest.getWebUrl()))
.collect(Collectors.joining("\n"));
@ -150,6 +148,7 @@ public class MenuConfig {
.build();
}
private MergeRequestFilter getAssigneeFilter(Long userId) {
final MergeRequestFilter mergeRequestFilter = new MergeRequestFilter();
mergeRequestFilter.setAssignee(userId);