Skip to content

Commit

Permalink
create rule based detection of bad practices(#226)
Browse files Browse the repository at this point in the history
  • Loading branch information
iam-flo committed Jan 28, 2025
1 parent 1e0dc5e commit a6678bc
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,10 @@ public List<PullRequestBadPracticeDTO> detectBadPractices(String login) {
Set.of(Issue.State.OPEN)
);

return pullRequests
List<PullRequestBadPractice> badPractices = pullRequestBadPracticeDetector.detectAndSyncBadPractices(pullRequests);

return badPractices
.stream()
.map(pullRequestBadPracticeDetector::detectAndSyncBadPractices)
.flatMap(List::stream)
.map(PullRequestBadPracticeDTO::fromPullRequestBadPractice)
.collect(Collectors.toList());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package de.tum.in.www1.hephaestus.activity;

import de.tum.in.www1.hephaestus.activity.model.PullRequestBadPracticeRule;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

@Repository
public interface PullRequestBadPracticeRuleRepository extends JpaRepository<PullRequestBadPracticeRule, Long> {
@Query(
"""
SELECT prbp
FROM PullRequestBadPracticeRule prbp
WHERE prbp.active = true
"""
)
List<PullRequestBadPracticeRule> findAllActive();
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
package de.tum.in.www1.hephaestus.activity.badpracticedetector;

import de.tum.in.www1.hephaestus.activity.PullRequestBadPracticeRepository;
import de.tum.in.www1.hephaestus.activity.PullRequestBadPracticeRuleRepository;
import de.tum.in.www1.hephaestus.activity.model.BadPracticeType;
import de.tum.in.www1.hephaestus.activity.model.PullRequestBadPractice;
import de.tum.in.www1.hephaestus.activity.model.PullRequestBadPracticeRule;
import de.tum.in.www1.hephaestus.gitprovider.pullrequest.PullRequest;

import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

import de.tum.in.www1.hephaestus.gitprovider.pullrequest.PullRequestRepository;
import de.tum.in.www1.hephaestus.intelligenceservice.api.DetectorApi;
import de.tum.in.www1.hephaestus.intelligenceservice.model.DetectorRequest;
import de.tum.in.www1.hephaestus.intelligenceservice.model.DetectorResponse;
import de.tum.in.www1.hephaestus.intelligenceservice.model.PullRequestWithBadPractices;
import de.tum.in.www1.hephaestus.intelligenceservice.model.Rule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -14,16 +27,90 @@ public class PullRequestBadPracticeDetector {

private static final Logger logger = LoggerFactory.getLogger(PullRequestBadPracticeDetector.class);

@Autowired
private PullRequestRepository pullRequestRepository;

@Autowired
private PullRequestBadPracticeRepository pullRequestBadPracticeRepository;

public List<PullRequestBadPractice> detectAndSyncBadPractices(PullRequest pullRequest) {
logger.info("Detecting bad practices for pull request: {}.", pullRequest.getId());
@Autowired
private PullRequestBadPracticeRuleRepository pullRequestBadPracticeRuleRepository;

private final DetectorApi detectorApi = new DetectorApi();

public List<PullRequestBadPractice> detectAndSyncBadPractices(List<PullRequest> pullRequests) {
logger.info("Detecting bad practices for pull requests.");

List<PullRequestBadPracticeRule> rules = pullRequestBadPracticeRuleRepository.findAllActive();

DetectorRequest detectorRequest = new DetectorRequest();
detectorRequest.setPullRequests(mapToApiPullRequests(pullRequests));
detectorRequest.setRules(mapToApiRules(rules));
DetectorResponse detectorResponse = detectorApi.detectDetectorPost(detectorRequest);

List<PullRequestBadPractice> detectedBadPractices = new LinkedList<>();

detectorResponse.getDetectBadPractices().forEach(prWithBadPractices ->
detectedBadPractices.addAll(handleDetectedBadPractices(prWithBadPractices))
);

return detectedBadPractices;
}

private List<PullRequestBadPractice> handleDetectedBadPractices(PullRequestWithBadPractices prWithBadPractices) {

Long pullRequestId = Long.valueOf(prWithBadPractices.getPullRequestId());
PullRequest pullRequest = pullRequestRepository.findById(pullRequestId).orElse(null);

if (pullRequest == null) {
logger.error("Pull request with id {} not found.", prWithBadPractices.getPullRequestId());
return List.of();
}

List<PullRequestBadPractice> existingBadPractices = pullRequestBadPracticeRepository.findByPullRequestId(
pullRequest.getId()
pullRequest.getId()
);

return existingBadPractices;
List<PullRequestBadPractice> newBadPractices = prWithBadPractices.getBadPracticeIds().stream()
.map(badPracticeRule -> {
PullRequestBadPractice pullRequestBadPractice = new PullRequestBadPractice();
pullRequestBadPractice.setPullrequest(pullRequest);
pullRequestBadPractice.setType(findBadPracticeType(badPracticeRule));
pullRequestBadPractice.setResolved(false);
return pullRequestBadPractice;
})
.collect(Collectors.toList());

pullRequestBadPracticeRepository.saveAll(newBadPractices);
existingBadPractices.removeAll(newBadPractices);
existingBadPractices.forEach(badPractice -> badPractice.setResolved(true));
pullRequestBadPracticeRepository.saveAll(existingBadPractices);
return newBadPractices;
}

private BadPracticeType findBadPracticeType(String badPracticeRuleId) {
return pullRequestBadPracticeRuleRepository.findById(Long.valueOf(badPracticeRuleId))
.map(PullRequestBadPracticeRule::getType)
.orElse(null);
}

private List<de.tum.in.www1.hephaestus.intelligenceservice.model.PullRequest> mapToApiPullRequests(List<PullRequest> pullRequests) {
return pullRequests.stream().map(pullRequest -> {
de.tum.in.www1.hephaestus.intelligenceservice.model.PullRequest apiPullRequest = new de.tum.in.www1.hephaestus.intelligenceservice.model.PullRequest();
apiPullRequest.setId(String.valueOf(pullRequest.getId()));
apiPullRequest.setTitle(pullRequest.getTitle());
apiPullRequest.setDescription(pullRequest.getBody());
return apiPullRequest;
}).collect(Collectors.toList());
}

private List<Rule> mapToApiRules(List<PullRequestBadPracticeRule> rules) {
return rules.stream().map(rule -> {
Rule apiRule = new Rule();
apiRule.setBadPracticeId(String.valueOf(rule.getId()));
apiRule.setName(rule.getType().getTitle());
apiRule.setDescription(rule.getType().getLlmPrompt());
return apiRule;
}).collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package de.tum.in.www1.hephaestus.activity.model;

import lombok.Getter;

@Getter
public enum BadPracticeType {

UncheckedCheckbox(
"Unchecked Checkbox",
"This pull request contains an unchecked checkbox.",
"The pull request contains an unchecked checkbox. An unchecked checkbox looks like this: '- [ ]'."
),
EmptySection(
"Empty Section",
"This pull request contains an empty section.",
"The pull request contains an empty section. An empty section is a section that does not contain any content. An empty section is directly followed by another section of the same or bigger title size."
);

private final String title;
private final String description;
private final String llmPrompt;

BadPracticeType(String title, String description, String llmPrompt) {
this.title = title;
this.description = description;
this.llmPrompt = llmPrompt;
}
}

0 comments on commit a6678bc

Please sign in to comment.