Skip to content

Commit

Permalink
Exit sputnik with error code if checks fail
Browse files Browse the repository at this point in the history
This allows scripts/tools to take the return result into account.

Furthermore, Extensions of sputnik like the sputnik-maven-plugin can use
a return value of the Engine to communicate the result of a run and do
something like fail a build.

Implement this by adding a Score object (with the review label and the
score value as fields) and return that in Engine.run().

If a failing score value (< 0) is returned, then call System.exit with
the score as the error status.
  • Loading branch information
Marquis Wong authored and Marquis Wong committed Oct 15, 2019
1 parent 01f0303 commit 8a27c63
Show file tree
Hide file tree
Showing 23 changed files with 294 additions and 283 deletions.
6 changes: 5 additions & 1 deletion src/main/java/pl/touk/sputnik/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import pl.touk.sputnik.connector.ConnectorFacadeFactory;
import pl.touk.sputnik.connector.ConnectorType;
import pl.touk.sputnik.engine.Engine;
import pl.touk.sputnik.engine.score.Score;

public final class Main {
private static final String SPUTNIK = "sputnik";
Expand All @@ -38,7 +39,10 @@ public static void main(String[] args) {
configuration.updateWithCliOptions(commandLine);

ConnectorFacade facade = getConnectorFacade(configuration);
new Engine(facade, facade, configuration).run();
Score runResult = new Engine(facade, facade, configuration).run();
if (runResult.getScore() < 0) {
System.exit(runResult.getScore());
}
}

private static ConnectorFacade getConnectorFacade(Configuration configuration) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import pl.touk.sputnik.review.ReviewFile;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

Expand All @@ -23,7 +24,9 @@ public class ReviewInputBuilder {
public ReviewInput toReviewInput(@NotNull Review review) {
ReviewInput reviewInput = new ReviewInput();
reviewInput.message = Joiner.on(". ").join(review.getMessages());
reviewInput.labels = new HashMap<String, Short>(review.getScores());
reviewInput.labels = review.getScore() == null
? Collections.emptyMap()
: Collections.singletonMap(review.getScore().getLabel(), (short) review.getScore().getScore());
reviewInput.comments = new HashMap<String, List<ReviewInput.CommentInput>>();
for (ReviewFile file : review.getFiles()) {
List<ReviewInput.CommentInput> comments = new ArrayList<ReviewInput.CommentInput>();
Expand Down
10 changes: 9 additions & 1 deletion src/main/java/pl/touk/sputnik/engine/Engine.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
import pl.touk.sputnik.connector.ReviewPublisher;
import pl.touk.sputnik.engine.visitor.AfterReviewVisitor;
import pl.touk.sputnik.engine.visitor.BeforeReviewVisitor;
import pl.touk.sputnik.engine.score.ScoreStrategy;
import pl.touk.sputnik.engine.score.ScoreStrategyFactory;
import pl.touk.sputnik.engine.score.Score;
import pl.touk.sputnik.review.Review;
import pl.touk.sputnik.review.ReviewFile;
import pl.touk.sputnik.review.ReviewFormatterFactory;
Expand All @@ -26,7 +29,7 @@ public Engine(ConnectorFacade facade, ReviewPublisher reviewPublisher, Configura
this.config = configuration;
}

public void run() {
public Score run() {
List<ReviewFile> reviewFiles = facade.listFiles();
Review review = new Review(reviewFiles, ReviewFormatterFactory.get(config));

Expand All @@ -44,6 +47,11 @@ public void run() {
afterReviewVisitor.afterReview(review);
}

ScoreStrategy scoreStrategy = new ScoreStrategyFactory().buildScoreStrategy(config);
Score score = scoreStrategy.score(review);
review.setScore(score);
reviewPublisher.publish(review);

return score;
}
}
46 changes: 0 additions & 46 deletions src/main/java/pl/touk/sputnik/engine/VisitorBuilder.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package pl.touk.sputnik.engine;

import com.google.common.collect.ImmutableMap;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.math.NumberUtils;
Expand All @@ -14,24 +13,12 @@
import pl.touk.sputnik.engine.visitor.LimitCommentVisitor;
import pl.touk.sputnik.engine.visitor.RegexFilterFilesVisitor;
import pl.touk.sputnik.engine.visitor.SummaryMessageVisitor;
import pl.touk.sputnik.engine.visitor.score.NoScore;
import pl.touk.sputnik.engine.visitor.score.ScoreAlwaysPass;
import pl.touk.sputnik.engine.visitor.score.ScorePassIfEmpty;
import pl.touk.sputnik.engine.visitor.score.ScorePassIfNoErrors;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static org.apache.commons.lang3.Validate.notBlank;

@Slf4j
public class VisitorBuilder {
private static final String NOSCORE = "NOSCORE";
private static final String SCOREALWAYSPASS = "SCOREALWAYSPASS";
private static final String SCOREPASSIFEMPTY = "SCOREPASSIFEMPTY";
private static final String SCOREPASSIFNOERRORS = "SCOREPASSIFNOERRORS";

@NotNull
public List<BeforeReviewVisitor> buildBeforeReviewVisitors(Configuration configuration) {
List<BeforeReviewVisitor> beforeReviewVisitors = new ArrayList<>();
Expand Down Expand Up @@ -65,40 +52,7 @@ public List<AfterReviewVisitor> buildAfterReviewVisitors(Configuration configura
afterReviewVisitors.add(new LimitCommentVisitor(maxNumberOfComments));
}

afterReviewVisitors.add(buildScoreAfterReviewVisitor(configuration));

return afterReviewVisitors;
}

@NotNull
private AfterReviewVisitor buildScoreAfterReviewVisitor(Configuration configuration) {
Map<String, Short> passingScore = ImmutableMap.<String, Short>of(
configuration.getProperty(GeneralOption.SCORE_PASSING_KEY),
Short.valueOf(configuration.getProperty(GeneralOption.SCORE_PASSING_VALUE))
);
Map<String, Short> failingScore = ImmutableMap.<String, Short>of(
configuration.getProperty(GeneralOption.SCORE_FAILING_KEY),
Short.valueOf(configuration.getProperty(GeneralOption.SCORE_FAILING_VALUE))
);
String scoreStrategy = configuration.getProperty(GeneralOption.SCORE_STRATEGY);
notBlank(scoreStrategy);

switch(scoreStrategy.toUpperCase()) {
case NOSCORE:
return new NoScore();

case SCOREALWAYSPASS:
return new ScoreAlwaysPass(passingScore);

case SCOREPASSIFEMPTY:
return new ScorePassIfEmpty(passingScore, failingScore);

case SCOREPASSIFNOERRORS:
return new ScorePassIfNoErrors(passingScore, failingScore);

default:
log.warn("Score strategy {} not found, using default ScoreAlwaysPass", scoreStrategy);
return new ScoreAlwaysPass(passingScore);
}
}
}
17 changes: 17 additions & 0 deletions src/main/java/pl/touk/sputnik/engine/score/NoScore.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package pl.touk.sputnik.engine.score;

import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import pl.touk.sputnik.review.Review;

@Slf4j
@EqualsAndHashCode
public class NoScore implements ScoreStrategy {

@Override
public Score score(@NotNull Review review) {
log.info("No score for review");
return null;
}
}
13 changes: 13 additions & 0 deletions src/main/java/pl/touk/sputnik/engine/score/Score.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package pl.touk.sputnik.engine.score;

import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;

@AllArgsConstructor
@Getter
@EqualsAndHashCode
public class Score {
private final String label;
private final int score;
}
22 changes: 22 additions & 0 deletions src/main/java/pl/touk/sputnik/engine/score/ScoreAlwaysPass.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package pl.touk.sputnik.engine.score;

import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import pl.touk.sputnik.review.Review;

@Slf4j
@Getter
@EqualsAndHashCode
@AllArgsConstructor
public class ScoreAlwaysPass implements ScoreStrategy {
private final Score passingScore;

@Override
public Score score(@NotNull Review review) {
log.info("Adding static passing score {} to review", passingScore);
return passingScore;
}
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,28 @@
package pl.touk.sputnik.engine.visitor.score;
package pl.touk.sputnik.engine.score;

import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import pl.touk.sputnik.engine.visitor.AfterReviewVisitor;
import pl.touk.sputnik.review.Review;

import java.util.Map;

@Slf4j
@Getter
@EqualsAndHashCode
@AllArgsConstructor
public class ScorePassIfEmpty implements AfterReviewVisitor {
private final Map<String, Short> passingScore;
private final Map<String, Short> failingScore;
public class ScorePassIfEmpty implements ScoreStrategy {
private final Score passingScore;
private final Score failingScore;

@Override
public void afterReview(@NotNull Review review) {
public Score score(@NotNull Review review) {
if (review.getTotalViolationCount() == 0) {
log.info("Adding passing score {} for no violation(s) found", passingScore);
review.setScores(passingScore);
return;
return passingScore;
}

log.info("Adding failing score {} for {} violations found", failingScore, review.getTotalViolationCount());
review.setScores(failingScore);
return failingScore;
}
}
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
package pl.touk.sputnik.engine.visitor.score;
package pl.touk.sputnik.engine.score;

import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import pl.touk.sputnik.engine.visitor.AfterReviewVisitor;
import pl.touk.sputnik.review.Review;
import pl.touk.sputnik.review.Severity;

import java.util.Map;

@Slf4j
@Getter
@EqualsAndHashCode
@AllArgsConstructor
public class ScorePassIfNoErrors implements AfterReviewVisitor {
private final Map<String, Short> passingScore;
private final Map<String, Short> failingScore;
public class ScorePassIfNoErrors implements ScoreStrategy {
private final Score passingScore;
private final Score failingScore;

@Override
public void afterReview(@NotNull Review review) {
public Score score(@NotNull Review review) {
Integer errorCount = review.getViolationCount().get(Severity.ERROR);
if (errorCount == null || errorCount == 0) {
log.info("Adding passing score {} for no errors found", passingScore);
review.setScores(passingScore);
return;
return passingScore;
}

log.info("Adding failing score {} for {} errors found", failingScore, errorCount);
review.setScores(failingScore);
return failingScore;
}
}
8 changes: 8 additions & 0 deletions src/main/java/pl/touk/sputnik/engine/score/ScoreStrategy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package pl.touk.sputnik.engine.score;

import org.jetbrains.annotations.NotNull;
import pl.touk.sputnik.review.Review;

public interface ScoreStrategy {
Score score(@NotNull Review review);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package pl.touk.sputnik.engine.score;

import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import pl.touk.sputnik.configuration.Configuration;
import pl.touk.sputnik.configuration.GeneralOption;

import static org.apache.commons.lang3.Validate.notBlank;

@Slf4j
public class ScoreStrategyFactory {
private static final String NOSCORE = "NOSCORE";
private static final String SCOREALWAYSPASS = "SCOREALWAYSPASS";
private static final String SCOREPASSIFEMPTY = "SCOREPASSIFEMPTY";
private static final String SCOREPASSIFNOERRORS = "SCOREPASSIFNOERRORS";

@NotNull
public ScoreStrategy buildScoreStrategy(Configuration configuration) {
Score passingScore = new Score(
configuration.getProperty(GeneralOption.SCORE_PASSING_KEY),
Short.valueOf(configuration.getProperty(GeneralOption.SCORE_PASSING_VALUE))
);
Score failingScore = new Score(
configuration.getProperty(GeneralOption.SCORE_FAILING_KEY),
Short.valueOf(configuration.getProperty(GeneralOption.SCORE_FAILING_VALUE))
);
String scoreStrategy = configuration.getProperty(GeneralOption.SCORE_STRATEGY);
notBlank(scoreStrategy);

switch(scoreStrategy.toUpperCase()) {
case NOSCORE:
return new NoScore();

case SCOREALWAYSPASS:
return new ScoreAlwaysPass(passingScore);

case SCOREPASSIFEMPTY:
return new ScorePassIfEmpty(passingScore, failingScore);

case SCOREPASSIFNOERRORS:
return new ScorePassIfNoErrors(passingScore, failingScore);

default:
log.warn("Score strategy {} not found, using default ScoreAlwaysPass", scoreStrategy);
return new ScoreAlwaysPass(passingScore);
}
}
}
15 changes: 0 additions & 15 deletions src/main/java/pl/touk/sputnik/engine/visitor/score/NoScore.java

This file was deleted.

This file was deleted.

Loading

0 comments on commit 8a27c63

Please sign in to comment.