Стабильная версия

This commit is contained in:
upagge 2020-04-07 18:28:33 +03:00
parent 0f2179832d
commit b74f7ae7da
No known key found for this signature in database
GPG Key ID: 15CD012E46F6BA34
13 changed files with 140 additions and 37 deletions

View File

@ -2,6 +2,6 @@ package com.tsc.bitbucketbot.domain.change;
public enum ChangeType { public enum ChangeType {
STATUS_PR, UPDATE_PR, REVIEWERS, NEW_PR STATUS_PR, UPDATE_PR, REVIEWERS, NEW_PR, CONFLICT_PR
} }

View File

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

View File

@ -86,4 +86,7 @@ public class PullRequest {
@Column(name = "update_date") @Column(name = "update_date")
private LocalDateTime updateDate; private LocalDateTime updateDate;
@Column(name = "conflict")
private boolean conflict;
} }

View File

@ -0,0 +1,10 @@
package com.tsc.bitbucketbot.dto.bitbucket;
import lombok.Data;
@Data
public class MergeResult {
private Outcome outcome;
}

View File

@ -0,0 +1,8 @@
package com.tsc.bitbucketbot.dto.bitbucket;
public enum Outcome {
CONFLICTED,
CLEAN
}

View File

@ -0,0 +1,10 @@
package com.tsc.bitbucketbot.dto.bitbucket;
import lombok.Data;
@Data
public class Properties {
private MergeResult mergeResult;
}

View File

@ -31,5 +31,6 @@ public class PullRequestJson {
private UserDecisionJson author; private UserDecisionJson author;
private List<UserDecisionJson> reviewers; private List<UserDecisionJson> reviewers;
private FromRefJson fromRef; private FromRefJson fromRef;
private Properties properties;
} }

View File

@ -1,6 +1,7 @@
package com.tsc.bitbucketbot.scheduler; package com.tsc.bitbucketbot.scheduler;
import com.tsc.bitbucketbot.domain.change.Change; import com.tsc.bitbucketbot.domain.change.Change;
import com.tsc.bitbucketbot.domain.change.ConflictPrChange;
import com.tsc.bitbucketbot.domain.change.NewPrChange; import com.tsc.bitbucketbot.domain.change.NewPrChange;
import com.tsc.bitbucketbot.domain.change.ReviewersPrChange; import com.tsc.bitbucketbot.domain.change.ReviewersPrChange;
import com.tsc.bitbucketbot.domain.change.StatusPrChange; import com.tsc.bitbucketbot.domain.change.StatusPrChange;
@ -59,6 +60,9 @@ public class SchedulerChangeParsing {
case UPDATE_PR: case UPDATE_PR:
message = Message.generate(((UpdatePrChange) change)); message = Message.generate(((UpdatePrChange) change));
break; break;
case CONFLICT_PR:
message = Message.generate(((ConflictPrChange) change));
break;
default: default:
throw new NotFoundException("Нет обработчика для типа " + change.getType().name()); throw new NotFoundException("Нет обработчика для типа " + change.getType().name());
} }

View File

@ -4,6 +4,7 @@ import com.tsc.bitbucketbot.config.BitbucketConfig;
import com.tsc.bitbucketbot.domain.IdAndStatusPr; import com.tsc.bitbucketbot.domain.IdAndStatusPr;
import com.tsc.bitbucketbot.domain.PullRequestStatus; import com.tsc.bitbucketbot.domain.PullRequestStatus;
import com.tsc.bitbucketbot.domain.ReviewerStatus; import com.tsc.bitbucketbot.domain.ReviewerStatus;
import com.tsc.bitbucketbot.domain.change.ConflictPrChange;
import com.tsc.bitbucketbot.domain.change.NewPrChange; import com.tsc.bitbucketbot.domain.change.NewPrChange;
import com.tsc.bitbucketbot.domain.change.ReviewersPrChange; import com.tsc.bitbucketbot.domain.change.ReviewersPrChange;
import com.tsc.bitbucketbot.domain.change.StatusPrChange; import com.tsc.bitbucketbot.domain.change.StatusPrChange;
@ -12,6 +13,7 @@ import com.tsc.bitbucketbot.domain.entity.PullRequest;
import com.tsc.bitbucketbot.domain.entity.Reviewer; import com.tsc.bitbucketbot.domain.entity.Reviewer;
import com.tsc.bitbucketbot.domain.entity.User; import com.tsc.bitbucketbot.domain.entity.User;
import com.tsc.bitbucketbot.domain.util.ReviewerChange; import com.tsc.bitbucketbot.domain.util.ReviewerChange;
import com.tsc.bitbucketbot.dto.bitbucket.PullRequestJson;
import com.tsc.bitbucketbot.dto.bitbucket.sheet.PullRequestSheetJson; import com.tsc.bitbucketbot.dto.bitbucket.sheet.PullRequestSheetJson;
import com.tsc.bitbucketbot.service.ChangeService; import com.tsc.bitbucketbot.service.ChangeService;
import com.tsc.bitbucketbot.service.PullRequestsService; import com.tsc.bitbucketbot.service.PullRequestsService;
@ -56,7 +58,7 @@ public class SchedulerPullRequest {
private final BitbucketConfig bitbucketConfig; private final BitbucketConfig bitbucketConfig;
@Scheduled(fixedRate = 30000) @Scheduled(fixedRate = 30000)
public void checkOldPullRequest() { public void checkPullRequest() {
final Set<Long> existsId = pullRequestsService.getAllId(STATUSES).stream() final Set<Long> existsId = pullRequestsService.getAllId(STATUSES).stream()
.map(IdAndStatusPr::getId) .map(IdAndStatusPr::getId)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
@ -97,29 +99,17 @@ public class SchedulerPullRequest {
Optional<PullRequestSheetJson> sheetJson = Utils.urlToJson(bitbucketConfig.getUrlPullRequestClose(), user.getToken(), PullRequestSheetJson.class); Optional<PullRequestSheetJson> sheetJson = Utils.urlToJson(bitbucketConfig.getUrlPullRequestClose(), user.getToken(), PullRequestSheetJson.class);
while (sheetJson.isPresent() && sheetJson.get().getValues() != null && !sheetJson.get().getValues().isEmpty()) { while (sheetJson.isPresent() && sheetJson.get().getValues() != null && !sheetJson.get().getValues().isEmpty()) {
final PullRequestSheetJson bitbucketSheet = sheetJson.get(); final PullRequestSheetJson bitbucketSheet = sheetJson.get();
final List<PullRequest> newPrs = bitbucketSheet.getValues().stream() final Map<Long, PullRequest> existsPr = getExistsPr(bitbucketSheet.getValues());
.map(jsonPr -> conversionService.convert(jsonPr, PullRequest.class)) final Set<PullRequest> pullRequests = pullRequestsService.getAllById(existsPr.keySet());
.peek(pullRequest -> pullRequestsService.getIdByBitbucketIdAndReposId(pullRequest.getBitbucketId(), pullRequest.getRepositoryId()).ifPresent(pullRequest::setId)) if (!existsPr.isEmpty() && !pullRequests.isEmpty()) {
.filter(pullRequest -> pullRequest.getId() != null) processingUpdateClosePr(existsPr, pullRequests);
.collect(Collectors.toList()); ids.addAll(
for (PullRequest pullRequest : newPrs) { pullRequestsService.updateAll(existsPr.values()).stream()
changeService.add( .map(PullRequest::getId)
StatusPrChange.builder() .collect(Collectors.toSet())
.name(pullRequest.getName())
.url(pullRequest.getUrl())
.oldStatus(pullRequest.getStatus())
.newStatus(OPEN)
.telegramId(pullRequest.getAuthor().getTelegramId())
.build()
); );
} }
ids.addAll(
pullRequestsService.updateAll(newPrs).stream()
.map(PullRequest::getId)
.collect(Collectors.toSet())
);
if (bitbucketSheet.getNextPageStart() != null) { if (bitbucketSheet.getNextPageStart() != null) {
sheetJson = Utils.urlToJson(bitbucketConfig.getUrlPullRequestClose() + bitbucketSheet.getNextPageStart(), bitbucketConfig.getToken(), PullRequestSheetJson.class); sheetJson = Utils.urlToJson(bitbucketConfig.getUrlPullRequestClose() + bitbucketSheet.getNextPageStart(), bitbucketConfig.getToken(), PullRequestSheetJson.class);
} else { } else {
@ -137,15 +127,10 @@ public class SchedulerPullRequest {
Optional<PullRequestSheetJson> sheetJson = Utils.urlToJson(bitbucketConfig.getUrlPullRequestOpen(), user.getToken(), PullRequestSheetJson.class); Optional<PullRequestSheetJson> sheetJson = Utils.urlToJson(bitbucketConfig.getUrlPullRequestOpen(), user.getToken(), PullRequestSheetJson.class);
while (sheetJson.isPresent() && sheetJson.get().getValues() != null && !sheetJson.get().getValues().isEmpty()) { while (sheetJson.isPresent() && sheetJson.get().getValues() != null && !sheetJson.get().getValues().isEmpty()) {
final PullRequestSheetJson jsonSheet = sheetJson.get(); final PullRequestSheetJson jsonSheet = sheetJson.get();
final Map<Long, PullRequest> existsPr = jsonSheet.getValues().stream() final Map<Long, PullRequest> existsPr = getExistsPr(jsonSheet.getValues());
.filter(Objects::nonNull)
.map(pullRequestJson -> conversionService.convert(pullRequestJson, PullRequest.class))
.peek(pullRequest -> pullRequestsService.getIdByBitbucketIdAndReposId(pullRequest.getBitbucketId(), pullRequest.getRepositoryId()).ifPresent(pullRequest::setId))
.filter(pullRequest -> pullRequest.getId() != null)
.collect(Collectors.toMap(PullRequest::getId, pullRequest -> pullRequest));
final Set<PullRequest> pullRequests = pullRequestsService.getAllById(existsPr.keySet()); final Set<PullRequest> pullRequests = pullRequestsService.getAllById(existsPr.keySet());
if (!existsPr.isEmpty() && !pullRequests.isEmpty()) { if (!existsPr.isEmpty() && !pullRequests.isEmpty()) {
processingUpdate(existsPr, pullRequests); processingUpdateOpenPr(existsPr, pullRequests);
ids.addAll( ids.addAll(
pullRequestsService.updateAll(existsPr.values()).stream() pullRequestsService.updateAll(existsPr.values()).stream()
.map(PullRequest::getId) .map(PullRequest::getId)
@ -163,12 +148,44 @@ public class SchedulerPullRequest {
return ids; return ids;
} }
private Map<Long, PullRequest> getExistsPr(List<PullRequestJson> pullRequestJsons) {
return pullRequestJsons.stream()
.filter(Objects::nonNull)
.map(pullRequestJson -> conversionService.convert(pullRequestJson, PullRequest.class))
.peek(pullRequest -> pullRequestsService.getIdByBitbucketIdAndReposId(pullRequest.getBitbucketId(), pullRequest.getRepositoryId()).ifPresent(pullRequest::setId))
.filter(pullRequest -> pullRequest.getId() != null)
.collect(Collectors.toMap(PullRequest::getId, pullRequest -> pullRequest));
}
@NonNull @NonNull
private void processingUpdate(Map<Long, PullRequest> newPullRequests, Set<PullRequest> pullRequests) { private void processingUpdateOpenPr(Map<Long, PullRequest> newPullRequests, Set<PullRequest> pullRequests) {
for (PullRequest pullRequest : pullRequests) { for (PullRequest pullRequest : pullRequests) {
PullRequest newPullRequest = newPullRequests.get(pullRequest.getId()); PullRequest newPullRequest = newPullRequests.get(pullRequest.getId());
processingAuthor(pullRequest, newPullRequest); changeStatusPR(pullRequest, newPullRequest);
changeReviewersPR(pullRequest, newPullRequest);
processingReviewer(pullRequest, newPullRequest); processingReviewer(pullRequest, newPullRequest);
conflictPr(pullRequest, newPullRequest);
}
}
@NonNull
private void processingUpdateClosePr(Map<Long, PullRequest> newPullRequests, Set<PullRequest> pullRequests) {
for (PullRequest pullRequest : pullRequests) {
PullRequest newPullRequest = newPullRequests.get(pullRequest.getId());
changeStatusPR(pullRequest, newPullRequest);
}
}
@NonNull
private void conflictPr(PullRequest pullRequest, PullRequest newPullRequest) {
if (newPullRequest.isConflict() && !pullRequest.isConflict()) {
changeService.add(
ConflictPrChange.builder()
.name(pullRequest.getName())
.url(pullRequest.getUrl())
.telegramId(pullRequest.getAuthor().getTelegramId())
.build()
);
} }
} }
@ -189,12 +206,6 @@ public class SchedulerPullRequest {
} }
} }
@NonNull
private void processingAuthor(PullRequest pullRequest, PullRequest newPullRequest) {
changeStatusPR(pullRequest, newPullRequest);
changeReviewersPR(pullRequest, newPullRequest);
}
@NonNull @NonNull
private boolean isUpdatePr(PullRequest pullRequest, PullRequest newPullRequest) { private boolean isUpdatePr(PullRequest pullRequest, PullRequest newPullRequest) {
LocalDateTime oldDate = pullRequest.getUpdateDate(); LocalDateTime oldDate = pullRequest.getUpdateDate();

View File

@ -5,6 +5,8 @@ import com.tsc.bitbucketbot.domain.ReviewerStatus;
import com.tsc.bitbucketbot.domain.entity.PullRequest; import com.tsc.bitbucketbot.domain.entity.PullRequest;
import com.tsc.bitbucketbot.domain.entity.Reviewer; import com.tsc.bitbucketbot.domain.entity.Reviewer;
import com.tsc.bitbucketbot.domain.entity.User; import com.tsc.bitbucketbot.domain.entity.User;
import com.tsc.bitbucketbot.dto.bitbucket.Outcome;
import com.tsc.bitbucketbot.dto.bitbucket.Properties;
import com.tsc.bitbucketbot.dto.bitbucket.PullRequestJson; import com.tsc.bitbucketbot.dto.bitbucket.PullRequestJson;
import com.tsc.bitbucketbot.dto.bitbucket.PullRequestState; import com.tsc.bitbucketbot.dto.bitbucket.PullRequestState;
import com.tsc.bitbucketbot.dto.bitbucket.UserDecisionJson; import com.tsc.bitbucketbot.dto.bitbucket.UserDecisionJson;
@ -32,6 +34,7 @@ public class PullRequestJsonConverter implements Converter<PullRequestJson, Pull
.version(json.getVersion()) .version(json.getVersion())
.createDate(json.getCreatedDate()) .createDate(json.getCreatedDate())
.updateDate(json.getUpdatedDate()) .updateDate(json.getUpdatedDate())
.conflict(convertConflict(json.getProperties()))
.description(convertDescription(json.getDescription())) .description(convertDescription(json.getDescription()))
.repositoryId(json.getFromRef().getRepository().getId()) .repositoryId(json.getFromRef().getRepository().getId())
.author(this.convertUser(json.getAuthor().getUser())) .author(this.convertUser(json.getAuthor().getUser()))
@ -44,6 +47,13 @@ public class PullRequestJsonConverter implements Converter<PullRequestJson, Pull
.build(); .build();
} }
private boolean convertConflict(Properties properties) {
return properties != null
&& properties.getMergeResult() != null
&& properties.getMergeResult().getOutcome() != null
&& Outcome.CONFLICTED.equals(properties.getMergeResult().getOutcome());
}
private String convertDescription(String description) { private String convertDescription(String description) {
if (description != null) { if (description != null) {
return description.length() > 180 ? description.substring(0, 180) + "..." : description; return description.length() > 180 ? description.substring(0, 180) + "..." : description;

View File

@ -1,5 +1,6 @@
package com.tsc.bitbucketbot.utils; package com.tsc.bitbucketbot.utils;
import com.tsc.bitbucketbot.domain.change.ConflictPrChange;
import com.tsc.bitbucketbot.domain.change.NewPrChange; import com.tsc.bitbucketbot.domain.change.NewPrChange;
import com.tsc.bitbucketbot.domain.change.ReviewersPrChange; import com.tsc.bitbucketbot.domain.change.ReviewersPrChange;
import com.tsc.bitbucketbot.domain.change.StatusPrChange; import com.tsc.bitbucketbot.domain.change.StatusPrChange;
@ -98,6 +99,11 @@ public class Message {
Smile.TWO_BR; Smile.TWO_BR;
} }
public static String generate(@NonNull ConflictPrChange change) {
return Smile.DANGEROUS + "*Внимание конфлик в ПР*" + Smile.HR +
link(change.getName(), change.getUrl()) + Smile.TWO_BR;
}
@NonNull @NonNull
public static String goodMorningStatistic(List<PullRequest> pullRequestsReviews, List<PullRequest> pullRequestsNeedWork) { public static String goodMorningStatistic(List<PullRequest> pullRequestsReviews, List<PullRequest> pullRequestsNeedWork) {
StringBuilder message = new StringBuilder().append(Smile.SUN).append(" Доброе утро ").append(Smile.SUN).append(Smile.HR); StringBuilder message = new StringBuilder().append(Smile.SUN).append(" Доброе утро ").append(Smile.SUN).append(Smile.HR);

View File

@ -7,5 +7,6 @@
<include file="liquibase/change-set/v1.2.0.xml"/> <include file="liquibase/change-set/v1.2.0.xml"/>
<include file="liquibase/change-set/v1.3.0.xml"/> <include file="liquibase/change-set/v1.3.0.xml"/>
<include file="liquibase/change-set/v1.4.0.xml"/> <include file="liquibase/change-set/v1.4.0.xml"/>
<include file="liquibase/change-set/v2.0.0.xml"/>
</databaseChangeLog> </databaseChangeLog>

View File

@ -0,0 +1,18 @@
<databaseChangeLog
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<changeSet id="add-column-pr-conflict" author="upagge">
<addColumn tableName="pull_request" schemaName="public" catalogName="pg_catalog">
<column name="conflict" type="boolean"/>
</addColumn>
</changeSet>
<changeSet id="default-pr-conflict" author="upagge">
<update tableName="pull_request" schemaName="public" catalogName="pg_catalog">
<column name="conflict" value="false" type="boolean"/>
</update>
</changeSet>
</databaseChangeLog>