Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement codecheck api #4

Merged
merged 2 commits into from
Oct 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ on: # yamllint disable-line rule:truthy
jobs:
build:
name: "build"
permissions:
checks: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -42,7 +40,7 @@ jobs:
java-version: '17'
cache: 'gradle'
- name: Cache SonarQube packages
uses: actions/cache@v1
uses: actions/cache@v3
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
Expand Down Expand Up @@ -90,7 +88,8 @@ jobs:
- name: Qualityannotate
if: success() && steps.findPr.outputs.number
env:
GITHUB_TOKEN: ${{ secrets.TOKEN }}
# ${{ secrets.TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_PULL_REQUEST: ${{ steps.findPr.outputs.pr }}
GITHUB_PROJECT: balrok/qualityannotate # ${{env.GITHUB_ACTION_REPOSITORY}}
SONARQUBE_PROJECT: quyt_qualityannotate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

import java.util.List;

import org.qualityannotate.api.qualitytool.MetricsAndIssues;

public interface CodeRepository {
void createOrUpdateAnnotations(Comment globalComment, List<FileComment> fileComments) throws Exception;
void createOrUpdateAnnotations(Comment globalComment, List<FileComment> fileComments,
MetricsAndIssues metricsAndIssues) throws Exception;

Check warning on line 9 in src/main/java/org/qualityannotate/api/coderepository/CodeRepository.java

View workflow job for this annotation

GitHub Actions / qualityannotate

src/main/java/org/qualityannotate/api/coderepository/CodeRepository.java#L9

⚠️maintainability: Define and throw a dedicated exception instead of using a generic one. https://sonarcloud.io/organizations/quyt/rules?open=java:S112&rule_key=java:S112

String printConfigWithoutSecrets();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.qualityannotate.api.coderepository;

import org.qualityannotate.api.coderepository.api.CodeStructuredApi;
import org.qualityannotate.api.qualitytool.MetricsAndIssues;

public final class CodeStructuredExecutor {
private CodeStructuredExecutor() {

}

public static void run(CodeStructuredApi codeStructuredApi, MetricsAndIssues metricsAndIssues) throws Exception {

Check warning on line 11 in src/main/java/org/qualityannotate/api/coderepository/CodeStructuredExecutor.java

View workflow job for this annotation

GitHub Actions / qualityannotate

src/main/java/org/qualityannotate/api/coderepository/CodeStructuredExecutor.java#L11

⚠️maintainability: Define and throw a dedicated exception instead of using a generic one. https://sonarcloud.io/organizations/quyt/rules?open=java:S112&rule_key=java:S112
codeStructuredApi.update(metricsAndIssues);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,25 @@
import org.apache.commons.lang3.tuple.Pair;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.*;
import java.util.stream.Collectors;

import org.qualityannotate.api.coderepository.api.CodeApi;
import org.qualityannotate.api.coderepository.api.CodeFileComment;
import org.qualityannotate.api.coderepository.api.CodeMainComment;
import org.qualityannotate.api.coderepository.api.CodeStructuredApi;
import org.qualityannotate.api.coderepository.api.CodeTextApi;
import org.qualityannotate.api.coderepository.api.CodeTextFileComment;
import org.qualityannotate.api.coderepository.api.CodeTextMainComment;
import org.qualityannotate.api.qualitytool.MetricsAndIssues;

public abstract class AbstractCodeRepository implements CodeRepository {
public final class CodeTextExecutor {
private CodeTextExecutor() {

protected static Map<Pair<String, Integer>, String> convertFileCommentsToMap(List<FileComment> fileComments) {
Map<Pair<String, Integer>, List<Comment>> fileLineToCommentList = new HashMap<>();
for (FileComment fileComment : fileComments) {
List<Comment> comments = fileLineToCommentList
.computeIfAbsent(Pair.of(fileComment.fileName(), fileComment.linenumber()), k -> new ArrayList<>());
comments.add(fileComment.comment());
}
return fileLineToCommentList.entrySet()
.stream()
.map(e -> Map.entry(e.getKey(), e.getValue().stream().reduce((c1, c2) -> c1).orElse(Comment.EMPTY)))
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().markdown()));
}

protected abstract CodeApi getCodeApi();

@Override
public void createOrUpdateAnnotations(Comment globalComment, List<FileComment> fileComments) {
CodeApi codeApi = getCodeApi();
Optional<CodeMainComment> mainComment = Optional.empty();
public static void run(CodeTextApi codeTextApi, Comment globalComment, List<FileComment> fileComments)

Check failure on line 21 in src/main/java/org/qualityannotate/api/coderepository/CodeTextExecutor.java

View workflow job for this annotation

GitHub Actions / qualityannotate

src/main/java/org/qualityannotate/api/coderepository/CodeTextExecutor.java#L21

🛑maintainability: Refactor this method to reduce its Cognitive Complexity from 23 to the 15 allowed. https://sonarcloud.io/organizations/quyt/rules?open=java:S3776&rule_key=java:S3776
throws Exception {

Check warning on line 22 in src/main/java/org/qualityannotate/api/coderepository/CodeTextExecutor.java

View workflow job for this annotation

GitHub Actions / qualityannotate

src/main/java/org/qualityannotate/api/coderepository/CodeTextExecutor.java#L22

⚠️maintainability: Define and throw a dedicated exception instead of using a generic one. https://sonarcloud.io/organizations/quyt/rules?open=java:S112&rule_key=java:S112
Optional<CodeTextMainComment> mainComment = Optional.empty();
try {
mainComment = codeApi.getMainComment();
mainComment = codeTextApi.getMainComment();
} catch (IOException e) {
Log.warn("Could not retrieve main comment");
}
Expand All @@ -50,20 +34,20 @@
}
}, () -> {
try {
codeApi.createMainComment(globalComment.markdown());
codeTextApi.createMainComment(globalComment.markdown());
} catch (IOException e) {
Log.warn("Could not create main comment", e);
}
});

Map<Pair<String, Integer>, String> fileLineToComment = convertFileCommentsToMap(fileComments);
List<CodeFileComment> githubFileComments = Collections.emptyList();
List<CodeTextFileComment> githubFileComments = Collections.emptyList();
try {
githubFileComments = codeApi.listFileComments();
githubFileComments = codeTextApi.listFileComments();
} catch (IOException e) {
Log.warn("Could not retrieve comments");
}
for (CodeFileComment review : githubFileComments) {
for (CodeTextFileComment review : githubFileComments) {
String comment = fileLineToComment.get(review.getFileLine());
Log.info("Found existing file comment");
if (comment != null) {
Expand All @@ -90,11 +74,29 @@
for (Map.Entry<Pair<String, Integer>, String> fileLineCommentEntry : fileLineToComment.entrySet()) {
try {
Log.infof("Creating %s", fileLineCommentEntry.getKey());
codeApi.createFileComment(fileLineCommentEntry.getKey().getLeft(),
codeTextApi.createFileComment(fileLineCommentEntry.getKey().getLeft(),
fileLineCommentEntry.getKey().getRight(), fileLineCommentEntry.getValue());
} catch (IOException e) {
Log.warn("Could not create comment", e);
}
}
}

private static Map<Pair<String, Integer>, String> convertFileCommentsToMap(List<FileComment> fileComments) {
Map<Pair<String, Integer>, List<Comment>> fileLineToCommentList = new HashMap<>();
for (FileComment fileComment : fileComments) {
List<Comment> comments = fileLineToCommentList
.computeIfAbsent(Pair.of(fileComment.fileName(), fileComment.linenumber()), k -> new ArrayList<>());
comments.add(fileComment.comment());
}
return fileLineToCommentList.entrySet()
.stream()
.map(e -> Map.entry(e.getKey(), e.getValue().stream().reduce((c1, c2) -> c1).orElse(Comment.EMPTY)))
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().markdown()));
}

private static void runCodeStructuredApi(CodeStructuredApi codeStructuredApi, MetricsAndIssues metricsAndIssues)

Check warning on line 98 in src/main/java/org/qualityannotate/api/coderepository/CodeTextExecutor.java

View workflow job for this annotation

GitHub Actions / qualityannotate

src/main/java/org/qualityannotate/api/coderepository/CodeTextExecutor.java#L98

⚠️maintainability: Remove this unused private "runCodeStructuredApi" method. https://sonarcloud.io/organizations/quyt/rules?open=java:S1144&rule_key=java:S1144
throws Exception {

Check warning on line 99 in src/main/java/org/qualityannotate/api/coderepository/CodeTextExecutor.java

View workflow job for this annotation

GitHub Actions / qualityannotate

src/main/java/org/qualityannotate/api/coderepository/CodeTextExecutor.java#L99

⚠️maintainability: Define and throw a dedicated exception instead of using a generic one. https://sonarcloud.io/organizations/quyt/rules?open=java:S112&rule_key=java:S112
codeStructuredApi.update(metricsAndIssues);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.qualityannotate.api.coderepository.api;

import java.io.IOException;

import org.qualityannotate.api.qualitytool.MetricsAndIssues;

/**
* Abstraction for the API of Code repositories like Gitlab, github, bitbucket, etc.
* Can be used best for APIs which are structured and know about issues with severity. So github-checks
* api and bitbucket-report api are well suited.
*/
public interface CodeStructuredApi {
void update(MetricsAndIssues metricsAndIssues) throws IOException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.qualityannotate.api.coderepository.api;

import java.io.IOException;
import java.util.List;
import java.util.Optional;

/**
* Abstraction for the API of Code repositories like Gitlab, github, bitbucket, etc.
* Can be used best for APIs which are only text-based. So github-checks api and bitbucket-report api should use a
* different interface.
*/
public interface CodeTextApi {
Optional<CodeTextMainComment> getMainComment() throws IOException;

void createMainComment(String comment) throws IOException;

List<CodeTextFileComment> listFileComments() throws IOException;

void createFileComment(String file, Integer line, String comment) throws IOException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import java.io.IOException;

public interface CodeFileComment {
public interface CodeTextFileComment {
void update(String comment) throws IOException;

void delete() throws IOException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

import java.io.IOException;

public interface CodeMainComment {
public interface CodeTextMainComment {
void update(String comment) throws IOException;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package org.qualityannotate.api.qualitytool;

import jakarta.annotation.Nullable;

import java.util.Map;
import java.util.Optional;

public record GlobalMetrics(Map<String, String> metrics) {
public record GlobalMetrics(Map<String, String> metrics, String url, @Nullable String statusUrl) {
public Optional<String> getStatusUrl() {
return Optional.ofNullable(statusUrl);
}
}
18 changes: 17 additions & 1 deletion src/main/java/org/qualityannotate/api/qualitytool/Issue.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
package org.qualityannotate.api.qualitytool;

import jakarta.annotation.Nullable;
import lombok.AllArgsConstructor;
import lombok.Getter;

public record Issue(String fileName, Integer lineNumber, String comment, String severity, @Nullable String urlToIssue) {
public record Issue(String fileName, Integer startLine, @Nullable Integer endLine, @Nullable Integer startColumn,
@Nullable Integer endColumn, String comment, String severity, Severity severityEnum,
@Nullable String urlToIssue) {

public Integer lineNumber() {
return startLine;
}

@AllArgsConstructor
@Getter
public enum Severity {
LOW("ℹ\uFE0F"), MEDIUM("⚠\uFE0F"), HIGH("\uD83D\uDED1");

private final String unicodeIcon;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,5 @@
public interface QualityTool {
MetricsAndIssues getMetricsAndIssues() throws Exception;

String getSeverityReadable(String severity);

String getSeverityIcon(String severity);

String printConfigWithoutSecrets();

String getUrl();
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,41 @@
package org.qualityannotate.coderepo.github;

import io.quarkus.logging.Log;
import jakarta.enterprise.context.ApplicationScoped;
import lombok.AllArgsConstructor;

import java.util.List;

import org.qualityannotate.api.coderepository.AbstractCodeRepository;
import org.qualityannotate.api.coderepository.CodeRepository;
import org.qualityannotate.api.coderepository.api.CodeApi;
import org.qualityannotate.coderepo.github.client.GithubApi;
import org.qualityannotate.api.coderepository.CodeStructuredExecutor;
import org.qualityannotate.api.coderepository.CodeTextExecutor;
import org.qualityannotate.api.coderepository.Comment;
import org.qualityannotate.api.coderepository.FileComment;
import org.qualityannotate.api.qualitytool.MetricsAndIssues;
import org.qualityannotate.coderepo.github.client.GithubStructuredApi;
import org.qualityannotate.coderepo.github.client.GithubTextApi;

@ApplicationScoped
public class GithubCodeRepository extends AbstractCodeRepository implements CodeRepository {
@AllArgsConstructor
public class GithubCodeRepository implements CodeRepository {
private final GithubConfig config;
private final GithubApi githubApi;
private final GithubTextApi githubTextApi;
private final GithubStructuredApi githubStructuredApi;

public GithubCodeRepository(GithubConfig config) {
this.config = config;
this.githubApi = new GithubApi(config.token(), config.project(), config.pullRequest());
@Override
public void createOrUpdateAnnotations(Comment globalComment, List<FileComment> fileComments,
MetricsAndIssues metricsAndIssues) throws Exception {
if (config.useChecks()) {

Check notice on line 28 in src/main/java/org/qualityannotate/coderepo/github/GithubCodeRepository.java

View workflow job for this annotation

GitHub Actions / qualityannotate

src/main/java/org/qualityannotate/coderepo/github/GithubCodeRepository.java#L28

ℹ️maintainability: Use a primitive boolean expression here. https://sonarcloud.io/organizations/quyt/rules?open=java:S5411&rule_key=java:S5411
Log.info("Using the checks api");
CodeStructuredExecutor.run(githubStructuredApi, metricsAndIssues);
} else {
Log.info("Using the comment-based api");
CodeTextExecutor.run(githubTextApi, globalComment, fileComments);
}
}

@Override
public String printConfigWithoutSecrets() {
return config.printWithoutSecrets();
}

@Override
protected CodeApi getCodeApi() {
return githubApi;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.qualityannotate.coderepo.github;

import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithDefault;
import io.smallrye.config.WithName;

@ConfigMapping(prefix = GithubConfig.NAME)
Expand All @@ -16,10 +17,18 @@ public interface GithubConfig {
@WithName("pull_request")
Integer pullRequest();

/**
* when true will use the checks-api, otherwise it will write comments
*/
@WithName("use_checks")
@WithDefault("true")
Boolean useChecks();

default String printWithoutSecrets() {
return String.format("""
project: %s
pull_request: %s
""", project(), pullRequest());
use_checks: %s
""", project(), pullRequest(), useChecks());
}
}
Loading