Исправление null

This commit is contained in:
upagge 2020-04-10 18:37:29 +03:00
parent c3c35f59e4
commit 2ad244de13
No known key found for this signature in database
GPG Key ID: 15CD012E46F6BA34
26 changed files with 249 additions and 83 deletions

View File

@ -19,6 +19,12 @@
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.2-jre</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>

View File

@ -6,6 +6,9 @@ import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Configuration
@EnableScheduling
public class AppConfig {
@ -17,4 +20,9 @@ public class AppConfig {
return taskScheduler;
}
@Bean
public ExecutorService executorService() {
return Executors.newFixedThreadPool(10);
}
}

View File

@ -4,7 +4,6 @@ import com.tsc.bitbucketbot.domain.Answer;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Singular;
import java.util.List;
import java.util.Set;
@ -19,12 +18,12 @@ public class AnswerCommentChange extends Change {
@Builder
protected AnswerCommentChange(
@Singular("telegramId") Set<Long> telegramId,
Set<Long> telegramIds,
String youMessage,
String url,
List<Answer> answers
) {
super(ChangeType.NEW_ANSWERS_COMMENT, telegramId);
super(ChangeType.NEW_ANSWERS_COMMENT, telegramIds);
this.youMessage = youMessage;
this.url = url;
this.answers = answers;

View File

@ -13,13 +13,13 @@ public abstract class Change {
protected final ChangeType type;
protected final LocalDateTime localDateTime = LocalDateTime.now();
protected final Set<Long> telegramId;
protected final Set<Long> telegramIds;
@Setter
protected Long id;
protected Change(ChangeType type, Set<Long> telegramId) {
protected Change(ChangeType type, Set<Long> telegramIds) {
this.type = type;
this.telegramId = telegramId;
this.telegramIds = telegramIds;
}
}

View File

@ -3,28 +3,30 @@ package com.tsc.bitbucketbot.domain.change;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Singular;
import java.util.Set;
@Getter
@EqualsAndHashCode(callSuper = true)
public class CommentChange extends PrChange {
public class CommentChange extends Change {
private final String authorName;
private final String message;
private final String url;
@Builder
private CommentChange(
@Singular("telegramId") Set<Long> telegramId,
String name,
Set<Long> telegramIds,
String url,
String authorName,
String message
) {
super(ChangeType.NEW_COMMENT, telegramId, name, url);
super(ChangeType.NEW_COMMENT, telegramIds);
this.authorName = authorName;
this.message = message;
this.url = url;
}
}

View File

@ -2,7 +2,6 @@ package com.tsc.bitbucketbot.domain.change;
import lombok.Builder;
import lombok.Getter;
import lombok.Singular;
import java.util.Set;
@ -11,11 +10,11 @@ public class ConflictPrChange extends PrChange {
@Builder
private ConflictPrChange(
@Singular("telegramId") Set<Long> telegramId,
Set<Long> telegramIds,
String name,
String url
) {
super(ChangeType.CONFLICT_PR, telegramId, name, url);
super(ChangeType.CONFLICT_PR, telegramIds, name, url);
}
}

View File

@ -3,7 +3,6 @@ package com.tsc.bitbucketbot.domain.change;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Singular;
import java.util.Set;
@ -16,12 +15,12 @@ public class NewPrChange extends PrChange {
@Builder
private NewPrChange(
@Singular("telegramId") Set<Long> telegramId,
Set<Long> telegramIds,
String name,
String url,
String description,
String author) {
super(ChangeType.NEW_PR, telegramId, name, url);
super(ChangeType.NEW_PR, telegramIds, name, url);
this.description = description;
this.author = author;
}

View File

@ -12,8 +12,8 @@ public abstract class PrChange extends Change {
private final String name;
private final String url;
protected PrChange(ChangeType type, Set<Long> telegramId, String name, String url) {
super(type, telegramId);
protected PrChange(ChangeType type, Set<Long> telegramIds, String name, String url) {
super(type, telegramIds);
this.name = name;
this.url = url;
}

View File

@ -4,7 +4,6 @@ import com.tsc.bitbucketbot.domain.util.ReviewerChange;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Singular;
import java.util.List;
import java.util.Set;
@ -17,11 +16,11 @@ public class ReviewersPrChange extends PrChange {
@Builder
private ReviewersPrChange(
@Singular("telegramId") Set<Long> telegramId,
Set<Long> telegramIds,
String name,
String url,
List<ReviewerChange> reviewerChanges) {
super(ChangeType.REVIEWERS, telegramId, name, url);
super(ChangeType.REVIEWERS, telegramIds, name, url);
this.reviewerChanges = reviewerChanges;
}

View File

@ -4,7 +4,6 @@ import com.tsc.bitbucketbot.domain.PullRequestStatus;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Singular;
import java.util.Set;
@ -17,12 +16,12 @@ public class StatusPrChange extends PrChange {
@Builder
private StatusPrChange(
@Singular("telegramId") Set<Long> telegramId,
Set<Long> telegramIds,
String name,
String url,
PullRequestStatus oldStatus,
PullRequestStatus newStatus) {
super(ChangeType.STATUS_PR, telegramId, name, url);
super(ChangeType.STATUS_PR, telegramIds, name, url);
this.oldStatus = oldStatus;
this.newStatus = newStatus;
}

View File

@ -3,7 +3,6 @@ package com.tsc.bitbucketbot.domain.change;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Singular;
import java.util.Set;
@ -15,10 +14,10 @@ public class UpdatePrChange extends PrChange {
@Builder
private UpdatePrChange(
@Singular("telegramId") Set<Long> telegramId,
Set<Long> telegramIds,
String name,
String url, String author) {
super(ChangeType.UPDATE_PR, telegramId, name, url);
super(ChangeType.UPDATE_PR, telegramIds, name, url);
this.author = author;
}

View File

@ -27,7 +27,7 @@ public interface UserRepository extends JpaRepository<User, String> {
Long findTelegramIdByLogin(String login);
@Query("SELECT u.telegramId FROM User u WHERE u.login IN :logins AND u.telegramId IS NOT NULL")
List<Long> findAllTelegramIdByLogin(Set<String> logins);
Set<Long> findAllTelegramIdByLogin(Set<String> logins);
Optional<User> findByLogin(String login);

View File

@ -28,14 +28,14 @@ public class SchedulerChangeParsing {
private final MessageSendService messageSendService;
private final ChangeService changeService;
@Scheduled(cron = "30 */1 * * * MON-FRI")
@Scheduled(cron = "*/15 * * * * *")
public void parsing() {
final List<Change> newChange = changeService.getNew().stream()
.filter(change -> change.getTelegramId() != null && !change.getTelegramId().isEmpty())
.filter(change -> change.getTelegramIds() != null && !change.getTelegramIds().isEmpty())
.collect(Collectors.toList());
for (Change change : newChange) {
final String message = generateMessage(change);
change.getTelegramId().forEach(
change.getTelegramIds().forEach(
telegramId -> messageSendService.add(
MessageSend.builder()
.telegramId(telegramId)

View File

@ -13,6 +13,9 @@ import com.tsc.bitbucketbot.service.CommentService;
import com.tsc.bitbucketbot.service.PullRequestsService;
import com.tsc.bitbucketbot.service.UserService;
import com.tsc.bitbucketbot.service.Utils;
import com.tsc.bitbucketbot.service.executor.DataScan;
import com.tsc.bitbucketbot.service.executor.ResultScan;
import com.tsc.bitbucketbot.service.impl.ExecutorScanner;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -21,6 +24,8 @@ import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
@ -35,45 +40,48 @@ import java.util.stream.Collectors;
public class SchedulerComments {
private static final Integer COUNT = 100;
private static final Integer NO_COMMENT = 30;
private static final Integer NO_COMMENT = 6;
private static final Pattern PATTERN = Pattern.compile("@[\\w]+");
private final CommentService commentService;
private final PullRequestsService pullRequestsService;
private final UserService userService;
private final ChangeService changeService;
private final ExecutorScanner executorScanner;
private final BitbucketConfig bitbucketConfig;
@Scheduled(cron = "0 */4 8-18 * * MON-FRI")
@Scheduled(cron = "0 */1 * * * MON-FRI")
public void newComments() {
log.info("Начало сканирования комментариев");
long commentId = commentService.getLastCommentId() + 1;
long count = 0;
int count = 0;
do {
List<DataScan> commentUrls = new ArrayList<>();
for (int i = 0; i < 5; i++) {
int page = 0;
Page<PullRequest> pullRequestPage = pullRequestsService.getAll(Pagination.of(page, COUNT));
while (pullRequestPage.hasContent()) {
for (PullRequest pullRequest : pullRequestPage.getContent()) {
final String commentUrl = getCommentUrl(commentId, pullRequest);
final Optional<CommentJson> optCommentJson = Utils.urlToJson(commentUrl, bitbucketConfig.getToken(), CommentJson.class);
if (optCommentJson.isPresent()) {
final CommentJson commentJson = optCommentJson.get();
notification(commentJson, pullRequest);
saveComments(commentJson, commentUrl, pullRequest.getUrl());
count = 0;
break;
}
}
long finalCommentId = commentId;
commentUrls.addAll(pullRequestPage.getContent().stream()
.map(pullRequest -> new DataScan(getCommentUrl(finalCommentId, pullRequest), pullRequest.getUrl()))
.collect(Collectors.toList()));
pullRequestPage = pullRequestsService.getAll(Pagination.of(++page, COUNT));
}
count++;
commentId += 1;
} while (count < NO_COMMENT);
log.info("Конец сканирования комментариев");
commentId++;
}
executorScanner.registration(commentUrls);
final List<ResultScan> result = executorScanner.getResult();
if (!result.isEmpty()) {
result.forEach(resultScan -> {
notificationPersonal(resultScan.getCommentJson(), resultScan.getUrlPr());
saveComments(resultScan.getCommentJson(), resultScan.getUrlComment(), resultScan.getUrlPr());
});
count = 0;
}
} while (count++ < NO_COMMENT);
}
@Scheduled(cron = "0 */1 8-18 * * MON-FRI")
@Scheduled(cron = "0 */1 * * * MON-FRI")
public void oldComments() {
@NonNull final List<Comment> comments = commentService.getAllBetweenDate(LocalDateTime.now().minusDays(10), LocalDateTime.now());
for (Comment comment : comments) {
@ -91,7 +99,11 @@ public class SchedulerComments {
if (!newAnswers.isEmpty()) {
changeService.add(
AnswerCommentChange.builder()
.telegramId(userService.getTelegramIdByLogin(commentJson.getAuthor().getName()).orElse(null))
.telegramIds(
userService.getTelegramIdByLogin(commentJson.getAuthor().getName())
.map(Collections::singleton)
.orElse(Collections.emptySet())
)
.url(comment.getPrUrl())
.youMessage(commentJson.getText())
.answers(
@ -127,24 +139,19 @@ public class SchedulerComments {
.replace("{commentId}", String.valueOf(commentId));
}
private void notification(@NonNull CommentJson comment, @NonNull PullRequest pullRequest) {
notificationPersonal(comment, pullRequest);
}
private void notificationPersonal(@NonNull CommentJson comment, @NonNull PullRequest pullRequest) {
private void notificationPersonal(@NonNull CommentJson comment, @NonNull String urlPr) {
Matcher matcher = PATTERN.matcher(comment.getText());
Set<String> recipientsLogins = new HashSet<>();
while (matcher.find()) {
final String login = matcher.group(0).replace("@", "");
recipientsLogins.add(login);
}
final List<Long> recipientsIds = userService.getAllTelegramIdByLogin(recipientsLogins);
final Set<Long> recipientsIds = userService.getAllTelegramIdByLogin(recipientsLogins);
changeService.add(
CommentChange.builder()
.authorName(comment.getAuthor().getName())
.name(pullRequest.getName())
.url(pullRequest.getUrl())
.telegramId(recipientsIds)
.url(urlPr)
.telegramIds(recipientsIds)
.message(comment.getText())
.build()
);

View File

@ -19,6 +19,7 @@ import com.tsc.bitbucketbot.service.ChangeService;
import com.tsc.bitbucketbot.service.PullRequestsService;
import com.tsc.bitbucketbot.service.UserService;
import com.tsc.bitbucketbot.service.Utils;
import com.tsc.bitbucketbot.utils.NonNullUtils;
import com.tsc.bitbucketbot.utils.Pair;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
@ -28,6 +29,7 @@ import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@ -82,7 +84,7 @@ public class SchedulerPullRequest {
.url(pullRequest.getUrl())
.oldStatus(pullRequest.getStatus())
.newStatus(DELETE)
.telegramId(pullRequest.getAuthor().getTelegramId())
.telegramIds(Collections.singleton(pullRequest.getAuthor().getTelegramId()))
.build()
));
pullRequestsService.updateAll(
@ -183,7 +185,7 @@ public class SchedulerPullRequest {
ConflictPrChange.builder()
.name(pullRequest.getName())
.url(pullRequest.getUrl())
.telegramId(pullRequest.getAuthor().getTelegramId())
.telegramIds(NonNullUtils.telegramIdByUser(pullRequest.getAuthor()))
.build()
);
}
@ -194,13 +196,13 @@ public class SchedulerPullRequest {
final Set<String> logins = newPullRequest.getReviewers().stream()
.map(Reviewer::getUser)
.collect(Collectors.toSet());
final List<Long> telegramIds = userService.getAllTelegramIdByLogin(logins);
final Set<Long> telegramIds = userService.getAllTelegramIdByLogin(logins);
changeService.add(
UpdatePrChange.builder()
.name(newPullRequest.getName())
.url(newPullRequest.getUrl())
.author(newPullRequest.getAuthor().getLogin())
.telegramId(telegramIds)
.telegramIds(telegramIds)
.build()
);
}
@ -241,7 +243,7 @@ public class SchedulerPullRequest {
.name(pullRequest.getName())
.url(pullRequest.getUrl())
.reviewerChanges(reviewerChanges)
.telegramId(newPullRequest.getAuthor().getTelegramId())
.telegramIds(NonNullUtils.telegramIdByUser(pullRequest.getAuthor()))
.build()
);
}
@ -259,7 +261,7 @@ public class SchedulerPullRequest {
.url(newPullRequest.getUrl())
.oldStatus(oldStatus)
.newStatus(newStatus)
.telegramId(newPullRequest.getAuthor().getTelegramId())
.telegramIds(NonNullUtils.telegramIdByUser(newPullRequest.getAuthor()))
.build()
);
}
@ -293,7 +295,7 @@ public class SchedulerPullRequest {
private void sendNotificationNewPullRequest(@NonNull List<PullRequest> newPullRequests) {
if (!newPullRequests.isEmpty()) {
for (PullRequest newPullRequest : newPullRequests) {
final List<Long> reviewerTelegramIds = userService.getAllTelegramIdByLogin(newPullRequest.getReviewers().stream()
final Set<Long> reviewerTelegramIds = userService.getAllTelegramIdByLogin(newPullRequest.getReviewers().stream()
.map(Reviewer::getUser)
.collect(Collectors.toSet()));
changeService.add(
@ -302,7 +304,7 @@ public class SchedulerPullRequest {
.url(newPullRequest.getUrl())
.description(newPullRequest.getDescription())
.author(newPullRequest.getAuthor().getLogin())
.telegramId(reviewerTelegramIds)
.telegramIds(reviewerTelegramIds)
.build()
);
}

View File

@ -38,8 +38,8 @@ public class SchedulerPushMessageSend {
@PostConstruct
public void init() {
int proxyPort = 8080;
String proxyHost = "proxy.tsc.ts";
final int proxyPort = 8080;
final String proxyHost = "proxy.tsc.ts";
final String username = "internet";
final String password = "123454321";
@ -72,12 +72,12 @@ public class SchedulerPushMessageSend {
}
private void sendMessage(String json) {
System.out.println(json);
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(pushMessageConfig.getUrl())
.post(body)
.build();
try (final Response response = client.newCall(request).execute()) {
if (response.code() != 200) {
log.error("Ошибка отправки сообщения: " + response);

View File

@ -21,6 +21,6 @@ public interface UserService {
Optional<Long> getTelegramIdByLogin(@NonNull String login);
List<Long> getAllTelegramIdByLogin(Set<String> logins);
Set<Long> getAllTelegramIdByLogin(Set<String> logins);
}

View File

@ -0,0 +1,11 @@
package com.tsc.bitbucketbot.service.executor;
import lombok.Data;
@Data
public class DataScan {
private final String urlComment;
private final String urlPr;
}

View File

@ -0,0 +1,12 @@
package com.tsc.bitbucketbot.service.executor;
import lombok.NonNull;
import java.util.List;
public interface Executor<T, D> {
boolean registration(@NonNull List<T> seeker);
List<D> getResult();
}

View File

@ -0,0 +1,13 @@
package com.tsc.bitbucketbot.service.executor;
import com.tsc.bitbucketbot.dto.bitbucket.CommentJson;
import lombok.Data;
@Data
public class ResultScan {
private final String urlComment;
private final String urlPr;
private final CommentJson commentJson;
}

View File

@ -0,0 +1,30 @@
package com.tsc.bitbucketbot.service.executor;
import com.tsc.bitbucketbot.dto.bitbucket.CommentJson;
import com.tsc.bitbucketbot.service.Utils;
import lombok.RequiredArgsConstructor;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
@RequiredArgsConstructor
public class Seeker implements Callable<List<ResultScan>> {
private final List<DataScan> dataScan;
private final String token;
@Override
public List<ResultScan> call() throws Exception {
return dataScan.stream()
.map(
data -> Utils.urlToJson(data.getUrlComment(), token, CommentJson.class)
.map(commentJson -> new ResultScan(data.getUrlComment(), data.getUrlPr(), commentJson))
)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
}
}

View File

@ -0,0 +1,64 @@
package com.tsc.bitbucketbot.service.impl;
import com.google.common.collect.Lists;
import com.tsc.bitbucketbot.config.BitbucketConfig;
import com.tsc.bitbucketbot.service.executor.DataScan;
import com.tsc.bitbucketbot.service.executor.Executor;
import com.tsc.bitbucketbot.service.executor.ResultScan;
import com.tsc.bitbucketbot.service.executor.Seeker;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
@Slf4j
@Service
@RequiredArgsConstructor
public class ExecutorScanner implements Executor<DataScan, ResultScan> {
private final ExecutorService executorService;
private final List<Future<List<ResultScan>>> resultList = new ArrayList<>();
private final BitbucketConfig bitbucketConfig;
@Override
public boolean registration(@NonNull List<DataScan> dataScans) {
Lists.partition(dataScans, 20).forEach(
list -> resultList.add(executorService.submit(new Seeker(list, bitbucketConfig.getToken())))
);
return true;
}
@Override
public List<ResultScan> getResult() {
while (!resultList.stream().allMatch(Future::isDone)) {
}
final List<ResultScan> result = resultList.stream()
.filter(Future::isDone)
.map(this::getResultScans)
.flatMap(Collection::stream)
.collect(Collectors.toList());
resultList.clear();
return result;
}
private List<ResultScan> getResultScans(Future<List<ResultScan>> listFuture) {
try {
return listFuture.get();
} catch (InterruptedException | ExecutionException e) {
log.error(e.getMessage());
}
return Collections.emptyList();
}
}

View File

@ -69,7 +69,7 @@ public class UserServiceImpl implements UserService {
}
@Override
public List<Long> getAllTelegramIdByLogin(Set<String> logins) {
public Set<Long> getAllTelegramIdByLogin(Set<String> logins) {
return userRepository.findAllTelegramIdByLogin(logins);
}

View File

@ -151,10 +151,8 @@ public class Message {
}
public static String generate(@NonNull CommentChange commentChange) {
return Smile.BELL + " *Новое упоминание* | " + commentChange.getAuthorName() + Smile.BR +
link(commentChange.getName(), commentChange.getUrl()) +
Smile.HR +
commentChange.getMessage().replaceAll("@[\\w]+", "");
return Smile.BELL + " *Новое упоминание* | " + link("ПР", commentChange.getUrl()) + Smile.HR +
commentChange.getAuthorName() + ": " + commentChange.getMessage().replaceAll("@[\\w]+", "");
}
public static String generate(@NonNull AnswerCommentChange answerCommentChange) {

View File

@ -0,0 +1,19 @@
package com.tsc.bitbucketbot.utils;
import com.tsc.bitbucketbot.domain.entity.User;
import lombok.NonNull;
import java.util.Collections;
import java.util.Set;
public class NonNullUtils {
private NonNullUtils() {
throw new IllegalStateException("Утилитный класс");
}
public static Set<Long> telegramIdByUser(@NonNull User user) {
return user.getTelegramId() != null ? Collections.singleton(user.getTelegramId()) : Collections.emptySet();
}
}

View File

@ -18,7 +18,7 @@
</appender>
<root level="info">
<appender-ref ref="FILE"/>
<appender-ref ref="STDOUT"/>
</root>
</configuration>