Вынес вызовы к gitlab в отдельный модуль
This commit is contained in:
parent
d2e1fdbfcb
commit
5c8ddb8e08
@ -11,7 +11,6 @@ import lombok.Setter;
|
||||
@Setter
|
||||
public class PersonProperty {
|
||||
|
||||
private String token;
|
||||
private String telegramId;
|
||||
|
||||
}
|
||||
|
@ -67,10 +67,7 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
|
@ -1,7 +1,7 @@
|
||||
package dev.struchkov.bot.gitlab.core.convert;
|
||||
|
||||
import dev.struchkov.bot.gitlab.context.domain.entity.Discussion;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.DiscussionJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.DiscussionJson;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
@ -3,9 +3,9 @@ package dev.struchkov.bot.gitlab.core.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 dev.struchkov.bot.gitlab.sdk.domain.json.MergeRequestJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.MergeRequestStateJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.PersonJson;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package dev.struchkov.bot.gitlab.core.convert;
|
||||
|
||||
import dev.struchkov.bot.gitlab.context.domain.entity.Note;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.NoteJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.NoteJson;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package dev.struchkov.bot.gitlab.core.convert;
|
||||
|
||||
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.PersonJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.PersonJson;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
@ -2,8 +2,8 @@ package dev.struchkov.bot.gitlab.core.convert;
|
||||
|
||||
import dev.struchkov.bot.gitlab.context.domain.PipelineStatus;
|
||||
import dev.struchkov.bot.gitlab.context.domain.entity.Pipeline;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.PipelineJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.PipelineStatusJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.PipelineJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.PipelineStatusJson;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package dev.struchkov.bot.gitlab.core.convert;
|
||||
|
||||
import dev.struchkov.bot.gitlab.context.domain.entity.Project;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.ProjectJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.ProjectJson;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
@ -5,14 +5,13 @@ import dev.struchkov.bot.gitlab.context.domain.entity.Discussion;
|
||||
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequestForDiscussion;
|
||||
import dev.struchkov.bot.gitlab.context.domain.entity.Note;
|
||||
import dev.struchkov.bot.gitlab.context.domain.entity.Person;
|
||||
import dev.struchkov.bot.gitlab.context.prop.GitlabProperty;
|
||||
import dev.struchkov.bot.gitlab.context.prop.PersonProperty;
|
||||
import dev.struchkov.bot.gitlab.context.service.DiscussionService;
|
||||
import dev.struchkov.bot.gitlab.context.service.MergeRequestsService;
|
||||
import dev.struchkov.bot.gitlab.core.utils.HttpParse;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.DiscussionJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.GitlabSdkManager;
|
||||
import dev.struchkov.bot.gitlab.sdk.config.GitlabProperty;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.DiscussionJson;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@ -21,15 +20,11 @@ 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.concurrent.ForkJoinPool;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static dev.struchkov.bot.gitlab.core.utils.HttpParse.ACCEPT;
|
||||
import static dev.struchkov.bot.gitlab.core.utils.StringUtils.H_PRIVATE_TOKEN;
|
||||
import static dev.struchkov.haiti.utils.Checker.checkFalse;
|
||||
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
|
||||
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
|
||||
@ -41,35 +36,20 @@ import static dev.struchkov.haiti.utils.Checker.checkNotNull;
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class DiscussionParser {
|
||||
|
||||
public static final int PAGE_COUNT = 100;
|
||||
|
||||
//TODO [23.08.2024|uPagge]: Убрать
|
||||
private final GitlabProperty gitlabProperty;
|
||||
private final GitlabSdkManager gitlabSdkManager;
|
||||
|
||||
private final DiscussionService discussionService;
|
||||
|
||||
private final MergeRequestsService mergeRequestsService;
|
||||
private final ConversionService conversionService;
|
||||
private final ForkJoinPool forkJoinPool;
|
||||
|
||||
private final GitlabProperty gitlabProperty;
|
||||
|
||||
private final PersonProperty personProperty;
|
||||
|
||||
public DiscussionParser(
|
||||
DiscussionService discussionService,
|
||||
MergeRequestsService mergeRequestsService,
|
||||
ConversionService conversionService,
|
||||
@Qualifier("parserPool") ForkJoinPool forkJoinPool,
|
||||
GitlabProperty gitlabProperty,
|
||||
PersonProperty personProperty
|
||||
) {
|
||||
this.discussionService = discussionService;
|
||||
this.mergeRequestsService = mergeRequestsService;
|
||||
this.conversionService = conversionService;
|
||||
this.forkJoinPool = forkJoinPool;
|
||||
this.gitlabProperty = gitlabProperty;
|
||||
this.personProperty = personProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Поиск новых обсуждений
|
||||
@ -85,11 +65,11 @@ public class DiscussionParser {
|
||||
|
||||
private void processingNewDiscussion(MergeRequestForDiscussion mergeRequest) {
|
||||
int page = 1;
|
||||
final List<DiscussionJson> discussionJson = getDiscussionJson(mergeRequest, page);
|
||||
final List<DiscussionJson> discussionJson = gitlabSdkManager.getDiscussionForMergeRequest(mergeRequest.getProjectId(), mergeRequest.getTwoId(), page);
|
||||
|
||||
if (checkNotEmpty(discussionJson)) {
|
||||
while (discussionJson.size() == PAGE_COUNT) {
|
||||
discussionJson.addAll(getDiscussionJson(mergeRequest, ++page));
|
||||
discussionJson.addAll(gitlabSdkManager.getDiscussionForMergeRequest(mergeRequest.getProjectId(), mergeRequest.getTwoId(), ++page));
|
||||
}
|
||||
createNewDiscussion(discussionJson, mergeRequest);
|
||||
}
|
||||
@ -170,11 +150,12 @@ public class DiscussionParser {
|
||||
|
||||
final List<Discussion> newDiscussions = new ArrayList<>();
|
||||
for (Discussion discussion : discussions) {
|
||||
if (checkNotNull(discussion.getMergeRequest())) {
|
||||
getOldDiscussionJson(discussion)
|
||||
final MergeRequestForDiscussion mergeRequest = discussion.getMergeRequest();
|
||||
if (checkNotNull(mergeRequest)) {
|
||||
gitlabSdkManager.getDiscussionById(mergeRequest.getProjectId(), mergeRequest.getTwoId(), discussion.getId())
|
||||
.map(json -> {
|
||||
final Discussion newDiscussion = conversionService.convert(json, Discussion.class);
|
||||
newDiscussion.getNotes().forEach(createNoteLink(discussion.getMergeRequest()));
|
||||
newDiscussion.getNotes().forEach(createNoteLink(mergeRequest));
|
||||
return newDiscussion;
|
||||
}).ifPresent(newDiscussions::add);
|
||||
} else {
|
||||
@ -190,29 +171,6 @@ public class DiscussionParser {
|
||||
log.debug("Конец обработки старых дискуссий");
|
||||
}
|
||||
|
||||
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.getDiscussionUrl(),
|
||||
discussion.getMergeRequest().getProjectId(),
|
||||
discussion.getMergeRequest().getTwoId(),
|
||||
discussion.getId()
|
||||
);
|
||||
}
|
||||
|
||||
private List<DiscussionJson> getDiscussionJson(MergeRequestForDiscussion mergeRequest, int page) {
|
||||
return HttpParse.request(MessageFormat.format(gitlabProperty.getDiscussionsUrl(), mergeRequest.getProjectId(), mergeRequest.getTwoId(), page, PAGE_COUNT))
|
||||
.header(ACCEPT)
|
||||
.header(H_PRIVATE_TOKEN, personProperty.getToken())
|
||||
.executeList(DiscussionJson.class);
|
||||
}
|
||||
|
||||
private Consumer<Note> createNoteLink(MergeRequestForDiscussion mergeRequest) {
|
||||
return note -> {
|
||||
final String url = MessageFormat.format(
|
||||
|
@ -1,89 +1,61 @@
|
||||
package dev.struchkov.bot.gitlab.core.parser;
|
||||
|
||||
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.prop.GitlabProperty;
|
||||
import dev.struchkov.bot.gitlab.context.prop.PersonProperty;
|
||||
import dev.struchkov.bot.gitlab.context.service.MergeRequestsService;
|
||||
import dev.struchkov.bot.gitlab.context.service.ProjectService;
|
||||
import dev.struchkov.bot.gitlab.core.parser.forktask.GetAllMergeRequestForProjectTask;
|
||||
import dev.struchkov.bot.gitlab.core.parser.forktask.GetSingleMergeRequestTask;
|
||||
import dev.struchkov.bot.gitlab.core.utils.HttpParse;
|
||||
import dev.struchkov.bot.gitlab.core.utils.StringUtils;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.ApprovalContainerJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.ApprovalJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.CommitJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.MergeRequestJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.GitlabSdkManager;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.ApprovalJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.CommitJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.MergeRequestJson;
|
||||
import dev.struchkov.haiti.utils.container.Pair;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
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.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.ForkJoinTask;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static dev.struchkov.bot.gitlab.core.utils.HttpParse.ACCEPT;
|
||||
import static dev.struchkov.haiti.context.exception.ConvertException.convertException;
|
||||
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
|
||||
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
|
||||
import static dev.struchkov.haiti.utils.concurrent.ForkJoinUtils.pullTaskResult;
|
||||
import static dev.struchkov.haiti.utils.concurrent.ForkJoinUtils.pullTaskResults;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class MergeRequestParser {
|
||||
|
||||
private static final Set<MergeRequestState> OLD_STATUSES = Set.of(
|
||||
MergeRequestState.MERGED, MergeRequestState.OPENED, MergeRequestState.CLOSED
|
||||
);
|
||||
|
||||
private final GitlabProperty gitlabProperty;
|
||||
private final GitlabSdkManager gitlabSdkManager;
|
||||
|
||||
private final MergeRequestsService mergeRequestsService;
|
||||
private final ProjectService projectService;
|
||||
private final ConversionService conversionService;
|
||||
private final PersonProperty personProperty;
|
||||
|
||||
private final ForkJoinPool forkJoinPool;
|
||||
|
||||
public MergeRequestParser(
|
||||
GitlabProperty gitlabProperty,
|
||||
MergeRequestsService mergeRequestsService,
|
||||
ProjectService projectService,
|
||||
ConversionService conversionService,
|
||||
PersonProperty personProperty,
|
||||
@Qualifier("parserPool") ForkJoinPool forkJoinPool
|
||||
) {
|
||||
this.gitlabProperty = gitlabProperty;
|
||||
this.mergeRequestsService = mergeRequestsService;
|
||||
this.projectService = projectService;
|
||||
this.conversionService = conversionService;
|
||||
this.personProperty = personProperty;
|
||||
this.forkJoinPool = forkJoinPool;
|
||||
}
|
||||
|
||||
public void parsingOldMergeRequest() {
|
||||
log.debug("Старт обработки старых MR");
|
||||
final Set<IdAndStatusPr> existIds = mergeRequestsService.getAllId(OLD_STATUSES);
|
||||
final Set<Pair<Long, Long>> existIds = mergeRequestsService.getAllId(OLD_STATUSES).stream()
|
||||
.map(idAndStatusPr -> new Pair<>(idAndStatusPr.getProjectId(), idAndStatusPr.getTwoId()))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
final List<MergeRequest> newMergeRequests = getOldMergeRequests(existIds).stream()
|
||||
final List<MergeRequest> newMergeRequests = gitlabSdkManager.getAllMergeRequestById(existIds).stream()
|
||||
.map(mergeRequestJson -> {
|
||||
final MergeRequest newMergeRequest = conversionService.convert(mergeRequestJson, MergeRequest.class);
|
||||
parsingCommits(newMergeRequest);
|
||||
parsingApprovals(newMergeRequest);
|
||||
return newMergeRequest;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
.collect(toList());
|
||||
|
||||
if (checkNotEmpty(newMergeRequests)) {
|
||||
personMapping(newMergeRequests);
|
||||
@ -92,28 +64,11 @@ public class MergeRequestParser {
|
||||
log.debug("Конец обработки старых MR");
|
||||
}
|
||||
|
||||
private List<MergeRequestJson> getOldMergeRequests(Set<IdAndStatusPr> existIds) {
|
||||
final List<ForkJoinTask<Optional<MergeRequestJson>>> tasks = existIds.stream()
|
||||
.map(
|
||||
existId -> new GetSingleMergeRequestTask(
|
||||
gitlabProperty.getMergeRequestUrl(),
|
||||
existId.getProjectId(),
|
||||
existId.getTwoId(),
|
||||
personProperty.getToken()
|
||||
)
|
||||
).map(forkJoinPool::submit)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return pullTaskResult(tasks).stream()
|
||||
.flatMap(Optional::stream)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public void parsingNewMergeRequest() {
|
||||
log.debug("Старт обработки новых MR");
|
||||
final Set<Long> projectIds = projectService.getAllIdByProcessingEnable();
|
||||
|
||||
final List<MergeRequestJson> mergeRequestJsons = getMergeRequests(projectIds);
|
||||
final List<MergeRequestJson> mergeRequestJsons = gitlabSdkManager.getAllMergeRequestByProjectIds(projectIds);
|
||||
|
||||
if (checkNotEmpty(mergeRequestJsons)) {
|
||||
final Set<Long> jsonIds = mergeRequestJsons.stream()
|
||||
@ -143,20 +98,6 @@ public class MergeRequestParser {
|
||||
log.debug("Конец обработки новых MR");
|
||||
}
|
||||
|
||||
/**
|
||||
* Позволяет получить MR для переданных идентификаторов проектов.
|
||||
*
|
||||
* @param projectIds идентификаторы проектов
|
||||
* @return полученные у GitLab MergeRequests
|
||||
*/
|
||||
private List<MergeRequestJson> getMergeRequests(Set<Long> projectIds) {
|
||||
final List<ForkJoinTask<List<MergeRequestJson>>> tasks = projectIds.stream()
|
||||
.map(projectId -> new GetAllMergeRequestForProjectTask(projectId, gitlabProperty.getOpenMergeRequestsUrl(), personProperty.getToken()))
|
||||
.map(forkJoinPool::submit)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return pullTaskResults(tasks);
|
||||
}
|
||||
|
||||
private static void personMapping(List<MergeRequest> newMergeRequests) {
|
||||
final Map<Long, Person> personMap = Stream.concat(
|
||||
@ -179,19 +120,14 @@ public class MergeRequestParser {
|
||||
newMergeRequest.setReviewers(
|
||||
newMergeRequest.getReviewers().stream()
|
||||
.map(reviewer -> personMap.get(reviewer.getId()))
|
||||
.collect(Collectors.toList())
|
||||
.collect(toList())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO [19.01.2024|uPagge]: Переделать в многопоточный режим
|
||||
private void parsingCommits(MergeRequest mergeRequest) {
|
||||
final List<CommitJson> commitJson = HttpParse.request(
|
||||
MessageFormat.format(gitlabProperty.getLastCommitOfMergeRequestUrl(), mergeRequest.getProjectId(), mergeRequest.getTwoId())
|
||||
)
|
||||
.header(ACCEPT)
|
||||
.header(StringUtils.H_PRIVATE_TOKEN, personProperty.getToken())
|
||||
.executeList(CommitJson.class);
|
||||
final List<CommitJson> commitJson = gitlabSdkManager.getAllCommitByProjectId(mergeRequest.getProjectId(), mergeRequest.getTwoId());
|
||||
if (checkNotEmpty(commitJson)) {
|
||||
mergeRequest.setDateLastCommit(commitJson.get(0).getCreatedDate());
|
||||
}
|
||||
@ -199,22 +135,13 @@ public class MergeRequestParser {
|
||||
|
||||
//TODO [19.01.2024|uPagge]: Переделать в многопоточный режим
|
||||
private void parsingApprovals(MergeRequest mergeRequest) {
|
||||
final ApprovalContainerJson approvalContainer = HttpParse.request(
|
||||
MessageFormat.format(gitlabProperty.getMergeRequestApprovalUrl(), mergeRequest.getProjectId(), mergeRequest.getTwoId())
|
||||
)
|
||||
.header(ACCEPT)
|
||||
.header(StringUtils.H_PRIVATE_TOKEN, personProperty.getToken())
|
||||
.execute(ApprovalContainerJson.class)
|
||||
.orElseThrow(convertException("Error request approvals"));
|
||||
final List<Person> personApprovals = gitlabSdkManager.getAllApprovalForMergeRequest(mergeRequest.getProjectId(), mergeRequest.getTwoId()).stream()
|
||||
.map(ApprovalJson::getUser)
|
||||
.map(personJson -> conversionService.convert(personJson, Person.class))
|
||||
.collect(toList());
|
||||
|
||||
|
||||
|
||||
if (checkNotEmpty(approvalContainer.getApprovals())) {
|
||||
final List<Person> approvals = approvalContainer.getApprovals().stream()
|
||||
.map(ApprovalJson::getUser)
|
||||
.map(personJson -> conversionService.convert(personJson, Person.class))
|
||||
.collect(Collectors.toList());
|
||||
mergeRequest.setApprovals(approvals);
|
||||
if (checkNotEmpty(personApprovals)) {
|
||||
mergeRequest.setApprovals(personApprovals);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,26 +3,20 @@ package dev.struchkov.bot.gitlab.core.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.prop.GitlabProperty;
|
||||
import dev.struchkov.bot.gitlab.context.prop.PersonProperty;
|
||||
import dev.struchkov.bot.gitlab.context.service.PipelineService;
|
||||
import dev.struchkov.bot.gitlab.context.service.ProjectService;
|
||||
import dev.struchkov.bot.gitlab.core.parser.forktask.GetPipelineShortTask;
|
||||
import dev.struchkov.bot.gitlab.core.parser.forktask.GetPipelineTask;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.PipelineJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.PipelineShortJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.GitlabSdkManager;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.PipelineShortJson;
|
||||
import dev.struchkov.haiti.utils.container.Pair;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.ForkJoinTask;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.CREATED;
|
||||
@ -33,9 +27,8 @@ 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.utils.Checker.checkFalse;
|
||||
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
|
||||
import static dev.struchkov.haiti.utils.concurrent.ForkJoinUtils.pullTaskResult;
|
||||
import static dev.struchkov.haiti.utils.concurrent.ForkJoinUtils.pullTaskResults;
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
/**
|
||||
* Парсер пайплайнов.
|
||||
@ -44,37 +37,21 @@ import static java.util.stream.Collectors.toMap;
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PipelineParser {
|
||||
|
||||
private static final Set<PipelineStatus> oldStatus = Set.of(
|
||||
CREATED, WAITING_FOR_RESOURCE, PREPARING, PENDING, RUNNING, MANUAL
|
||||
);
|
||||
|
||||
private final GitlabSdkManager gitlabSdkManager;
|
||||
|
||||
private final PipelineService pipelineService;
|
||||
private final ProjectService projectService;
|
||||
private final GitlabProperty gitlabProperty;
|
||||
private final PersonProperty personProperty;
|
||||
private final ConversionService conversionService;
|
||||
private final ForkJoinPool forkJoinPool;
|
||||
|
||||
private LocalDateTime lastUpdate = LocalDateTime.now();
|
||||
|
||||
public PipelineParser(
|
||||
PipelineService pipelineService,
|
||||
ProjectService projectService,
|
||||
GitlabProperty gitlabProperty,
|
||||
PersonProperty personProperty,
|
||||
ConversionService conversionService,
|
||||
@Qualifier("parserPool") ForkJoinPool forkJoinPool
|
||||
) {
|
||||
this.pipelineService = pipelineService;
|
||||
this.projectService = projectService;
|
||||
this.gitlabProperty = gitlabProperty;
|
||||
this.personProperty = personProperty;
|
||||
this.conversionService = conversionService;
|
||||
this.forkJoinPool = forkJoinPool;
|
||||
}
|
||||
|
||||
public void scanNewPipeline() {
|
||||
log.debug("Старт обработки новых пайплайнов");
|
||||
final Set<Long> projectIds = projectService.getAllIdByProcessingEnable();
|
||||
@ -86,9 +63,14 @@ public class PipelineParser {
|
||||
final ExistContainer<Pipeline, Long> existContainer = pipelineService.existsById(pipelineProjectMap.keySet());
|
||||
|
||||
if (checkFalse(existContainer.isAllFound())) {
|
||||
final Set<Long> idsNotFound = existContainer.getIdNoFound();
|
||||
final Set<Pair<Long, Long>> idsNotFound = existContainer.getIdNoFound().stream()
|
||||
.map(pipelineId -> new Pair<>(pipelineProjectMap.get(pipelineId), pipelineId))
|
||||
.collect(toSet());
|
||||
|
||||
final List<Pipeline> newPipelines = getNewPipelines(pipelineProjectMap, idsNotFound);
|
||||
final List<Pipeline> newPipelines = gitlabSdkManager.getAllPipelineForProject(idsNotFound).stream()
|
||||
.map(json -> conversionService.convert(json, Pipeline.class))
|
||||
.collect(Collectors.toList());
|
||||
;
|
||||
|
||||
if (checkNotEmpty(newPipelines)) {
|
||||
pipelineService.createAll(newPipelines);
|
||||
@ -100,63 +82,22 @@ public class PipelineParser {
|
||||
log.debug("Конец обработки новых пайплайнов");
|
||||
}
|
||||
|
||||
private List<Pipeline> getNewPipelines(Map<Long, Long> pipelineIdAndProjectId, Set<Long> idsNotFound) {
|
||||
final List<ForkJoinTask<Optional<PipelineJson>>> tasks = idsNotFound.stream()
|
||||
.map(
|
||||
pipelineId -> GetPipelineTask.builder()
|
||||
.pipelineId(pipelineId)
|
||||
.projectId(pipelineIdAndProjectId.get(pipelineId))
|
||||
.urlPipeline(gitlabProperty.getPipelineUrl())
|
||||
.gitlabToken(personProperty.getToken())
|
||||
.build()
|
||||
)
|
||||
.map(forkJoinPool::submit)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return pullTaskResult(tasks).stream()
|
||||
.flatMap(Optional::stream)
|
||||
.map(json -> conversionService.convert(json, Pipeline.class))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<PipelineShortJson> getPipelineShortJsons(Set<Long> projectIds) {
|
||||
final LocalDateTime newLastUpdate = LocalDateTime.now();
|
||||
final List<ForkJoinTask<List<PipelineShortJson>>> tasks = projectIds.stream()
|
||||
.map(projectId -> new GetPipelineShortTask(
|
||||
gitlabProperty.getPipelinesUrl(),
|
||||
projectId,
|
||||
lastUpdate,
|
||||
personProperty.getToken()
|
||||
))
|
||||
.map(forkJoinPool::submit)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final List<PipelineShortJson> pipelineJsons = pullTaskResults(tasks);
|
||||
|
||||
final List<PipelineShortJson> pipelineJsons = gitlabSdkManager.getAllPipeline(projectIds, lastUpdate.minusHours(12L));
|
||||
lastUpdate = newLastUpdate;
|
||||
return pipelineJsons;
|
||||
}
|
||||
|
||||
|
||||
public void scanOldPipeline() {
|
||||
log.debug("Старт обработки старых пайплайнов");
|
||||
final List<Pipeline> pipelines = pipelineService.getAllByStatuses(oldStatus);
|
||||
|
||||
final List<ForkJoinTask<Optional<PipelineJson>>> tasks = pipelines.stream()
|
||||
.map(
|
||||
pipeline ->
|
||||
GetPipelineTask.builder()
|
||||
.projectId(pipeline.getProjectId())
|
||||
.pipelineId(pipeline.getId())
|
||||
.urlPipeline(gitlabProperty.getPipelineUrl())
|
||||
.gitlabToken(personProperty.getToken())
|
||||
.build()
|
||||
)
|
||||
.map(forkJoinPool::submit)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final List<Pipeline> newPipelines = pullTaskResult(tasks).stream()
|
||||
.flatMap(Optional::stream)
|
||||
final List<Pipeline> newPipelines = gitlabSdkManager.getAllPipelineForProject(
|
||||
pipelines.stream()
|
||||
.map(pipeline -> new Pair<>(pipeline.getProjectId(), pipeline.getId()))
|
||||
.collect(toSet())
|
||||
).stream()
|
||||
.map(json -> conversionService.convert(json, Pipeline.class))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
|
@ -3,27 +3,21 @@ package dev.struchkov.bot.gitlab.core.parser;
|
||||
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.prop.GitlabProperty;
|
||||
import dev.struchkov.bot.gitlab.context.prop.PersonProperty;
|
||||
import dev.struchkov.bot.gitlab.context.service.MergeRequestsService;
|
||||
import dev.struchkov.bot.gitlab.context.service.PersonService;
|
||||
import dev.struchkov.bot.gitlab.context.service.ProjectService;
|
||||
import dev.struchkov.bot.gitlab.core.utils.HttpParse;
|
||||
import dev.struchkov.bot.gitlab.core.utils.StringUtils;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.PersonJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.ProjectJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.GitlabSdkManager;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.GitlabProjectParam;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.ProjectJson;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static dev.struchkov.bot.gitlab.core.utils.HttpParse.ACCEPT;
|
||||
import static dev.struchkov.haiti.context.exception.ConvertException.convertException;
|
||||
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
|
||||
|
||||
@ -37,33 +31,28 @@ import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
|
||||
@RequiredArgsConstructor
|
||||
public class ProjectParser {
|
||||
|
||||
public static final String OWNER = "&owned=true";
|
||||
public static final String PRIVATE = "&visibility=private";
|
||||
private final GitlabSdkManager gitlabSdkManager;
|
||||
private final ConversionService conversionService;
|
||||
|
||||
private final MergeRequestsService mergeRequestsService;
|
||||
private final ProjectService projectService;
|
||||
private final PersonService personService;
|
||||
|
||||
private final ConversionService conversionService;
|
||||
|
||||
private final GitlabProperty gitlabProperty;
|
||||
private final PersonProperty personProperty;
|
||||
|
||||
public void parseAllProjectOwner() {
|
||||
log.debug("Старт обработки всех проектов, где пользователь владелец");
|
||||
parseProjects(OWNER);
|
||||
parseProjects(GitlabProjectParam.OWNER);
|
||||
log.debug("Конец обработки всех проектов, где пользователь владелец");
|
||||
}
|
||||
|
||||
public void parseAllPrivateProject() {
|
||||
log.debug("Старт обработки приватных проектов");
|
||||
parseProjects(PRIVATE);
|
||||
parseProjects(GitlabProjectParam.PRIVATE);
|
||||
log.debug("Конец обработки приватных проектов");
|
||||
}
|
||||
|
||||
private void parseProjects(String param) {
|
||||
private void parseProjects(GitlabProjectParam param) {
|
||||
int page = 1;
|
||||
List<ProjectJson> projectJsons = getProjectJsons(page, param);
|
||||
List<ProjectJson> projectJsons = gitlabSdkManager.getAllProject(page, param);
|
||||
|
||||
while (checkNotEmpty(projectJsons)) {
|
||||
|
||||
@ -83,15 +72,12 @@ public class ProjectParser {
|
||||
projectService.createAll(newProjects);
|
||||
}
|
||||
|
||||
projectJsons = getProjectJsons(++page, param);
|
||||
projectJsons = gitlabSdkManager.getAllProject(++page, param);
|
||||
}
|
||||
}
|
||||
|
||||
public Project parseByUrl(String projectUrl) {
|
||||
final ProjectJson projectJson = HttpParse.request(projectUrl)
|
||||
.header(ACCEPT)
|
||||
.header(StringUtils.H_PRIVATE_TOKEN, personProperty.getToken())
|
||||
.execute(ProjectJson.class)
|
||||
final ProjectJson projectJson = gitlabSdkManager.getProjectByUrl(projectUrl)
|
||||
.orElseThrow(convertException("Error adding a repository"));
|
||||
if (!projectService.existsById(projectJson.getId())) {
|
||||
createNewPersons(List.of(projectJson));
|
||||
@ -114,10 +100,7 @@ public class ProjectParser {
|
||||
|
||||
final List<Person> newPersons = notFoundId.stream()
|
||||
.map(
|
||||
userId -> HttpParse.request(gitlabProperty.getUsersUrl() + "/" + userId)
|
||||
.header(ACCEPT)
|
||||
.header(StringUtils.H_PRIVATE_TOKEN, personProperty.getToken())
|
||||
.execute(PersonJson.class)
|
||||
userId -> gitlabSdkManager.getPersonById(userId)
|
||||
.map(json -> conversionService.convert(json, Person.class))
|
||||
.orElseThrow(convertException("Ошибка преобразования нового пользователя"))
|
||||
).toList();
|
||||
@ -126,13 +109,5 @@ public class ProjectParser {
|
||||
}
|
||||
}
|
||||
|
||||
private List<ProjectJson> getProjectJsons(int page, String... params) {
|
||||
String param = String.join("", params);
|
||||
final String url = MessageFormat.format(gitlabProperty.getProjectsUrl(), page);
|
||||
return HttpParse.request(url + param)
|
||||
.header(ACCEPT)
|
||||
.header(StringUtils.H_PRIVATE_TOKEN, personProperty.getToken())
|
||||
.executeList(ProjectJson.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -10,26 +10,18 @@ import dev.struchkov.bot.gitlab.context.domain.notify.comment.NewCommentNotify;
|
||||
import dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel;
|
||||
import dev.struchkov.bot.gitlab.context.domain.notify.task.DiscussionNewNotify;
|
||||
import dev.struchkov.bot.gitlab.context.domain.notify.task.ThreadCloseNotify;
|
||||
import dev.struchkov.bot.gitlab.context.prop.GitlabProperty;
|
||||
import dev.struchkov.bot.gitlab.context.prop.PersonProperty;
|
||||
import dev.struchkov.bot.gitlab.context.repository.DiscussionRepository;
|
||||
import dev.struchkov.bot.gitlab.context.service.AppSettingService;
|
||||
import dev.struchkov.bot.gitlab.context.service.DiscussionService;
|
||||
import dev.struchkov.bot.gitlab.context.service.NotifyService;
|
||||
import dev.struchkov.bot.gitlab.core.utils.StringUtils;
|
||||
import dev.struchkov.bot.gitlab.sdk.GitlabSdkManager;
|
||||
import dev.struchkov.haiti.utils.container.Pair;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.FormBody;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -59,7 +51,6 @@ import static java.lang.Boolean.TRUE;
|
||||
public class DiscussionServiceImpl implements DiscussionService {
|
||||
|
||||
protected static final Pattern PATTERN = Pattern.compile("@[\\w]+");
|
||||
private final OkHttpClient client = new OkHttpClient();
|
||||
|
||||
private final DiscussionRepository repository;
|
||||
|
||||
@ -67,8 +58,8 @@ public class DiscussionServiceImpl implements DiscussionService {
|
||||
private final AppSettingService settingService;
|
||||
|
||||
private final PersonInformation personInformation;
|
||||
private final GitlabProperty gitlabProperty;
|
||||
private final PersonProperty personProperty;
|
||||
|
||||
private final GitlabSdkManager gitlabSdkManager;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@ -235,20 +226,7 @@ public class DiscussionServiceImpl implements DiscussionService {
|
||||
final MergeRequestForDiscussion mergeRequest = discussion.getMergeRequest();
|
||||
final Long projectId = mergeRequest.getProjectId();
|
||||
|
||||
final String requestUrl = MessageFormat.format(gitlabProperty.getNewNoteUrl(), projectId, mergeRequest.getTwoId(), discussion.getId(), text);
|
||||
|
||||
final RequestBody formBody = new FormBody.Builder().build();
|
||||
|
||||
final Request request = new Request.Builder()
|
||||
.post(formBody)
|
||||
.header(StringUtils.H_PRIVATE_TOKEN, personProperty.getToken())
|
||||
.url(requestUrl)
|
||||
.build();
|
||||
try {
|
||||
client.newCall(request).execute();
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
gitlabSdkManager.sendMessageToDiscussion(projectId, mergeRequest.getTwoId(), discussionId, text);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,99 +0,0 @@
|
||||
package dev.struchkov.bot.gitlab.core.utils;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
public class HttpParse {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(HttpParse.class);
|
||||
private static final ObjectMapper objectMapper;
|
||||
private final HttpHeaders headers = new HttpHeaders();
|
||||
private final UriComponentsBuilder uriBuilder;
|
||||
|
||||
static {
|
||||
objectMapper = new ObjectMapper();
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
}
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
public HttpParse(String url, RestTemplate restTemplate) {
|
||||
this.restTemplate = restTemplate;
|
||||
this.uriBuilder = UriComponentsBuilder.fromHttpUrl(url);
|
||||
}
|
||||
|
||||
public static HttpParse request(String url, RestTemplate restTemplate) {
|
||||
return new HttpParse(url, restTemplate);
|
||||
}
|
||||
|
||||
public HttpParse header(String name, String value) {
|
||||
if (name != null && value != null) {
|
||||
headers.add(name, value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpParse header(HttpHeader header) {
|
||||
if (header != null) {
|
||||
headers.add(header.getName(), header.getValue());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpParse getParameter(String name, String value) {
|
||||
if (name != null && value != null) {
|
||||
uriBuilder.queryParam(name, value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> Optional<T> execute(Class<T> classOfT) {
|
||||
try {
|
||||
String url = uriBuilder.toUriString();
|
||||
log.trace("Выполняется RestTemplate запрос | {}", url);
|
||||
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
|
||||
log.trace("Запрос выполнен | {}", url);
|
||||
if (response.getStatusCode().is2xxSuccessful() && response.hasBody()) {
|
||||
String body = response.getBody();
|
||||
return Optional.ofNullable(objectMapper.readValue(body, classOfT));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("Ошибка выполнения RestTemplate", e);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public <T> List<T> executeList(Class<T> classOfT) {
|
||||
try {
|
||||
String url = uriBuilder.toUriString();
|
||||
log.trace("Выполняется RestTemplate запрос | {}", url);
|
||||
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
|
||||
log.trace("Запрос выполнен | {}", url);
|
||||
if (response.getStatusCode().is2xxSuccessful() && response.hasBody()) {
|
||||
String body = response.getBody();
|
||||
return objectMapper.readValue(body, objectMapper.getTypeFactory().constructCollectionType(List.class, classOfT));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("Ошибка выполнения RestTemplate", e);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
@ -1,125 +0,0 @@
|
||||
//package dev.struchkov.bot.gitlab.core.utils;
|
||||
//
|
||||
//import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
//import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
//import dev.struchkov.haiti.utils.Inspector;
|
||||
//import jakarta.validation.constraints.NotNull;
|
||||
//import okhttp3.HttpUrl;
|
||||
//import okhttp3.OkHttpClient;
|
||||
//import okhttp3.Request;
|
||||
//import okhttp3.Response;
|
||||
//import okhttp3.ResponseBody;
|
||||
//import org.slf4j.Logger;
|
||||
//import org.slf4j.LoggerFactory;
|
||||
//
|
||||
//import java.io.IOException;
|
||||
//import java.util.Collections;
|
||||
//import java.util.List;
|
||||
//import java.util.Optional;
|
||||
//import java.util.concurrent.TimeUnit;
|
||||
//
|
||||
//import static dev.struchkov.haiti.utils.Checker.checkNotNull;
|
||||
//import static dev.struchkov.haiti.utils.Inspector.isNotNull;
|
||||
//
|
||||
///**
|
||||
// * Утилитарный класс для работы с web.
|
||||
// *
|
||||
// * @author upagge 30.09.2020
|
||||
// */
|
||||
//public class HttpParse {
|
||||
//
|
||||
// private static final Logger log = LoggerFactory.getLogger(HttpParse.class);
|
||||
//
|
||||
// public static final HttpHeader ACCEPT = HttpHeader.of("Accept", "text/html,application/xhtml+xml,application/json");
|
||||
//
|
||||
// private static final ObjectMapper objectMapper;
|
||||
//
|
||||
// private final Request.Builder requestBuilder = new Request.Builder();
|
||||
// private final HttpUrl.Builder httpUrlBuilder;
|
||||
//
|
||||
// static {
|
||||
// objectMapper = new ObjectMapper();
|
||||
// objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
// }
|
||||
//
|
||||
// public HttpParse(String url) {
|
||||
// Inspector.isNotNull(url);
|
||||
// httpUrlBuilder = HttpUrl.parse(url).newBuilder();
|
||||
// }
|
||||
//
|
||||
// public static HttpParse request(String url) {
|
||||
// Inspector.isNotNull(url);
|
||||
// return new HttpParse(url);
|
||||
// }
|
||||
//
|
||||
// public HttpParse header(String name, String value) {
|
||||
// isNotNull(name);
|
||||
// if (value != null) {
|
||||
// requestBuilder.header(name, value);
|
||||
// }
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
// public HttpParse header(HttpHeader header) {
|
||||
// isNotNull(header);
|
||||
// requestBuilder.header(header.getName(), header.getValue());
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
// public HttpParse getParameter(String name, String value) {
|
||||
// isNotNull(name);
|
||||
// if (value != null) {
|
||||
// httpUrlBuilder.addQueryParameter(name, value);
|
||||
// }
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
// public <T> Optional<T> execute(Class<T> classOfT) {
|
||||
// isNotNull(classOfT);
|
||||
// final HttpUrl url = httpUrlBuilder.build();
|
||||
// final Request request = requestBuilder.url(url).build();
|
||||
// log.trace("Выполняется okhttp3 запрос | {}", url);
|
||||
// final OkHttpClient httpClient = getNewClient();
|
||||
// try (final Response execute = httpClient.newCall(request).execute()) {
|
||||
// log.trace("Запрос выполнен | {}", url);
|
||||
// if (execute.isSuccessful() && checkNotNull(execute.body())) {
|
||||
// final String string = execute.body().string();
|
||||
// return Optional.ofNullable(objectMapper.readValue(string, classOfT));
|
||||
// }
|
||||
// } catch (IOException e) {
|
||||
// log.error("Ошибка выполнения okhttp3", e);
|
||||
// }
|
||||
// return Optional.empty();
|
||||
// }
|
||||
//
|
||||
// //TODO [16.01.2023|uPagge]: Okhttp Client создается на каждый запрос, что не рационально по потреблению ресурсов и производительности, но позволяет обойти ограничение со стороны гитлаба, при котором один и тот же клиент отбрасывался спустя 1000 запросов. Возможно стоит заменить OkHttp на что-то другое, например, RestTemplate
|
||||
// public <T> List<T> executeList(Class<T> classOfT) {
|
||||
// isNotNull(classOfT);
|
||||
// final HttpUrl url = httpUrlBuilder.build();
|
||||
// final Request request = requestBuilder.url(url).build();
|
||||
// log.trace("Выполняется okhttp3 запрос | {}", url);
|
||||
// final OkHttpClient httpClient = getNewClient();
|
||||
// try (Response execute = httpClient.newCall(request).execute()) {
|
||||
// log.trace("Запрос выполнен | {}", url);
|
||||
// ResponseBody body = execute.body();
|
||||
// if (execute.isSuccessful() && checkNotNull(body)) {
|
||||
// final String stringBody = body.string();
|
||||
// final List<T> list = objectMapper.readValue(stringBody, objectMapper.getTypeFactory().constructCollectionType(List.class, classOfT));
|
||||
// return (list == null || list.isEmpty()) ? Collections.emptyList() : list;
|
||||
// }
|
||||
// } catch (IOException e) {
|
||||
// log.error("Ошибка выполнения okhttp3", e);
|
||||
// }
|
||||
// return Collections.emptyList();
|
||||
// }
|
||||
//
|
||||
// @NotNull
|
||||
// private static OkHttpClient getNewClient() {
|
||||
// return new OkHttpClient().newBuilder()
|
||||
// .connectTimeout(30, TimeUnit.SECONDS)
|
||||
// .readTimeout(30, TimeUnit.SECONDS)
|
||||
// .writeTimeout(30, TimeUnit.SECONDS)
|
||||
// .build();
|
||||
// }
|
||||
//
|
||||
//}
|
@ -2,10 +2,10 @@ package dev.struchkov.bot.gitlab.config;
|
||||
|
||||
import dev.struchkov.bot.gitlab.context.domain.PersonInformation;
|
||||
import dev.struchkov.bot.gitlab.context.prop.AppProperty;
|
||||
import dev.struchkov.bot.gitlab.context.prop.GitlabProperty;
|
||||
import dev.struchkov.bot.gitlab.context.prop.PersonProperty;
|
||||
import dev.struchkov.bot.gitlab.core.utils.HttpParse;
|
||||
import dev.struchkov.bot.gitlab.core.utils.StringUtils;
|
||||
import dev.struchkov.bot.gitlab.sdk.client.HttpParse;
|
||||
import dev.struchkov.bot.gitlab.sdk.client.StringUtils;
|
||||
import dev.struchkov.bot.gitlab.sdk.config.GitlabProperty;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@ -17,7 +17,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
|
||||
import static dev.struchkov.bot.gitlab.core.utils.HttpParse.ACCEPT;
|
||||
import static dev.struchkov.bot.gitlab.sdk.client.HttpParse.ACCEPT;
|
||||
import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException;
|
||||
|
||||
/**
|
||||
@ -76,7 +76,7 @@ public class AppConfig {
|
||||
) {
|
||||
final PersonInformation personInformation = HttpParse.request(gitlabProperty.getUserUrl())
|
||||
.header(ACCEPT)
|
||||
.header(StringUtils.H_PRIVATE_TOKEN, personProperty.getToken())
|
||||
.header(StringUtils.H_PRIVATE_TOKEN, gitlabProperty.getAccessToken())
|
||||
.execute(PersonInformation.class)
|
||||
.orElseThrow(notFoundException("Пользователь не найден"));
|
||||
personInformation.setTelegramId(personProperty.getTelegramId());
|
||||
|
@ -37,7 +37,7 @@ telegram:
|
||||
password: ${PROXY_PASSWORD:}
|
||||
|
||||
gitlab-bot:
|
||||
version: 1.0.0
|
||||
version: 2.0.0
|
||||
cron:
|
||||
scan:
|
||||
general: ${CRON_GENERAL:0 */1 * * * *}
|
||||
@ -45,8 +45,8 @@ gitlab-bot:
|
||||
new-merge-request: ${CRON_NEW_MR:0 */15 * * * *}
|
||||
person:
|
||||
telegram-id: ${TELEGRAM_PERSON_ID}
|
||||
token: ${GITLAB_PERSONAL_TOKEN}
|
||||
gitlab:
|
||||
access-token: ${GITLAB_PERSONAL_TOKEN}
|
||||
base-url: ${GITLAB_URL}
|
||||
replaceUrl: ${GITLAB_REPLACE_URL}
|
||||
users-url: "${GITLAB_URL}/api/v4/users"
|
||||
|
@ -10,6 +10,19 @@
|
||||
<artifactId>gitlab-sdk</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dev.struchkov.haiti</groupId>
|
||||
<artifactId>haiti-utils</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
|
@ -0,0 +1,208 @@
|
||||
package dev.struchkov.bot.gitlab.sdk;
|
||||
|
||||
import dev.struchkov.bot.gitlab.sdk.client.HttpParse;
|
||||
import dev.struchkov.bot.gitlab.sdk.client.StringUtils;
|
||||
import dev.struchkov.bot.gitlab.sdk.config.GitlabProperty;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.GitlabProjectParam;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.ApprovalContainerJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.ApprovalJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.CommitJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.DiscussionJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.MergeRequestJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.PersonJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.PipelineJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.PipelineShortJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.ProjectJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.forktask.GetAllMergeRequestForProjectTask;
|
||||
import dev.struchkov.bot.gitlab.sdk.forktask.GetPipelineShortTask;
|
||||
import dev.struchkov.bot.gitlab.sdk.forktask.GetPipelineTask;
|
||||
import dev.struchkov.bot.gitlab.sdk.forktask.GetSingleMergeRequestTask;
|
||||
import dev.struchkov.haiti.utils.container.Pair;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.FormBody;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.ForkJoinTask;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static dev.struchkov.bot.gitlab.sdk.client.HttpParse.ACCEPT;
|
||||
import static dev.struchkov.bot.gitlab.sdk.client.StringUtils.H_PRIVATE_TOKEN;
|
||||
import static dev.struchkov.haiti.utils.concurrent.ForkJoinUtils.pullTaskResult;
|
||||
import static dev.struchkov.haiti.utils.concurrent.ForkJoinUtils.pullTaskResults;
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class GitlabSdkManager {
|
||||
|
||||
private final ForkJoinPool forkJoinPool;
|
||||
private final GitlabProperty gitlabProperty;
|
||||
|
||||
public Optional<PersonJson> getPersonById(Long userId) {
|
||||
return HttpParse.request(gitlabProperty.getUsersUrl() + "/" + userId)
|
||||
.header(ACCEPT)
|
||||
.header(StringUtils.H_PRIVATE_TOKEN, gitlabProperty.getAccessToken())
|
||||
.execute(PersonJson.class);
|
||||
}
|
||||
|
||||
public List<ProjectJson> getAllProject(int pageNumber, GitlabProjectParam... params) {
|
||||
String param = Arrays.stream(params)
|
||||
.map(GitlabProjectParam::getUrl)
|
||||
.collect(Collectors.joining());
|
||||
final String url = MessageFormat.format(gitlabProperty.getProjectsUrl(), pageNumber);
|
||||
return HttpParse.request(url + param)
|
||||
.header(ACCEPT)
|
||||
.header(StringUtils.H_PRIVATE_TOKEN, gitlabProperty.getAccessToken())
|
||||
.executeList(ProjectJson.class);
|
||||
}
|
||||
|
||||
public Optional<ProjectJson> getProjectByUrl(String projectUrl) {
|
||||
return HttpParse.request(projectUrl)
|
||||
.header(ACCEPT)
|
||||
.header(StringUtils.H_PRIVATE_TOKEN, gitlabProperty.getAccessToken())
|
||||
.execute(ProjectJson.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Позволяет получить MR для переданных идентификаторов проектов.
|
||||
*
|
||||
* @param projectIds идентификаторы проектов
|
||||
* @return полученные у GitLab MergeRequests
|
||||
*/
|
||||
public List<MergeRequestJson> getAllMergeRequestByProjectIds(Set<Long> projectIds) {
|
||||
final List<ForkJoinTask<List<MergeRequestJson>>> tasks = projectIds.stream()
|
||||
.map(projectId -> new GetAllMergeRequestForProjectTask(projectId, gitlabProperty.getOpenMergeRequestsUrl(), gitlabProperty.getAccessToken()))
|
||||
.map(forkJoinPool::submit)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return pullTaskResults(tasks);
|
||||
}
|
||||
|
||||
public List<CommitJson> getAllCommitByProjectId(Long projectId, Long mergeRequestIdForProject) {
|
||||
return HttpParse.request(
|
||||
MessageFormat.format(gitlabProperty.getLastCommitOfMergeRequestUrl(), projectId, mergeRequestIdForProject)
|
||||
)
|
||||
.header(ACCEPT)
|
||||
.header(StringUtils.H_PRIVATE_TOKEN, gitlabProperty.getAccessToken())
|
||||
.executeList(CommitJson.class);
|
||||
}
|
||||
|
||||
public List<ApprovalJson> getAllApprovalForMergeRequest(Long projectId, Long mergeRequestIdForProject) {
|
||||
return HttpParse.request(
|
||||
MessageFormat.format(gitlabProperty.getMergeRequestApprovalUrl(), projectId, mergeRequestIdForProject)
|
||||
)
|
||||
.header(ACCEPT)
|
||||
.header(StringUtils.H_PRIVATE_TOKEN, gitlabProperty.getAccessToken())
|
||||
.execute(ApprovalContainerJson.class)
|
||||
.map(ApprovalContainerJson::getApprovals)
|
||||
.orElse(emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* projectId + mrTwoId
|
||||
*/
|
||||
public List<MergeRequestJson> getAllMergeRequestById(Collection<Pair<Long, Long>> projectIdAndMrIdForProject) {
|
||||
final List<ForkJoinTask<Optional<MergeRequestJson>>> tasks = projectIdAndMrIdForProject.stream()
|
||||
.map(
|
||||
pair -> new GetSingleMergeRequestTask(
|
||||
gitlabProperty.getMergeRequestUrl(),
|
||||
pair.getKey(),
|
||||
pair.getValue(),
|
||||
gitlabProperty.getAccessToken()
|
||||
)
|
||||
).map(forkJoinPool::submit)
|
||||
.collect(toList());
|
||||
|
||||
return pullTaskResult(tasks).stream()
|
||||
.flatMap(Optional::stream)
|
||||
.collect(toList());
|
||||
}
|
||||
|
||||
public List<PipelineJson> getAllPipelineForProject(Collection<Pair<Long, Long>> projectIdAndPipelineId) {
|
||||
final List<ForkJoinTask<Optional<PipelineJson>>> tasks = projectIdAndPipelineId.stream()
|
||||
.map(
|
||||
pair -> GetPipelineTask.builder()
|
||||
.pipelineId(pair.getValue())
|
||||
.projectId(pair.getKey())
|
||||
.urlPipeline(gitlabProperty.getPipelineUrl())
|
||||
.gitlabToken(gitlabProperty.getAccessToken())
|
||||
.build()
|
||||
)
|
||||
.map(forkJoinPool::submit)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return pullTaskResult(tasks).stream()
|
||||
.flatMap(Optional::stream)
|
||||
.collect(toList());
|
||||
}
|
||||
|
||||
public List<PipelineShortJson> getAllPipeline(Collection<Long> projectIds, LocalDateTime updatedAfter) {
|
||||
final List<ForkJoinTask<List<PipelineShortJson>>> tasks = projectIds.stream()
|
||||
.map(projectId -> new GetPipelineShortTask(
|
||||
gitlabProperty.getPipelinesUrl(),
|
||||
projectId,
|
||||
updatedAfter,
|
||||
gitlabProperty.getAccessToken()
|
||||
))
|
||||
.map(forkJoinPool::submit)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return pullTaskResults(tasks);
|
||||
}
|
||||
|
||||
public List<DiscussionJson> getDiscussionForMergeRequest(Long projectId, Long mergeRequestIdForProject, int pageNumber) {
|
||||
return HttpParse.request(MessageFormat.format(gitlabProperty.getDiscussionsUrl(), projectId, mergeRequestIdForProject, pageNumber, pageNumber))
|
||||
.header(ACCEPT)
|
||||
.header(H_PRIVATE_TOKEN, gitlabProperty.getAccessToken())
|
||||
.executeList(DiscussionJson.class);
|
||||
}
|
||||
|
||||
public Optional<DiscussionJson> getDiscussionById(Long projectId, Long mergeRequestIdForProject, String discussionId) {
|
||||
return HttpParse.request(createLinkOldDiscussion(projectId, mergeRequestIdForProject, discussionId))
|
||||
.header(ACCEPT)
|
||||
.header(H_PRIVATE_TOKEN, gitlabProperty.getAccessToken())
|
||||
.execute(DiscussionJson.class);
|
||||
}
|
||||
|
||||
private String createLinkOldDiscussion(Long projectId, Long mergeRequestIdForProject, String discussionId) {
|
||||
return MessageFormat.format(
|
||||
gitlabProperty.getDiscussionUrl(),
|
||||
projectId,
|
||||
mergeRequestIdForProject,
|
||||
discussionId
|
||||
);
|
||||
}
|
||||
|
||||
public void sendMessageToDiscussion(Long projectId, Long mergeRequestIdForProject, String discussionId, String message) {
|
||||
final String requestUrl = MessageFormat.format(gitlabProperty.getNewNoteUrl(), projectId, mergeRequestIdForProject, discussionId, message);
|
||||
|
||||
final RequestBody formBody = new FormBody.Builder().build();
|
||||
|
||||
final Request request = new Request.Builder()
|
||||
.post(formBody)
|
||||
.header(StringUtils.H_PRIVATE_TOKEN, gitlabProperty.getAccessToken())
|
||||
.url(requestUrl)
|
||||
.build();
|
||||
try {
|
||||
HttpParse.getNewClient().newCall(request).execute();
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package dev.struchkov.bot.gitlab.core.utils;
|
||||
package dev.struchkov.bot.gitlab.sdk.client;
|
||||
|
||||
import static dev.struchkov.haiti.utils.Inspector.isNotNull;
|
||||
import dev.struchkov.haiti.utils.Inspector;
|
||||
|
||||
/**
|
||||
* Утилитарная сущность для {@link HttpParse}. Упрощает сохранения в константы заголовков для запроса.
|
||||
@ -18,7 +18,7 @@ public class HttpHeader {
|
||||
}
|
||||
|
||||
public static HttpHeader of(String name, String value) {
|
||||
isNotNull(name, value);
|
||||
Inspector.isNotNull(name, value);
|
||||
return new HttpHeader(name, value);
|
||||
}
|
||||
|
@ -0,0 +1,121 @@
|
||||
package dev.struchkov.bot.gitlab.sdk.client;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import dev.struchkov.haiti.utils.Checker;
|
||||
import dev.struchkov.haiti.utils.Inspector;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Утилитарный класс для работы с web.
|
||||
*
|
||||
* @author upagge 30.09.2020
|
||||
*/
|
||||
public class HttpParse {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(HttpParse.class);
|
||||
|
||||
public static final HttpHeader ACCEPT = HttpHeader.of("Accept", "text/html,application/xhtml+xml,application/json");
|
||||
|
||||
private static final ObjectMapper objectMapper;
|
||||
|
||||
private final Request.Builder requestBuilder = new Request.Builder();
|
||||
private final HttpUrl.Builder httpUrlBuilder;
|
||||
|
||||
static {
|
||||
objectMapper = new ObjectMapper();
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
}
|
||||
|
||||
public HttpParse(String url) {
|
||||
Inspector.isNotNull(url);
|
||||
httpUrlBuilder = HttpUrl.parse(url).newBuilder();
|
||||
}
|
||||
|
||||
public static HttpParse request(String url) {
|
||||
Inspector.isNotNull(url);
|
||||
return new HttpParse(url);
|
||||
}
|
||||
|
||||
public HttpParse header(String name, String value) {
|
||||
Inspector.isNotNull(name);
|
||||
if (value != null) {
|
||||
requestBuilder.header(name, value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpParse header(HttpHeader header) {
|
||||
Inspector.isNotNull(header);
|
||||
requestBuilder.header(header.getName(), header.getValue());
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpParse getParameter(String name, String value) {
|
||||
Inspector.isNotNull(name);
|
||||
if (value != null) {
|
||||
httpUrlBuilder.addQueryParameter(name, value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> Optional<T> execute(Class<T> classOfT) {
|
||||
Inspector.isNotNull(classOfT);
|
||||
final HttpUrl url = httpUrlBuilder.build();
|
||||
final Request request = requestBuilder.url(url).build();
|
||||
log.trace("Выполняется okhttp3 запрос | {}", url);
|
||||
final OkHttpClient httpClient = getNewClient();
|
||||
try (final Response execute = httpClient.newCall(request).execute()) {
|
||||
log.trace("Запрос выполнен | {}", url);
|
||||
if (execute.isSuccessful() && Checker.checkNotNull(execute.body())) {
|
||||
final String string = execute.body().string();
|
||||
return Optional.ofNullable(objectMapper.readValue(string, classOfT));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("Ошибка выполнения okhttp3", e);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
//TODO [16.01.2023|uPagge]: Okhttp Client создается на каждый запрос, что не рационально по потреблению ресурсов и производительности, но позволяет обойти ограничение со стороны гитлаба, при котором один и тот же клиент отбрасывался спустя 1000 запросов. Возможно стоит заменить OkHttp на что-то другое, например, RestTemplate
|
||||
public <T> List<T> executeList(Class<T> classOfT) {
|
||||
Inspector.isNotNull(classOfT);
|
||||
final HttpUrl url = httpUrlBuilder.build();
|
||||
final Request request = requestBuilder.url(url).build();
|
||||
log.trace("Выполняется okhttp3 запрос | {}", url);
|
||||
final OkHttpClient httpClient = getNewClient();
|
||||
try (Response execute = httpClient.newCall(request).execute()) {
|
||||
log.trace("Запрос выполнен | {}", url);
|
||||
ResponseBody body = execute.body();
|
||||
if (execute.isSuccessful() && Checker.checkNotNull(body)) {
|
||||
final String stringBody = body.string();
|
||||
final List<T> list = objectMapper.readValue(stringBody, objectMapper.getTypeFactory().constructCollectionType(List.class, classOfT));
|
||||
return (list == null || list.isEmpty()) ? Collections.emptyList() : list;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("Ошибка выполнения okhttp3", e);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public static OkHttpClient getNewClient() {
|
||||
return new OkHttpClient().newBuilder()
|
||||
.connectTimeout(30, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.writeTimeout(30, TimeUnit.SECONDS)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
//package dev.struchkov.bot.gitlab.core.utils;
|
||||
//
|
||||
//import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
//import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
//import org.slf4j.Logger;
|
||||
//import org.slf4j.LoggerFactory;
|
||||
//import org.springframework.http.HttpEntity;
|
||||
//import org.springframework.http.HttpHeaders;
|
||||
//import org.springframework.http.HttpMethod;
|
||||
//import org.springframework.http.ResponseEntity;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//import org.springframework.web.client.RestTemplate;
|
||||
//import org.springframework.web.util.UriComponentsBuilder;
|
||||
//
|
||||
//import java.io.IOException;
|
||||
//import java.util.Collections;
|
||||
//import java.util.List;
|
||||
//import java.util.Optional;
|
||||
//
|
||||
//@Component
|
||||
//public class HttpParse {
|
||||
//
|
||||
// private static final Logger log = LoggerFactory.getLogger(HttpParse.class);
|
||||
// private static final ObjectMapper objectMapper;
|
||||
//
|
||||
// static {
|
||||
// objectMapper = new ObjectMapper();
|
||||
// objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
// }
|
||||
//
|
||||
// private final RestTemplate restTemplate;
|
||||
// private final HttpHeaders headers = new HttpHeaders();
|
||||
// private UriComponentsBuilder uriBuilder;
|
||||
//
|
||||
// public HttpParse(RestTemplate restTemplate) {
|
||||
// this.restTemplate = restTemplate;
|
||||
// }
|
||||
//
|
||||
// public HttpParse url(String url) {
|
||||
// this.uriBuilder = UriComponentsBuilder.fromHttpUrl(url);
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
// public HttpParse header(String name, String value) {
|
||||
// if (name != null && value != null) {
|
||||
// headers.add(name, value);
|
||||
// }
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
// public HttpParse header(HttpHeader header) {
|
||||
// if (header != null) {
|
||||
// headers.add(header.getName(), header.getValue());
|
||||
// }
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
// public HttpParse getParameter(String name, String value) {
|
||||
// if (name != null && value != null) {
|
||||
// uriBuilder.queryParam(name, value);
|
||||
// }
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
// public <T> Optional<T> execute(Class<T> classOfT) {
|
||||
// try {
|
||||
// String url = uriBuilder.toUriString();
|
||||
// log.trace("Выполняется RestTemplate запрос | {}", url);
|
||||
// HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||
// ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
|
||||
// log.trace("Запрос выполнен | {}", url);
|
||||
// if (response.getStatusCode().is2xxSuccessful() && response.hasBody()) {
|
||||
// String body = response.getBody();
|
||||
// return Optional.ofNullable(objectMapper.readValue(body, classOfT));
|
||||
// }
|
||||
// } catch (IOException e) {
|
||||
// log.error("Ошибка выполнения RestTemplate", e);
|
||||
// }
|
||||
// return Optional.empty();
|
||||
// }
|
||||
//
|
||||
// public <T> List<T> executeList(Class<T> classOfT) {
|
||||
// try {
|
||||
// String url = uriBuilder.toUriString();
|
||||
// log.trace("Выполняется RestTemplate запрос | {}", url);
|
||||
// HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||
// ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
|
||||
// log.trace("Запрос выполнен | {}", url);
|
||||
// if (response.getStatusCode().is2xxSuccessful() && response.hasBody()) {
|
||||
// String body = response.getBody();
|
||||
// return objectMapper.readValue(body, objectMapper.getTypeFactory().constructCollectionType(List.class, classOfT));
|
||||
// }
|
||||
// } catch (IOException e) {
|
||||
// log.error("Ошибка выполнения RestTemplate", e);
|
||||
// }
|
||||
// return Collections.emptyList();
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package dev.struchkov.bot.gitlab.core.utils;
|
||||
package dev.struchkov.bot.gitlab.sdk.client;
|
||||
|
||||
import dev.struchkov.haiti.utils.Exceptions;
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -9,14 +10,12 @@ import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import static dev.struchkov.haiti.utils.Exceptions.utilityClass;
|
||||
|
||||
public class OkHttpUtil {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(OkHttpUtil.class);
|
||||
|
||||
public OkHttpUtil() {
|
||||
utilityClass();
|
||||
Exceptions.utilityClass();
|
||||
}
|
||||
|
||||
public static void ignoreCertificate(OkHttpClient.Builder builder) {
|
@ -1,4 +1,4 @@
|
||||
package dev.struchkov.bot.gitlab.core.utils;
|
||||
package dev.struchkov.bot.gitlab.sdk.client;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
@ -1,4 +1,4 @@
|
||||
package dev.struchkov.bot.gitlab.context.prop;
|
||||
package dev.struchkov.bot.gitlab.sdk.config;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@ -14,6 +14,8 @@ public class GitlabProperty {
|
||||
|
||||
private String baseUrl;
|
||||
|
||||
private String accessToken;
|
||||
|
||||
private String replaceUrl;
|
||||
|
||||
private String usersUrl;
|
@ -0,0 +1,14 @@
|
||||
package dev.struchkov.bot.gitlab.sdk.domain;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum GitlabProjectParam {
|
||||
|
||||
OWNER("&owned=true"),
|
||||
PRIVATE("&visibility=private");
|
||||
|
||||
private final String url;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package dev.struchkov.bot.gitlab.sdk.domain;
|
||||
package dev.struchkov.bot.gitlab.sdk.domain.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
@ -1,4 +1,4 @@
|
||||
package dev.struchkov.bot.gitlab.sdk.domain;
|
||||
package dev.struchkov.bot.gitlab.sdk.domain.json;
|
||||
|
||||
import lombok.Data;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package dev.struchkov.bot.gitlab.sdk.domain;
|
||||
package dev.struchkov.bot.gitlab.sdk.domain.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
@ -1,4 +1,4 @@
|
||||
package dev.struchkov.bot.gitlab.sdk.domain;
|
||||
package dev.struchkov.bot.gitlab.sdk.domain.json;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
@ -1,4 +1,4 @@
|
||||
package dev.struchkov.bot.gitlab.sdk.domain;
|
||||
package dev.struchkov.bot.gitlab.sdk.domain.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
@ -1,4 +1,4 @@
|
||||
package dev.struchkov.bot.gitlab.sdk.domain;
|
||||
package dev.struchkov.bot.gitlab.sdk.domain.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package dev.struchkov.bot.gitlab.sdk.domain;
|
||||
package dev.struchkov.bot.gitlab.sdk.domain.json;
|
||||
|
||||
import lombok.Data;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package dev.struchkov.bot.gitlab.sdk.domain;
|
||||
package dev.struchkov.bot.gitlab.sdk.domain.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
@ -1,4 +1,4 @@
|
||||
package dev.struchkov.bot.gitlab.sdk.domain;
|
||||
package dev.struchkov.bot.gitlab.sdk.domain.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
@ -1,4 +1,4 @@
|
||||
package dev.struchkov.bot.gitlab.sdk.domain;
|
||||
package dev.struchkov.bot.gitlab.sdk.domain.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
@ -1,4 +1,4 @@
|
||||
package dev.struchkov.bot.gitlab.sdk.domain;
|
||||
package dev.struchkov.bot.gitlab.sdk.domain.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
@ -1,4 +1,4 @@
|
||||
package dev.struchkov.bot.gitlab.sdk.domain;
|
||||
package dev.struchkov.bot.gitlab.sdk.domain.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package dev.struchkov.bot.gitlab.sdk.domain;
|
||||
package dev.struchkov.bot.gitlab.sdk.domain.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
@ -1,4 +1,4 @@
|
||||
package dev.struchkov.bot.gitlab.sdk.domain;
|
||||
package dev.struchkov.bot.gitlab.sdk.domain.json;
|
||||
|
||||
import lombok.Data;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package dev.struchkov.bot.gitlab.core.parser.forktask;
|
||||
package dev.struchkov.bot.gitlab.sdk.forktask;
|
||||
|
||||
import dev.struchkov.bot.gitlab.core.utils.HttpParse;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.DiscussionJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.client.HttpParse;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.DiscussionJson;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
@ -10,8 +10,8 @@ import java.text.MessageFormat;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.RecursiveTask;
|
||||
|
||||
import static dev.struchkov.bot.gitlab.core.utils.HttpParse.ACCEPT;
|
||||
import static dev.struchkov.bot.gitlab.core.utils.StringUtils.H_PRIVATE_TOKEN;
|
||||
import static dev.struchkov.bot.gitlab.sdk.client.HttpParse.ACCEPT;
|
||||
import static dev.struchkov.bot.gitlab.sdk.client.StringUtils.H_PRIVATE_TOKEN;
|
||||
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
|
||||
|
||||
@AllArgsConstructor
|
@ -1,8 +1,8 @@
|
||||
package dev.struchkov.bot.gitlab.core.parser.forktask;
|
||||
package dev.struchkov.bot.gitlab.sdk.forktask;
|
||||
|
||||
import dev.struchkov.bot.gitlab.core.utils.HttpParse;
|
||||
import dev.struchkov.bot.gitlab.core.utils.StringUtils;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.MergeRequestJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.client.HttpParse;
|
||||
import dev.struchkov.bot.gitlab.sdk.client.StringUtils;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.MergeRequestJson;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
@ -12,7 +12,7 @@ import java.text.MessageFormat;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.RecursiveTask;
|
||||
|
||||
import static dev.struchkov.bot.gitlab.core.utils.HttpParse.ACCEPT;
|
||||
import static dev.struchkov.bot.gitlab.sdk.client.HttpParse.ACCEPT;
|
||||
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
|
||||
|
||||
@Slf4j
|
@ -1,8 +1,8 @@
|
||||
package dev.struchkov.bot.gitlab.core.parser.forktask;
|
||||
package dev.struchkov.bot.gitlab.sdk.forktask;
|
||||
|
||||
import dev.struchkov.bot.gitlab.core.utils.HttpParse;
|
||||
import dev.struchkov.bot.gitlab.core.utils.StringUtils;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.PipelineShortJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.client.HttpParse;
|
||||
import dev.struchkov.bot.gitlab.sdk.client.StringUtils;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.PipelineShortJson;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
@ -13,7 +13,7 @@ import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.RecursiveTask;
|
||||
|
||||
import static dev.struchkov.bot.gitlab.core.utils.HttpParse.ACCEPT;
|
||||
import static dev.struchkov.bot.gitlab.sdk.client.HttpParse.ACCEPT;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@ -47,7 +47,7 @@ public class GetPipelineShortTask extends RecursiveTask<List<PipelineShortJson>>
|
||||
final List<PipelineShortJson> jsons = HttpParse.request(MessageFormat.format(urlPipelines, projectId, pageNumber, PAGE_COUNT))
|
||||
.header(ACCEPT)
|
||||
.header(StringUtils.H_PRIVATE_TOKEN, gitlabToken)
|
||||
.getParameter("updated_after", lastUpdate.minusHours(12L).toString())
|
||||
.getParameter("updated_after", lastUpdate.toString())
|
||||
.executeList(PipelineShortJson.class);
|
||||
log.trace("Получено {} шт потенциально новых пайплайнов для проекта id:'{}' ", jsons.size(), projectId);
|
||||
return jsons;
|
@ -1,8 +1,8 @@
|
||||
package dev.struchkov.bot.gitlab.core.parser.forktask;
|
||||
package dev.struchkov.bot.gitlab.sdk.forktask;
|
||||
|
||||
import dev.struchkov.bot.gitlab.core.utils.HttpParse;
|
||||
import dev.struchkov.bot.gitlab.core.utils.StringUtils;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.PipelineJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.client.HttpParse;
|
||||
import dev.struchkov.bot.gitlab.sdk.client.StringUtils;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.PipelineJson;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
@ -14,7 +14,7 @@ import java.text.MessageFormat;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.RecursiveTask;
|
||||
|
||||
import static dev.struchkov.bot.gitlab.core.utils.HttpParse.ACCEPT;
|
||||
import static dev.struchkov.bot.gitlab.sdk.client.HttpParse.ACCEPT;
|
||||
|
||||
|
||||
@Slf4j
|
@ -1,8 +1,8 @@
|
||||
package dev.struchkov.bot.gitlab.core.parser.forktask;
|
||||
package dev.struchkov.bot.gitlab.sdk.forktask;
|
||||
|
||||
import dev.struchkov.bot.gitlab.core.utils.HttpParse;
|
||||
import dev.struchkov.bot.gitlab.core.utils.StringUtils;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.MergeRequestJson;
|
||||
import dev.struchkov.bot.gitlab.sdk.client.HttpParse;
|
||||
import dev.struchkov.bot.gitlab.sdk.client.StringUtils;
|
||||
import dev.struchkov.bot.gitlab.sdk.domain.json.MergeRequestJson;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -11,7 +11,7 @@ import java.text.MessageFormat;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.RecursiveTask;
|
||||
|
||||
import static dev.struchkov.bot.gitlab.core.utils.HttpParse.ACCEPT;
|
||||
import static dev.struchkov.bot.gitlab.sdk.client.HttpParse.ACCEPT;
|
||||
|
||||
|
||||
@Slf4j
|
@ -0,0 +1,8 @@
|
||||
package dev.struchkov.bot.gitlab.sdk.util;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
@UtilityClass
|
||||
public class GitlabUrlParser {
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package dev.struchkov.bot.gitlab.telegram.service;
|
||||
|
||||
import dev.struchkov.bot.gitlab.context.prop.GitlabProperty;
|
||||
import dev.struchkov.bot.gitlab.sdk.config.GitlabProperty;
|
||||
import dev.struchkov.godfather.simple.domain.BoxAnswer;
|
||||
import dev.struchkov.godfather.simple.domain.action.PreSendProcessing;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
@ -3,13 +3,13 @@ package dev.struchkov.bot.gitlab.telegram.unit;
|
||||
import dev.struchkov.bot.gitlab.context.domain.PersonInformation;
|
||||
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequest;
|
||||
import dev.struchkov.bot.gitlab.context.domain.entity.Project;
|
||||
import dev.struchkov.bot.gitlab.context.prop.GitlabProperty;
|
||||
import dev.struchkov.bot.gitlab.context.service.AppSettingService;
|
||||
import dev.struchkov.bot.gitlab.context.service.MergeRequestsService;
|
||||
import dev.struchkov.bot.gitlab.context.service.NoteService;
|
||||
import dev.struchkov.bot.gitlab.context.service.ProjectService;
|
||||
import dev.struchkov.bot.gitlab.context.utils.Icons;
|
||||
import dev.struchkov.bot.gitlab.core.parser.ProjectParser;
|
||||
import dev.struchkov.bot.gitlab.sdk.config.GitlabProperty;
|
||||
import dev.struchkov.bot.gitlab.telegram.utils.UnitName;
|
||||
import dev.struchkov.godfather.main.domain.annotation.Unit;
|
||||
import dev.struchkov.godfather.main.domain.content.Mail;
|
||||
@ -42,6 +42,7 @@ import static dev.struchkov.godfather.simple.domain.BoxAnswer.replaceBoxAnswer;
|
||||
import static dev.struchkov.godfather.telegram.domain.keyboard.InlineKeyBoard.inlineKeyBoard;
|
||||
import static dev.struchkov.godfather.telegram.domain.keyboard.SimpleKeyBoardLine.keyBoardLine;
|
||||
import static dev.struchkov.godfather.telegram.domain.keyboard.button.SimpleButton.simpleButton;
|
||||
import static dev.struchkov.godfather.telegram.main.context.BoxAnswerPayload.ENABLE_MARKDOWN;
|
||||
import static dev.struchkov.godfather.telegram.main.core.util.UnitTrigger.clickButtonRaw;
|
||||
import static dev.struchkov.godfather.telegram.main.core.util.UnitTrigger.isLinks;
|
||||
import static java.util.Collections.singleton;
|
||||
@ -65,7 +66,6 @@ public class MenuConfig implements PersonUnitConfiguration {
|
||||
private final MergeRequestsService mergeRequestsService;
|
||||
private final AppSettingService settingService;
|
||||
|
||||
|
||||
@Unit(value = ACCESS_ERROR, main = true)
|
||||
public AnswerText<Mail> accessError() {
|
||||
return AnswerText.<Mail>builder()
|
||||
@ -83,6 +83,7 @@ public class MenuConfig implements PersonUnitConfiguration {
|
||||
return BoxAnswer.builder()
|
||||
.recipientPersonId(personInformation.getTelegramId())
|
||||
.message(messageText)
|
||||
.payload(ENABLE_MARKDOWN)
|
||||
.build();
|
||||
})
|
||||
.build();
|
||||
|
Loading…
Reference in New Issue
Block a user