Skip to content

Commit

Permalink
Make action independent of github-autograding.
Browse files Browse the repository at this point in the history
  • Loading branch information
uhafner committed Feb 29, 2024
1 parent b75045d commit 3ea1663
Show file tree
Hide file tree
Showing 6 changed files with 242 additions and 13 deletions.
2 changes: 1 addition & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ inputs:

runs:
using: 'docker'
image: 'docker://uhafner/quality-monitor:1.2.0-SNAPSHOT'
image: 'docker://uhafner/quality-monitor:1.2.0'
env:
CONFIG: ${{ inputs.config }}
CHECKS_NAME: ${{ inputs.checks-name }}
Expand Down
2 changes: 1 addition & 1 deletion doc/dependency-graph.puml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ rectangle "spotbugs-annotations\n\n4.8.2" as com_github_spotbugs_spotbugs_annota
rectangle "error_prone_annotations\n\n2.23.0" as com_google_errorprone_error_prone_annotations_jar
rectangle "streamex\n\n0.8.2" as one_util_streamex_jar
rectangle "codingstyle\n\n3.30.0" as edu_hm_hafner_codingstyle_jar
rectangle "quality-monitor\n\n1.2.0-SNAPSHOT" as edu_hm_hafner_quality_monitor_jar
rectangle "quality-monitor\n\n1.2.0" as edu_hm_hafner_quality_monitor_jar
edu_hm_hafner_analysis_model_jar -[#000000]-> org_jsoup_jsoup_jar
org_apache_commons_commons_digester3_jar -[#000000]-> cglib_cglib_jar
org_apache_commons_commons_digester3_jar -[#000000]-> commons_logging_commons_logging_jar
Expand Down
57 changes: 53 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

<groupId>edu.hm.hafner</groupId>
<artifactId>quality-monitor</artifactId>
<version>1.2.0-SNAPSHOT</version>
<version>1.2.0</version>
<packaging>jar</packaging>

<scm>
Expand All @@ -29,16 +29,65 @@

<java.version>17</java.version>

<jib-maven-plugin.version>3.4.1</jib-maven-plugin.version>
<autograding-model.version>3.22.0</autograding-model.version>
<github-api.version>1.319</github-api.version>
<testcontainers.version>1.19.6</testcontainers.version>

<jib-maven-plugin.version>3.4.1</jib-maven-plugin.version>
</properties>

<dependencies>

<dependency>
<groupId>edu.hm.hafner</groupId>
<artifactId>autograding-github-action</artifactId>
<version>3.14.0</version>
<artifactId>autograding-model</artifactId>
<version>${autograding-model.version}</version>
<exclusions>
<exclusion>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
</exclusion>
<exclusion>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</exclusion>
<exclusion>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</exclusion>
<exclusion>
<artifactId>codingstyle</artifactId>
<groupId>edu.hm.hafner</groupId>
</exclusion>
<exclusion>
<artifactId>streamex</artifactId>
<groupId>one.util</groupId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.kohsuke</groupId>
<artifactId>github-api</artifactId>
<version>${github-api.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</exclusion>
<exclusion>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package edu.hm.hafner.grading.github;

import org.apache.commons.lang3.StringUtils;

import edu.hm.hafner.grading.CommentBuilder;

import org.kohsuke.github.GHCheckRun.AnnotationLevel;
import org.kohsuke.github.GHCheckRunBuilder.Annotation;
import org.kohsuke.github.GHCheckRunBuilder.Output;

/**
* Creates GitHub annotations for static analysis warnings, for lines with missing coverage, and for lines with
* survived mutations.
*
* @author Ullrich Hafner
*/
class GitHubAnnotationsBuilder extends CommentBuilder {
private static final String GITHUB_WORKSPACE_REL = "/github/workspace/./";
private static final String GITHUB_WORKSPACE_ABS = "/github/workspace/";

private final Output output;

GitHubAnnotationsBuilder(final Output output, final String prefix) {
super(prefix, GITHUB_WORKSPACE_REL, GITHUB_WORKSPACE_ABS);

this.output = output;
}

@Override
@SuppressWarnings("checkstyle:ParameterNumber")
protected void createComment(final CommentType commentType, final String relativePath,
final int lineStart, final int lineEnd,
final String message, final String title,
final int columnStart, final int columnEnd,
final String details) {
Annotation annotation = new Annotation(relativePath,
lineStart, lineEnd, AnnotationLevel.WARNING, message).withTitle(title);

if (lineStart == lineEnd) {
annotation.withStartColumn(columnStart).withEndColumn(columnEnd);
}
if (StringUtils.isNotBlank(details)) {
annotation.withRawDetails(details);
}

output.add(annotation);
}
}
144 changes: 138 additions & 6 deletions src/main/java/edu/hm/hafner/grading/github/QualityMonitor.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,42 @@
package edu.hm.hafner.grading.github;

import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.Date;

import org.apache.commons.lang3.StringUtils;

import edu.hm.hafner.grading.AggregatedScore;
import edu.hm.hafner.grading.AutoGradingRunner;
import edu.hm.hafner.grading.GradingReport;
import edu.hm.hafner.util.FilteredLog;
import edu.hm.hafner.util.VisibleForTesting;

import org.kohsuke.github.GHCheckRun;
import org.kohsuke.github.GHCheckRun.Conclusion;
import org.kohsuke.github.GHCheckRun.Status;
import org.kohsuke.github.GHCheckRunBuilder;
import org.kohsuke.github.GHCheckRunBuilder.Output;
import org.kohsuke.github.GitHub;
import org.kohsuke.github.GitHubBuilder;

/**
* GitHub action entrypoint for the quality monitor action.
*
* @author Ullrich Hafner
*/
public class QualityMonitor extends GitHubAutoGradingRunner {
public class QualityMonitor extends AutoGradingRunner {
static final String QUALITY_MONITOR = "Quality Monitor";

/**
* Public entry point for the GitHub action in the docker container, simply calls the action.
*
* @param unused
* not used
*/
* Public entry point for the GitHub action in the docker container, simply calls the action.
*
* @param unused
* not used
*/
public static void main(final String... unused) {
new QualityMonitor().run();
}
Expand All @@ -43,4 +62,117 @@ protected String getDisplayName() {
protected String getDefaultConfigurationPath() {
return "/default-no-score-config.json";
}

@Override
protected void publishGradingResult(final AggregatedScore score, final FilteredLog log) {
var errors = createErrorMessageMarkdown(log);

var results = new GradingReport();
addComment(score,
results.getTextSummary(score, getChecksName()),
results.getMarkdownDetails(score, getChecksName()) + errors,
results.getSubScoreDetails(score) + errors,
results.getMarkdownSummary(score, getChecksName()) + errors,
errors.isBlank() ? Conclusion.SUCCESS : Conclusion.FAILURE, log);

try {
var environmentVariables = createEnvironmentVariables(score, log);
Files.writeString(Paths.get("metrics.env"), environmentVariables);
}
catch (IOException exception) {
log.logException(exception, "Can't write environment variables to 'metrics.env'");
}

log.logInfo("GitHub Action has finished");
}

@Override
protected void publishError(final AggregatedScore score, final FilteredLog log, final Throwable exception) {
var results = new GradingReport();

var markdownErrors = results.getMarkdownErrors(score, exception);
addComment(score, results.getTextSummary(score, getChecksName()),
markdownErrors, markdownErrors, markdownErrors, Conclusion.FAILURE, log);
}

private void addComment(final AggregatedScore score, final String textSummary,
final String markdownDetails, final String markdownSummary, final String prSummary,
final Conclusion conclusion, final FilteredLog log) {
try {
var repository = getEnv("GITHUB_REPOSITORY", log);
if (repository.isBlank()) {
log.logError("No GITHUB_REPOSITORY defined - skipping");

return;
}
String oAuthToken = getEnv("GITHUB_TOKEN", log);
if (oAuthToken.isBlank()) {
log.logError("No valid GITHUB_TOKEN found - skipping");

return;
}

String sha = getEnv("GITHUB_SHA", log);

GitHub github = new GitHubBuilder().withAppInstallationToken(oAuthToken).build();
GHCheckRunBuilder check = github.getRepository(repository)
.createCheckRun(getChecksName(), sha)
.withStatus(Status.COMPLETED)
.withStartedAt(Date.from(Instant.now()))
.withConclusion(conclusion);

Output output = new Output(textSummary, markdownSummary).withText(markdownDetails);

if (getEnv("SKIP_ANNOTATIONS", log).isEmpty()) {
var annotationBuilder = new GitHubAnnotationsBuilder(output, computeAbsolutePathPrefixToRemove(log));
annotationBuilder.createAnnotations(score);
}

check.add(output);

GHCheckRun run = check.create();
log.logInfo("Successfully created check " + run);

var prNumber = getEnv("PR_NUMBER", log);
if (!prNumber.isBlank()) { // optional PR comment
github.getRepository(repository)
.getPullRequest(Integer.parseInt(prNumber))
.comment(prSummary + addCheckLink(run));
log.logInfo("Successfully commented PR#" + prNumber);
}
}
catch (IOException exception) {
log.logException(exception, "Could not create check");
}
}

String createEnvironmentVariables(final AggregatedScore score, final FilteredLog log) {
var metrics = new StringBuilder();
score.getMetrics().forEach((metric, value) -> metrics.append(String.format("%s=%d%n", metric, value)));
log.logInfo("---------------");
log.logInfo("Metrics Summary");
log.logInfo("---------------");
log.logInfo(metrics.toString());
return metrics.toString();
}

private String getChecksName() {
return StringUtils.defaultIfBlank(System.getenv("CHECKS_NAME"), getDisplayName());
}

private String computeAbsolutePathPrefixToRemove(final FilteredLog log) {
return String.format("%s/%s/", getEnv("RUNNER_WORKSPACE", log),
StringUtils.substringAfter(getEnv("GITHUB_REPOSITORY", log), "/"));
}

private String addCheckLink(final GHCheckRun run) {
return String.format("%n%n More details are available in the [GitHub Checks Result](%s).%n",
run.getDetailsUrl().toString());
}

private String getEnv(final String key, final FilteredLog log) {
String value = StringUtils.defaultString(System.getenv(key));
log.logInfo(">>>> " + key + ": " + value);
return value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ void shouldShowErrors() throws TimeoutException {
}

private GenericContainer<?> createContainer() {
return new GenericContainer<>(DockerImageName.parse("uhafner/quality-monitor:1.2.0-SNAPSHOT"));
return new GenericContainer<>(DockerImageName.parse("uhafner/quality-monitor:1.2.0"));
}

private String readStandardOut(final GenericContainer<? extends GenericContainer<?>> container) throws TimeoutException {
Expand Down

0 comments on commit 3ea1663

Please sign in to comment.