diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index fd9d124717..37203c3b13 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -13,13 +13,17 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: '11' + java-version: '21' check-latest: true cache: 'maven' + - name: Set up Maven + uses: stCarolas/setup-maven@v4.5 + with: + maven-version: 3.9.6 - name: Build warnings plugin and download dependencies run: mvn -V --color always -ntp verify -Pskip --file plugin/pom.xml -Dgpg.skip - name: Run UI tests for the details tabs @@ -33,13 +37,17 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: '11' + java-version: '21' check-latest: true cache: 'maven' + - name: Set up Maven + uses: stCarolas/setup-maven@v4.5 + with: + maven-version: 3.9.6 - name: Build warnings plugin and download dependencies run: mvn -V --color always -ntp verify -Pskip --file plugin/pom.xml -Dgpg.skip - name: Run UI tests for the dashboard view @@ -53,13 +61,17 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: '11' + java-version: '21' check-latest: true cache: 'maven' + - name: Set up Maven + uses: stCarolas/setup-maven@v4.5 + with: + maven-version: 3.9.6 - name: Build warnings plugin and download dependencies run: mvn -V --color always -ntp verify -Pskip --file plugin/pom.xml -Dgpg.skip - name: Run UI tests for the freestyle configuration @@ -73,13 +85,17 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: '11' + java-version: '21' check-latest: true cache: 'maven' + - name: Set up Maven + uses: stCarolas/setup-maven@v4.5 + with: + maven-version: 3.9.6 - name: Build warnings plugin and download dependencies run: mvn -V --color always -ntp verify -Pskip --file plugin/pom.xml -Dgpg.skip - name: Run UI tests for the pipeline snippet configurator @@ -93,13 +109,17 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: '11' + java-version: '21' check-latest: true cache: 'maven' + - name: Set up Maven + uses: stCarolas/setup-maven@v4.5 + with: + maven-version: 3.9.6 - name: Build warnings plugin and download dependencies run: mvn -V --color always -ntp verify -Pskip --file plugin/pom.xml -Dgpg.skip - name: Run UI tests for Jenkins' global configuration @@ -113,13 +133,17 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: '11' + java-version: '21' check-latest: true cache: 'maven' + - name: Set up Maven + uses: stCarolas/setup-maven@v4.5 + with: + maven-version: 3.9.6 - name: Build warnings plugin and download dependencies run: mvn -V --color always -ntp verify -Pskip --file plugin/pom.xml -Dgpg.skip - name: Run UI tests for the issues column @@ -133,13 +157,17 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: '11' + java-version: '21' check-latest: true cache: 'maven' + - name: Set up Maven + uses: stCarolas/setup-maven@v4.5 + with: + maven-version: 3.9.6 - name: Build warnings plugin and download dependencies run: mvn -V --color always -ntp verify -Pskip --file plugin/pom.xml -Dgpg.skip - name: Run UI tests for the trend charts @@ -153,13 +181,17 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: '11' + java-version: '21' check-latest: true cache: 'maven' + - name: Set up Maven + uses: stCarolas/setup-maven@v4.5 + with: + maven-version: 3.9.6 - name: Build warnings plugin and download dependencies run: mvn -V --color always -ntp verify -Pskip --file plugin/pom.xml -Dgpg.skip - name: Run miscellaneous UI tests of the warnings plugin diff --git a/doc/Documentation.md b/doc/Documentation.md index 0c24e41d5c..9038beb195 100644 --- a/doc/Documentation.md +++ b/doc/Documentation.md @@ -462,12 +462,11 @@ the number of issues that will fail a given quality gate. An example pipeline with these options is shown in the following snippet: ```groovy -recordIssues tool: java(pattern: '*.log'), qualityGates: [[threshold: 1, type: 'TOTAL', unstable: true]] +recordIssues tool: java(pattern: '*.log'), qualityGates: [[threshold: 1, type: 'TOTAL', criticality: 'FAILURE']] ``` The type determines the property that will be picked to evaluate the quality gate. Refer to the enum -[QualityGateType](../plugin/src/main/java/io/jenkins/plugins/analysis/core/util/QualityGate.java) to see which different -types are supported. +[QualityGateType](../plugin/src/main/java/io/jenkins/plugins/analysis/core/util/WarningsQualityGate.java) to see which different types are supported. ### Health report configuration diff --git a/plugin/pom.xml b/plugin/pom.xml index a1c9ca0439..d25d156d3e 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -21,7 +21,7 @@ https://github.com/jenkinsci/warnings-ng-plugin - 10.8.0 + 11.0.0 -SNAPSHOT ${project.groupId}.warnings.ng @@ -51,6 +51,7 @@ -Djava.awt.headless=true -Xmx1024m -Djenkins.test.timeout=1000 --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.util.concurrent=ALL-UNNAMED 1.29.0-8 + 3.9.0-rc855.756b_f8df78a_1 @@ -102,6 +103,7 @@ io.jenkins.plugins plugin-util-api + ${plugin-util-api.version} io.jenkins.plugins @@ -314,6 +316,7 @@ io.jenkins.plugins plugin-util-api + ${plugin-util-api.version} test tests @@ -369,6 +372,12 @@ parasoft-findings 10.7.1 test + + + warnings-ng + io.jenkins.plugins + + org.jenkins-ci.plugins diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/AggregatedTrendAction.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/AggregatedTrendAction.java index 96f9ae8b5a..d0ec002c39 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/AggregatedTrendAction.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/AggregatedTrendAction.java @@ -31,7 +31,6 @@ */ public class AggregatedTrendAction implements Action, AsyncConfigurableTrendChart { private static final int MIN_TOOLS = 2; - private static final String EMPTY = "{}"; private final Job owner; @@ -76,17 +75,6 @@ private Set createBuildHistory() { } } - /** - * Returns the trend chart model that renders the aggregated build results. - * - * @return the trend chart - * @deprecated replaced {@link #getConfigurableBuildTrendModel(String)} - */ - @Deprecated - public String getBuildTrendModel() { - return getConfigurableBuildTrendModel(EMPTY); - } - /** * Returns the trend chart model that renders the aggregated build results. * diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/AnalysisHistory.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/AnalysisHistory.java index 11b0d0db76..8e536222bd 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/AnalysisHistory.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/AnalysisHistory.java @@ -14,8 +14,6 @@ import io.jenkins.plugins.analysis.core.charts.JenkinsBuild; import io.jenkins.plugins.analysis.core.util.AnalysisBuildResult; -import io.jenkins.plugins.analysis.core.util.QualityGateEvaluator; -import io.jenkins.plugins.analysis.core.util.QualityGateStatus; import static io.jenkins.plugins.analysis.core.model.AnalysisHistory.JobResultEvaluationMode.*; import static io.jenkins.plugins.analysis.core.model.AnalysisHistory.QualityGateEvaluationMode.*; @@ -44,7 +42,7 @@ public class AnalysisHistory implements History { private final JobResultEvaluationMode jobResultEvaluationMode; /** - * Determines how the evaluation of the {@link QualityGateEvaluator} is taken into account when the previous result is + * Determines how the evaluation of the quality gates is taken into account when the previous result is * searched for. */ public enum QualityGateEvaluationMode { @@ -53,7 +51,7 @@ public enum QualityGateEvaluationMode { */ IGNORE_QUALITY_GATE, /** - * The quality gate result must be {@link QualityGateStatus#isSuccessful()}. I.e. the history is searched for a + * The quality gate result must be successful. I.e., the history is searched for a * build that either passed the quality gate or has deactivated the quality gate. */ SUCCESSFUL_QUALITY_GATE @@ -65,7 +63,7 @@ public enum QualityGateEvaluationMode { */ public enum JobResultEvaluationMode { /** - * Only those jobs are considered that did not fail. I.e. jobs with result {@link Result#UNSTABLE} or {@link + * Only those jobs are considered that did not fail. I.e., jobs with result {@link Result#UNSTABLE} or {@link * Result#SUCCESS}. */ NO_JOB_FAILURE, @@ -78,7 +76,7 @@ public enum JobResultEvaluationMode { } /** - * Creates a new instance of {@link AnalysisHistory}. This history ignores the {@link QualityGateStatus} of the + * Creates a new instance of {@link AnalysisHistory}. This history ignores the results of the * quality gate and the {@link Result} of the associated {@link Run}. * * @param baseline diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/AnalysisResult.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/AnalysisResult.java index 9a958cfb78..3d548dc6e7 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/AnalysisResult.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/AnalysisResult.java @@ -32,14 +32,15 @@ import io.jenkins.plugins.analysis.core.charts.JenkinsBuild; import io.jenkins.plugins.analysis.core.util.IssuesStatistics; import io.jenkins.plugins.analysis.core.util.IssuesStatisticsBuilder; -import io.jenkins.plugins.analysis.core.util.QualityGateEvaluator; -import io.jenkins.plugins.analysis.core.util.QualityGateStatus; import io.jenkins.plugins.analysis.core.util.StaticAnalysisRun; import io.jenkins.plugins.forensics.blame.Blames; import io.jenkins.plugins.forensics.blame.BlamesXmlStream; import io.jenkins.plugins.forensics.miner.RepositoryStatistics; import io.jenkins.plugins.forensics.miner.RepositoryStatisticsXmlStream; import io.jenkins.plugins.util.JenkinsFacade; +import io.jenkins.plugins.util.QualityGateEvaluator; +import io.jenkins.plugins.util.QualityGateResult; +import io.jenkins.plugins.util.QualityGateStatus; import io.jenkins.plugins.util.ValidationUtilities; /** @@ -49,7 +50,7 @@ * @author Ullrich Hafner */ @SuppressFBWarnings(value = "SE, DESERIALIZATION_GADGET", justification = "transient fields are restored using a Jenkins callback (or are checked for null)") -@SuppressWarnings({"PMD.TooManyFields", "PMD.ExcessiveClassLength", "PMD.GodClass", "checkstyle:ClassFanOutComplexity"}) +@SuppressWarnings({"PMD.TooManyFields", "PMD.ExcessiveClassLength", "PMD.GodClass", "checkstyle:ClassFanOutComplexity", "checkstyle:ClassDataAbstractionCoupling"}) public class AnalysisResult implements Serializable, StaticAnalysisRun { private static final long serialVersionUID = 1110545450292087475L; @@ -74,18 +75,18 @@ public class AnalysisResult implements Serializable, StaticAnalysisRun { private transient Run owner; /** - * All outstanding issues: i.e. all issues, that are part of the current and reference report. + * All outstanding issues: i.e., all issues, that are part of the current and reference report. */ @CheckForNull private transient WeakReference outstandingIssuesReference; /** - * All new issues: i.e. all issues, that are part of the current report but have not been shown up in the reference + * All new issues: i.e., all issues, that are part of the current report but have not been shown up in the reference * report. */ @CheckForNull private transient WeakReference newIssuesReference; /** - * All fixed issues: i.e. all issues, that are part of the reference report but are not present in the current + * All fixed issues: i.e., all issues, that are part of the reference report but are not present in the current * report anymore. */ @CheckForNull @@ -104,13 +105,15 @@ public class AnalysisResult implements Serializable, StaticAnalysisRun { /** Determines since which build the result is successful. */ private int successfulSinceBuild; /** The result of the quality gate evaluation. */ - private final QualityGateStatus qualityGateStatus; + private transient QualityGateStatus qualityGateStatus; + /** The result of the quality gate evaluation. */ + private QualityGateResult qualityGateResult; /** * Creates a new instance of {@link AnalysisResult}. * * @param owner - * the current build as owner of this action + * the current build as the owner of this action * @param id * ID of the results * @param report @@ -119,7 +122,7 @@ public class AnalysisResult implements Serializable, StaticAnalysisRun { * author and commit information for all issues * @param totals * repository statistics for all issues - * @param qualityGateStatus + * @param qualityGateResult * the quality gate status * @param sizePerOrigin * the number of issues per origin @@ -128,10 +131,9 @@ public class AnalysisResult implements Serializable, StaticAnalysisRun { */ @SuppressWarnings("checkstyle:ParameterNumber") public AnalysisResult(final Run owner, final String id, final DeltaReport report, final Blames blames, - final RepositoryStatistics totals, final QualityGateStatus qualityGateStatus, - final Map sizePerOrigin, - final AnalysisResult previousResult) { - this(owner, id, report, blames, totals, qualityGateStatus, sizePerOrigin, true); + final RepositoryStatistics totals, final QualityGateResult qualityGateResult, + final Map sizePerOrigin, final AnalysisResult previousResult) { + this(owner, id, report, blames, totals, qualityGateResult, sizePerOrigin, true); if (report.isEmpty()) { if (previousResult.noIssuesSinceBuild == NO_BUILD) { @@ -145,8 +147,9 @@ public AnalysisResult(final Run owner, final String id, final DeltaReport noIssuesSinceBuild = NO_BUILD; } - if (this.qualityGateStatus == QualityGateStatus.PASSED) { - if (previousResult.qualityGateStatus == QualityGateStatus.PASSED) { + var overallStatus = qualityGateResult.getOverallStatus(); + if (overallStatus == QualityGateStatus.PASSED) { + if (previousResult.getQualityGateResult().getOverallStatus() == QualityGateStatus.PASSED) { successfulSinceBuild = previousResult.successfulSinceBuild; } else { @@ -162,7 +165,7 @@ public AnalysisResult(final Run owner, final String id, final DeltaReport * Creates a new instance of {@link AnalysisResult}. * * @param owner - * the current build as owner of this action + * the current build as the owner of this action * @param id * ID of the results * @param report @@ -171,15 +174,15 @@ public AnalysisResult(final Run owner, final String id, final DeltaReport * author and commit information for all issues * @param totals * repository statistics for all issues - * @param qualityGateStatus + * @param qualityGateResult * the quality gate status * @param sizePerOrigin * the number of issues per origin */ public AnalysisResult(final Run owner, final String id, final DeltaReport report, final Blames blames, - final RepositoryStatistics totals, final QualityGateStatus qualityGateStatus, + final RepositoryStatistics totals, final QualityGateResult qualityGateResult, final Map sizePerOrigin) { - this(owner, id, report, blames, totals, qualityGateStatus, sizePerOrigin, true); + this(owner, id, report, blames, totals, qualityGateResult, sizePerOrigin, true); if (report.isEmpty()) { noIssuesSinceBuild = owner.getNumber(); @@ -187,7 +190,7 @@ public AnalysisResult(final Run owner, final String id, final DeltaReport else { noIssuesSinceBuild = NO_BUILD; } - if (this.qualityGateStatus == QualityGateStatus.PASSED) { + if (qualityGateResult.getOverallStatus() == QualityGateStatus.PASSED) { successfulSinceBuild = owner.getNumber(); } else { @@ -199,7 +202,7 @@ public AnalysisResult(final Run owner, final String id, final DeltaReport * Creates a new instance of {@link AnalysisResult}. * * @param owner - * the current run as owner of this action + * the current run as the owner of this action * @param id * ID of the results * @param report @@ -208,7 +211,7 @@ public AnalysisResult(final Run owner, final String id, final DeltaReport * author and commit information for all issues * @param repositoryStatistics * source code repository statistics for all issues - * @param qualityGateStatus + * @param qualityGateResult * the quality gate status * @param sizePerOrigin * the number of issues per origin @@ -219,7 +222,7 @@ public AnalysisResult(final Run owner, final String id, final DeltaReport @SuppressWarnings("checkstyle:ParameterNumber") protected AnalysisResult(final Run owner, final String id, final DeltaReport report, final Blames blames, final RepositoryStatistics repositoryStatistics, - final QualityGateStatus qualityGateStatus, final Map sizePerOrigin, + final QualityGateResult qualityGateResult, final Map sizePerOrigin, final boolean canSerialize) { this.owner = owner; @@ -245,7 +248,7 @@ protected AnalysisResult(final Run owner, final String id, final DeltaRepo messages = new ArrayList<>(aggregatedMessages); errors = new ArrayList<>(allIssues.getErrorMessages()); - this.qualityGateStatus = qualityGateStatus; + this.qualityGateResult = qualityGateResult; blamesReference = new WeakReference<>(blames); this.repositoryStatistics = new WeakReference<>(repositoryStatistics); @@ -263,21 +266,11 @@ protected AnalysisResult(final Run owner, final String id, final DeltaRepo * @return this */ protected Object readResolve() { + if (qualityGateResult == null && qualityGateStatus != null) { + qualityGateResult = new QualityGateResult(qualityGateStatus); + } if (totals == null) { - IssuesStatisticsBuilder builder = new IssuesStatisticsBuilder(); - - builder.setTotalErrorSize(sizePerSeverity.getOrDefault(Severity.ERROR, 0)); - builder.setTotalHighSize(sizePerSeverity.getOrDefault(Severity.WARNING_HIGH, 0)); - builder.setTotalNormalSize(sizePerSeverity.getOrDefault(Severity.WARNING_NORMAL, 0)); - builder.setTotalLowSize(sizePerSeverity.getOrDefault(Severity.WARNING_LOW, 0)); - - builder.setNewErrorSize(newSizePerSeverity.getOrDefault(Severity.ERROR, 0)); - builder.setNewHighSize(newSizePerSeverity.getOrDefault(Severity.WARNING_HIGH, 0)); - builder.setNewNormalSize(newSizePerSeverity.getOrDefault(Severity.WARNING_NORMAL, 0)); - builder.setNewLowSize(newSizePerSeverity.getOrDefault(Severity.WARNING_LOW, 0)); - - builder.setFixedSize(fixedSize); - totals = builder.build(); + totals = new IssuesStatisticsBuilder().build(); } return this; } @@ -439,7 +432,7 @@ public boolean hasNoNewWarnings() { } /** - * Returns all outstanding issues of the associated static analysis run. I.e. all issues, that are part of the + * Returns all outstanding issues of the associated static analysis run. I.e., all issues that are part of the * current and previous report. * * @return all outstanding issues @@ -451,7 +444,7 @@ public Report getOutstandingIssues() { } /** - * Returns all new issues of the associated static analysis run. I.e. all issues, that are part of the current + * Returns all new issues of the associated static analysis run. I.e., all issues that are part of the current * report but have not been shown up in the previous report. * * @return all new issues @@ -463,7 +456,7 @@ public Report getNewIssues() { } /** - * Returns all fixed issues of the associated static analysis run. I.e. all issues, that are part of the previous + * Returns all fixed issues of the associated static analysis run. I.e., all issues that are part of the previous * report but are not present in the current report anymore. * * @return all fixed issues @@ -474,6 +467,7 @@ public Report getFixedIssues() { "fixed"); } + @CheckForNull private WeakReference getOutstandingIssuesReference() { return outstandingIssuesReference; } @@ -482,6 +476,7 @@ private void setOutstandingIssuesReference(final WeakReference outstandi this.outstandingIssuesReference = outstandingIssuesReference; } + @CheckForNull private WeakReference getNewIssuesReference() { return newIssuesReference; } @@ -490,6 +485,7 @@ private void setNewIssuesReference(final WeakReference newIssuesReferenc this.newIssuesReference = newIssuesReference; } + @CheckForNull private WeakReference getFixedIssuesReference() { return fixedIssuesReference; } @@ -542,13 +538,18 @@ public int getSuccessfulSinceBuild() { * @see QualityGateEvaluator */ public boolean isSuccessful() { - return qualityGateStatus.isSuccessful(); + return qualityGateResult.isSuccessful(); } - @Whitelisted @Override public QualityGateStatus getQualityGateStatus() { - return qualityGateStatus; + return qualityGateResult.getOverallStatus(); + } + + @Whitelisted + @Override + public QualityGateResult getQualityGateResult() { + return qualityGateResult; } @Override @@ -612,9 +613,9 @@ public int getTotalErrorsSize() { } /** - * Returns the total number of high severity issues in this analysis run. + * Returns the total number of high-severity issues in this analysis run. * - * @return total number of high severity issues + * @return total number of high-severity issues */ public int getTotalHighPrioritySize() { return getTotalSizeOf(Severity.WARNING_HIGH); @@ -630,9 +631,9 @@ public int getTotalNormalPrioritySize() { } /** - * Returns the total number of low severity issues in this analysis run. + * Returns the total number of low-severity issues in this analysis run. * - * @return total number of low severity of issues + * @return total number of low-severity issues */ public int getTotalLowPrioritySize() { return getTotalSizeOf(Severity.WARNING_LOW); @@ -658,27 +659,27 @@ public int getNewErrorSize() { } /** - * Returns the number of new high severity issues in this analysis run. + * Returns the number of new high-severity issues in this analysis run. * - * @return number of new high severity issues + * @return number of new high-severity issues */ public int getNewHighPrioritySize() { return getNewSizeOf(Severity.WARNING_HIGH); } /** - * Returns the number of new normal severity issues in this analysis run. + * Returns the number of new normal-severity issues in this analysis run. * - * @return number of new normal severity issues + * @return number of new normal-severity issues */ public int getNewNormalPrioritySize() { return getNewSizeOf(Severity.WARNING_NORMAL); } /** - * Returns the number of new low severity issues in this analysis run. + * Returns the number of new low-severity issues in this analysis run. * - * @return number of new low severity of issues + * @return number of new low-severity issues */ public int getNewLowPrioritySize() { return getNewSizeOf(Severity.WARNING_LOW); @@ -693,45 +694,6 @@ public int getDeltaSize() { return totals.getDeltaSize(); } - /** - * Old serialization item. - * - * @deprecated Replaced by {@link AnalysisResult#totals}. - */ - @Deprecated @SuppressFBWarnings("SS_SHOULD_BE_STATIC") - private final transient int size = 0; - /** - * Old serialization item. - * - * @deprecated Replaced by {@link AnalysisResult#totals}. - */ - @Deprecated @SuppressFBWarnings("SS_SHOULD_BE_STATIC") - private final transient int newSize = 0; - /** - * Old serialization item. - * - * @deprecated Replaced by {@link AnalysisResult#totals}. - */ - @Deprecated - @SuppressWarnings("DeprecatedIsStillUsed") - private transient int fixedSize; - /** - * Old serialization item. - * - * @deprecated Replaced by {@link AnalysisResult#totals}. - */ - @Deprecated - @SuppressWarnings({"DeprecatedIsStillUsed", "MismatchedQueryAndUpdateOfCollection"}) - private final Map sizePerSeverity = new HashMap<>(); - /** - * Old serialization item. - * - * @deprecated Replaced by {@link AnalysisResult#totals}. - */ - @Deprecated - @SuppressWarnings({"DeprecatedIsStillUsed", "MismatchedQueryAndUpdateOfCollection"}) - private final Map newSizePerSeverity = new HashMap<>(); - public Build getBuild() { return new JenkinsBuild(getOwner()); } diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/IssuesDetail.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/IssuesDetail.java index 68b706ff04..a2814b2c67 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/IssuesDetail.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/IssuesDetail.java @@ -319,21 +319,6 @@ public String getTrendModel() { return JACKSON_FACADE.toJson(new NewVersusFixedPieChart().create(newIssues, outstandingIssues, fixedIssues)); } - /** - * Returns the UI model for an ECharts line chart that shows the issues stacked by severity. - * - * @param isBuildOnXAxis - * determines whether the Jenkins build number should be used on the X-axis or the date - * - * @return the UI model as JSON - * @deprecated replaced by {@link #getBuildTrend(String)} - */ - @Deprecated - @SuppressWarnings("unused") - public String getBuildTrend(final boolean isBuildOnXAxis) { - return createTrendAsJson(new SeverityTrendChart(), DEFAULT_CONFIGURATION); - } - /** * Returns the UI model for an ECharts line chart that shows the issues stacked by severity. * @@ -348,21 +333,6 @@ public String getBuildTrend(final String configuration) { return createTrendAsJson(new SeverityTrendChart(), configuration); } - /** - * Returns the UI model for an ECharts line chart that shows the issues by tool. - * - * @param isBuildOnXAxis - * determines whether the Jenkins build number should be used on the X-axis or the date - * - * @return the UI model as JSON - * @deprecated replaced by {@link #getToolsTrend(String)} - */ - @Deprecated - @SuppressWarnings("unused") - public String getToolsTrend(final boolean isBuildOnXAxis) { - return createTrendAsJson(new ToolsTrendChart(), DEFAULT_CONFIGURATION); - } - /** * Returns the UI model for an ECharts line chart that shows the issues by tool. * @@ -377,21 +347,6 @@ public String getToolsTrend(final String configuration) { return createTrendAsJson(new ToolsTrendChart(), configuration); } - /** - * Returns the UI model for an ECharts line chart that shows the new and fixed issues. - * - * @param isBuildOnXAxis - * determines whether the Jenkins build number should be used on the X-axis or the date - * - * @return the UI model as JSON - * @deprecated replaced by {@link #getNewVersusFixedTrend(String)} - */ - @Deprecated - @SuppressWarnings("unused") - public String getNewVersusFixedTrend(final boolean isBuildOnXAxis) { - return createTrendAsJson(new NewVersusFixedTrendChart(), DEFAULT_CONFIGURATION); - } - /** * Returns the UI model for an ECharts line chart that shows the new and fixed issues. * @@ -406,21 +361,6 @@ public String getNewVersusFixedTrend(final String configuration) { return createTrendAsJson(new NewVersusFixedTrendChart(), configuration); } - /** - * Returns the UI model for an ECharts line chart that shows the issues by tool. - * - * @param isBuildOnXAxis - * determines whether the Jenkins build number should be used on the X-axis or the date - * - * @return the UI model as JSON - * @deprecated replaced by {@link #getHealthTrend(String)} - */ - @Deprecated - @SuppressWarnings("unused") - public String getHealthTrend(final boolean isBuildOnXAxis) { - return createTrendAsJson(new HealthTrendChart(healthDescriptor), DEFAULT_CONFIGURATION); - } - /** * Returns the UI model for an ECharts line chart that shows the issues by tool. * @@ -466,7 +406,7 @@ public Report getIssues() { } /** - * Returns all new issues of the associated static analysis run. I.e. all issues, that are part of the current + * Returns all new issues of the associated static analysis run. I.e., all issues that are part of the current * report but have not been shown up in the previous report. * * @return all new issues @@ -477,7 +417,7 @@ public Report getNewIssues() { } /** - * Returns all fixed issues of the associated static analysis run. I.e. all issues, that are part of the previous + * Returns all fixed issues of the associated static analysis run. I.e., all issues that are part of the previous * report but are not present in the current report anymore. * * @return all fixed issues @@ -488,7 +428,7 @@ public Report getFixedIssues() { } /** - * Returns all outstanding issues of the associated static analysis run. I.e. all issues, that are part of the + * Returns all outstanding issues of the associated static analysis run. I.e., all issues that are part of the * current and previous report. * * @return all outstanding issues diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/JobAction.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/JobAction.java index 4439075a24..0c1e54feb2 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/JobAction.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/JobAction.java @@ -37,21 +37,6 @@ public class JobAction implements Action, AsyncConfigurableTrendChart { private final int numberOfTools; private final TrendChartType trendChartType; - /** - * Creates a new instance of {@link JobAction}. - * - * @param owner - * the job that owns this action - * @param labelProvider - * the label provider - * - * @deprecated use {@link #JobAction(Job, StaticAnalysisLabelProvider, int)} - */ - @Deprecated - public JobAction(final Job owner, final StaticAnalysisLabelProvider labelProvider) { - this(owner, labelProvider, 1); - } - /** * Creates a new instance of {@link JobAction}. * @@ -181,17 +166,6 @@ public Optional getLatestAction() { return createBuildHistory().getBaselineAction(); } - /** - * Returns the trend chart model that renders the aggregated build results. - * - * @return the trend chart - * @deprecated replaced {@link #getConfigurableBuildTrendModel(String)} - */ - @Deprecated - public String getBuildTrendModel() { - return getConfigurableBuildTrendModel("{}"); - } - /** * Returns the trend chart model that renders the build results for a specific action. * diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/PropertyStatistics.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/PropertyStatistics.java index 7669696a42..2181260f92 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/PropertyStatistics.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/PropertyStatistics.java @@ -35,7 +35,7 @@ public class PropertyStatistics { * @param property * the property to show the details for * @param propertyFormatter - * the formatter that show the property + * the formatter that shows the property */ PropertyStatistics(final Report report, final Report newIssues, final String property, final Function propertyFormatter) { @@ -57,9 +57,9 @@ public int getTotal() { } /** - * Returns the amount of issues introduced since the last build. + * Returns the number of issues introduced since the last build. * - * @return the amount of new issues + * @return the number of new issues */ public int getTotalNewIssues() { return totalNewIssues; @@ -151,7 +151,7 @@ public long getNewCount(final String key) { * @param key * the property instance * - * @return the number of high severity issues + * @return the number of high-severity issues */ public long getErrorsCount(final String key) { return getReportFor(key).getSizeOf(Severity.ERROR); @@ -163,7 +163,7 @@ public long getErrorsCount(final String key) { * @param key * the property instance * - * @return the number of high severity issues + * @return the number of high-severity issues */ public long getHighCount(final String key) { return getReportFor(key).getSizeOf(Severity.WARNING_HIGH); @@ -175,7 +175,7 @@ public long getHighCount(final String key) { * @param key * the property instance * - * @return the number of normal severity issues + * @return the number of normal-severity issues */ public long getNormalCount(final String key) { return getReportFor(key).getSizeOf(Severity.WARNING_NORMAL); @@ -187,7 +187,7 @@ public long getNormalCount(final String key) { * @param key * the property instance * - * @return the number of low severity issues + * @return the number of low-severity issues */ public long getLowCount(final String key) { return getReportFor(key).getSizeOf(Severity.WARNING_LOW); diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/ReportLocations.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/ReportLocations.java index 8ed574973d..8a3cda57df 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/ReportLocations.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/ReportLocations.java @@ -22,20 +22,4 @@ public FileLocations toFileLocations(final Report report) { report.stream().forEach(i -> fileLocations.addLine(i.getFileName(), i.getLineStart())); return fileLocations; } - - /** - * Returns the affected file locations in the report. - * - * @param report - * the report to get the affected files from - * @param workspace - * the workspace to get the SCM repository from - * - * @return the affected file locations - * @deprecated use {@link #toFileLocations(Report)} - */ - @Deprecated - public FileLocations toFileLocations(final Report report, @SuppressWarnings("unused") final String workspace) { - return toFileLocations(report); - } } diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/ResetQualityGateCommand.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/ResetQualityGateCommand.java index 3c4c44221a..338f3d4b00 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/ResetQualityGateCommand.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/ResetQualityGateCommand.java @@ -2,14 +2,12 @@ import java.io.IOException; import java.util.List; -import java.util.Optional; import edu.hm.hafner.util.VisibleForTesting; import hudson.model.Item; import hudson.model.Run; -import io.jenkins.plugins.analysis.core.util.QualityGateStatus; import io.jenkins.plugins.util.JenkinsFacade; /** @@ -93,15 +91,11 @@ public boolean isEnabled(final Run selectedBuild, final String id) { return false; } - Optional resultAction = selectedBuild.getActions(ResultAction.class) + return selectedBuild.getActions(ResultAction.class) .stream() .filter(action -> action.getId().equals(id)) - .findAny(); - if (resultAction.isEmpty()) { - return false; - } - - QualityGateStatus status = resultAction.get().getResult().getQualityGateStatus(); - return status == QualityGateStatus.FAILED || status == QualityGateStatus.WARNING; + .findAny() + .filter(action -> !action.getResult().getQualityGateResult().isSuccessful()) + .isPresent(); } } diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/ResetReferenceAction.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/ResetReferenceAction.java index 3731d0def9..75e3703ae0 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/ResetReferenceAction.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/ResetReferenceAction.java @@ -4,15 +4,11 @@ import hudson.model.Action; -import io.jenkins.plugins.analysis.core.util.QualityGateEvaluator; - /** - * Marker for a build to indicate that this build should serve as new reference build for the {@link - * QualityGateEvaluator} evaluation of the next build. This marker helps to reset the reference build computation in - * order to restart the new issue computation. + * Marker for a build to indicate that this build should serve as a new reference build for the quality gate evaluation + * of the next build. This marker helps to reset the reference build computation to restart the new issue computation. * * @author Ullrich Hafner - * @see QualityGateEvaluator */ public class ResetReferenceAction implements Action { private final String id; diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/ResultAction.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/ResultAction.java index 435b96403d..bcf4546c79 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/ResultAction.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/ResultAction.java @@ -22,9 +22,9 @@ import jenkins.tasks.SimpleBuildStep.LastBuildAction; import io.jenkins.plugins.analysis.core.util.HealthDescriptor; -import io.jenkins.plugins.analysis.core.util.QualityGateEvaluator; import io.jenkins.plugins.analysis.core.util.TrendChartType; import io.jenkins.plugins.util.JenkinsFacade; +import io.jenkins.plugins.util.QualityGateResult; /** * Controls the life cycle of the analysis results in a job. This action persists the results of a build and displays a @@ -120,6 +120,11 @@ public String getId() { return id; } + @Whitelisted + public QualityGateResult getQualityGateResult() { + return getResult().getQualityGateResult(); + } + /** * Returns the name of the static analysis tool. * @@ -288,12 +293,10 @@ public SummaryModel getSummaryModel() { } /** - * Returns whether the static analysis result is considered successfully with respect to the used {@link - * QualityGateEvaluator}. + * Returns whether the static analysis result is considered successfully with respect to the evaluated quality gates. * * @return {@code true} if the result is successful, {@code false} if the result has been set to {@link * Result#UNSTABLE} or {@link Result#FAILURE}. - * @see QualityGateEvaluator */ @Whitelisted public boolean isSuccessful() { diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/SourceDirectory.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/SourceDirectory.java deleted file mode 100644 index fab68b386a..0000000000 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/SourceDirectory.java +++ /dev/null @@ -1,55 +0,0 @@ -package io.jenkins.plugins.analysis.core.model; - -import java.io.Serializable; - -import org.apache.commons.lang3.StringUtils; - -import edu.umd.cs.findbugs.annotations.NonNull; - -import org.kohsuke.stapler.DataBoundConstructor; -import hudson.Extension; -import hudson.model.AbstractDescribableImpl; -import hudson.model.Descriptor; - -/** - * Directory that contains the source files that have issues. - * - * @author Ullrich Hafner - */ -public class SourceDirectory extends AbstractDescribableImpl implements Serializable { - private static final long serialVersionUID = -3864564528382064924L; - - private final String path; - - /** - * Creates a new instance of {@link SourceDirectory}. - * - * @param path - * the name of the folder - */ - @DataBoundConstructor - public SourceDirectory(final String path) { - super(); - - this.path = path; - } - - public String getPath() { - return path; - } - - /** - * Descriptor to validate {@link SourceDirectory}. - * - * @author Ullrich Hafner - */ - @Extension - public static class DescriptorImpl extends Descriptor { - @NonNull - @Override - public String getDisplayName() { - return StringUtils.EMPTY; - } - } -} - diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/StaticAnalysisLabelProvider.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/StaticAnalysisLabelProvider.java index 1438a87786..df4a13e373 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/StaticAnalysisLabelProvider.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/StaticAnalysisLabelProvider.java @@ -11,14 +11,9 @@ import edu.hm.hafner.util.VisibleForTesting; import edu.umd.cs.findbugs.annotations.CheckForNull; -import j2html.tags.ContainerTag; -import j2html.tags.DomContent; - import org.jvnet.localizer.Localizable; import hudson.model.Run; -import io.jenkins.plugins.analysis.core.util.QualityGateStatus; - import static j2html.TagCreator.*; /** @@ -181,17 +176,6 @@ public String toString() { * @return the name of the side panel link */ public String getLinkName() { - return getRawLinkName(); - } - - /** - * Returns the name of the link to the results. - * - * @return the name of the side panel link - * @deprecated use {@link #getLinkName()} - */ - @Deprecated @Generated - public String getRawLinkName() { if (StringUtils.isNotBlank(name)) { return Messages.Tool_Link_Name(name); } @@ -225,114 +209,6 @@ public String getLargeIconUrl() { return ANALYSIS_SVG_ICON; } - /** - * Returns the title for the small information box in the corresponding build page. - * - * @param result - * the result - * @param hasErrors - * indicates if an error has been reported - * - * @return the title div - * @deprecated rendering of the summary is now done on the client side with the new model {@link SummaryModel} - */ - @Deprecated - public ContainerTag getTitle(final AnalysisResult result, final boolean hasErrors) { - return emptyElementForDeprecatedMethod(); - } - - /** - * Returns the HTML label for the link to the new issues of the build. - * - * @param newSize - * the number of new issues - * - * @return the legend of the trend chart - * @deprecated rendering of the summary is now done on the client side with the new model {@link SummaryModel} - */ - @Deprecated - public ContainerTag getNewIssuesLabel(final int newSize) { - return emptyElementForDeprecatedMethod(); - } - - /** - * Returns the HTML label for the link to the fixed issues of the build. - * - * @param fixedSize - * the number of fixed issues - * - * @return the legend of the trend chart - * @deprecated rendering of the summary is now done on the client side with the new model {@link SummaryModel} - */ - @Deprecated - public ContainerTag getFixedIssuesLabel(final int fixedSize) { - return emptyElementForDeprecatedMethod(); - } - - /** - * Returns the HTML text showing the number of builds since the project has no issues. - * - * @param currentBuild - * the current build number - * @param noIssuesSinceBuild - * the build since there are no issues - * - * @return the legend of the trend chart - * @deprecated rendering of the summary is now done on the client side with the new model {@link SummaryModel} - */ - @Deprecated - public DomContent getNoIssuesSinceLabel(final int currentBuild, final int noIssuesSinceBuild) { - return emptyElementForDeprecatedMethod(); - } - - private ContainerTag emptyElementForDeprecatedMethod() { - return div(); - } - - /** - * Returns the HTML text showing the result of the quality gate. - * - * @param qualityGateStatus - * the status of the quality gate - * - * @return the legend of the trend chart - * @deprecated rendering of the summary is now done on the client side with the new model {@link SummaryModel} - */ - @Deprecated - public DomContent getQualityGateResult(final QualityGateStatus qualityGateStatus) { - return emptyElementForDeprecatedMethod(); - } - - /** - * Returns the HTML text showing the result of the quality gate. - * - * @param qualityGateStatus - * the status of the quality gate - * @param hasResetLink - * determines whether the reset reference link is shown - * - * @return the legend of the trend chart - * @deprecated rendering of the summary is now done on the client side with the new model {@link SummaryModel} - */ - @Deprecated - public DomContent getQualityGateResult(final QualityGateStatus qualityGateStatus, final boolean hasResetLink) { - return emptyElementForDeprecatedMethod(); - } - - /** - * Returns the HTML text showing a link to the reference build. - * - * @param referenceBuild - * the reference build - * - * @return the legend of the trend chart - * @deprecated rendering of the summary is now done on the client side with the new model {@link SummaryModel} - */ - @Deprecated - public DomContent getReferenceBuild(final Run referenceBuild) { - return emptyElementForDeprecatedMethod(); - } - /** * Returns a short description describing the total number of issues. * diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/SummaryModel.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/SummaryModel.java index b4b6d67e46..74de08d591 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/SummaryModel.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/SummaryModel.java @@ -10,7 +10,7 @@ import hudson.model.Run; -import io.jenkins.plugins.analysis.core.util.QualityGateStatus; +import io.jenkins.plugins.util.QualityGateStatus; /** * Summary message of a static analysis run. This message is shown as part of the 'summary.jelly' information of the @@ -132,7 +132,7 @@ public int totalSize(final String origin) { } public QualityGateStatus getQualityGateStatus() { - return analysisResult.getQualityGateStatus(); + return analysisResult.getQualityGateResult().getOverallStatus(); } public boolean isResetQualityGateVisible() { diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/WarningsPluginConfiguration.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/WarningsPluginConfiguration.java deleted file mode 100644 index eab56fa970..0000000000 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/model/WarningsPluginConfiguration.java +++ /dev/null @@ -1,118 +0,0 @@ -package io.jenkins.plugins.analysis.core.model; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import org.apache.commons.lang3.StringUtils; - -import edu.hm.hafner.util.PathUtil; -import edu.hm.hafner.util.VisibleForTesting; - -import org.kohsuke.stapler.DataBoundSetter; -import org.jenkinsci.Symbol; -import hudson.Extension; -import hudson.FilePath; -import jenkins.model.GlobalConfiguration; - -import io.jenkins.plugins.util.GlobalConfigurationFacade; -import io.jenkins.plugins.util.GlobalConfigurationItem; - -/** - * Global system configuration of the warnings plugin. These configuration options are used globally for all jobs and - * require administrator permissions. - * - * @author Ullrich Hafner - */ -@Extension -@Symbol("warningsPlugin") -public class WarningsPluginConfiguration extends GlobalConfigurationItem { - private static final PathUtil PATH_UTIL = new PathUtil(); - private List sourceDirectories = Collections.emptyList(); - private Set normalizedSourceDirectories = Collections.emptySet(); - - /** - * Creates the global configuration for the warnings plugins. - */ - public WarningsPluginConfiguration() { - super(); - - load(); - } - - @VisibleForTesting - WarningsPluginConfiguration(final GlobalConfigurationFacade facade) { - super(facade); - - load(); - } - - @Override - protected void clearRepeatableProperties() { - setSourceDirectories(new ArrayList<>()); - } - - /** - * Returns the singleton instance of this {@link WarningsPluginConfiguration}. - * - * @return the singleton instance - */ - public static WarningsPluginConfiguration getInstance() { - return GlobalConfiguration.all().get(WarningsPluginConfiguration.class); - } - - /** - * Returns the list of source directories that contain the affected files.. - * - * @return the source root folders - */ - public List getSourceDirectories() { - return sourceDirectories; - } - - /** - * Sets the list of source directories to the specified elements. Previously set directories will be removed. - * - * @param sourceDirectories - * the source directories that contain the affected files - */ - @DataBoundSetter - public void setSourceDirectories(final List sourceDirectories) { - this.sourceDirectories = new ArrayList<>(sourceDirectories); - - normalizedSourceDirectories = sourceDirectories.stream() - .map(SourceDirectory::getPath) - .map(PATH_UTIL::getAbsolutePath) - .collect(Collectors.toSet()); - - save(); - } - - /** - * Filters the specified collection of additional directories so that only permitted source directories will be - * returned. Permitted source directories are absolute paths that have been registered using {@link - * #setSourceDirectories(List)} or relative paths in the workspace. - * - * @param workspace - * the workspace containing the affected files - * @param sourceDirectory - * additional source directly (might be empty): a relative path in the workspace or an absolute path - * - * @return the permitted source directory - or as a fallback the the workspace path - */ - public FilePath getPermittedSourceDirectory(final FilePath workspace, final String sourceDirectory) { - PathUtil pathUtil = new PathUtil(); - String normalized = pathUtil.getAbsolutePath(sourceDirectory); - if (pathUtil.isAbsolute(normalized)) { - if (normalizedSourceDirectories.contains(normalized)) { // skip not registered absolute paths - return workspace.child(normalized); - } - } - else if (StringUtils.isNotBlank(sourceDirectory) && !"-".equals(sourceDirectory)) { - return workspace.child(normalized); - } - return workspace; - } -} diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/portlets/IssuesChartPortlet.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/portlets/IssuesChartPortlet.java index ab6007b59e..83a1ded346 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/portlets/IssuesChartPortlet.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/portlets/IssuesChartPortlet.java @@ -139,17 +139,6 @@ public String getBuildTrendModel() { severityChart.aggregate(histories, new ChartModelConfiguration(AxisType.DATE))); } - /** - * Returns the UI model for an ECharts line chart that shows the issues stacked by severity. - * - * @return the UI model as JSON - * @deprecated replaced by {@link #getBuildTrendModel()} which is called from JS file - */ - @JavaScriptMethod @Deprecated @SuppressWarnings("unused") // Called by jelly view - public String getTrend() { - return getBuildTrendModel(); - } - /** * Registers the specified jobs in this portlet. These jobs will be used to render the trend chart. Note that * rendering of the trend chart is done using an Ajax call later on. diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/portlets/PullRequestMonitoringPortlet.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/portlets/PullRequestMonitoringPortlet.java index 856cea2e8b..6e16f0ee06 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/portlets/PullRequestMonitoringPortlet.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/portlets/PullRequestMonitoringPortlet.java @@ -20,9 +20,9 @@ import io.jenkins.plugins.analysis.core.model.AnalysisResult; import io.jenkins.plugins.analysis.core.model.ResultAction; -import io.jenkins.plugins.analysis.core.util.QualityGateStatus; import io.jenkins.plugins.monitoring.MonitorPortlet; import io.jenkins.plugins.monitoring.MonitorPortletFactory; +import io.jenkins.plugins.util.QualityGateStatus; /** * A portlet that can be used for the @@ -154,18 +154,6 @@ public boolean hasQualityGate() { return !result.getQualityGateStatus().equals(QualityGateStatus.INACTIVE); } - /** - * Get the icon of the quality gate. - * - * @return - * the image url of the icon. - * @deprecated replaced by {@link #getQualityGateResultClass()} - */ - @Deprecated - public String getQualityGateResultIconUrl() { - return result.getQualityGateStatus().getResult().color.getImageOf("16x16"); - } - /** * Get the icon class of the quality gate. * diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/restapi/AnalysisResultApi.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/restapi/AnalysisResultApi.java index 75768b6ace..89442c768b 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/restapi/AnalysisResultApi.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/restapi/AnalysisResultApi.java @@ -8,8 +8,8 @@ import org.kohsuke.stapler.export.ExportedBean; import hudson.model.Run; -import io.jenkins.plugins.analysis.core.util.QualityGateStatus; import io.jenkins.plugins.analysis.core.util.StaticAnalysisRun; +import io.jenkins.plugins.util.QualityGateResult.QualityGateResultApi; /** * Remote API for the {@link StaticAnalysisRun}. Simple Java Bean that exposes several methods of an {@link @@ -56,9 +56,9 @@ public int getSuccessfulSinceBuild() { return result.getSuccessfulSinceBuild(); } - @Exported - public QualityGateStatus getQualityGateStatus() { - return result.getQualityGateStatus(); + @Exported(inline = true) + public QualityGateResultApi getQualityGates() { + return new QualityGateResultApi(result.getQualityGateResult()); } @Exported diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/restapi/ToolApi.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/restapi/ToolApi.java index f0d833d277..8b99813cdf 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/restapi/ToolApi.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/restapi/ToolApi.java @@ -1,6 +1,5 @@ package io.jenkins.plugins.analysis.core.restapi; -import java.util.Collections; import java.util.Map; import edu.hm.hafner.analysis.Severity; @@ -23,25 +22,6 @@ public class ToolApi { private final int size; private final Map sizePerSeverity; - /** - * Creates a new instance of {@link ToolApi}. - * - * @param id - * unique ID of the tool - * @param name - * human-readable name of the tool - * @param latestUrl - * the URL to the latest results - * @param size - * the number of warnings - * @deprecated - * use {@link #ToolApi(String, String, String, int, Map)} instead. - */ - @Deprecated - public ToolApi(final String id, final String name, final String latestUrl, final int size) { - this(name, id, latestUrl, size, Collections.emptyMap()); - } - /** * Creates a new instance of {@link ToolApi}. * @@ -103,5 +83,4 @@ public int getNormalSize() { public int getLowSize() { return sizePerSeverity.getOrDefault(Severity.WARNING_LOW, 0); } - } diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/AnalysisStepDescriptor.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/AnalysisStepDescriptor.java index bc8bda4f9e..c1ee37322e 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/AnalysisStepDescriptor.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/AnalysisStepDescriptor.java @@ -16,6 +16,7 @@ import jenkins.model.Jenkins; import io.jenkins.plugins.analysis.core.util.ModelValidation; +import io.jenkins.plugins.prism.SourceCodeRetention; import io.jenkins.plugins.util.JenkinsFacade; import io.jenkins.plugins.util.ValidationUtilities; @@ -86,34 +87,30 @@ public FormValidation doCheckSourceCodeEncoding(@AncestorInPath final BuildableI } /** - * Returns a model with all available severity filters. + * Returns a model with all {@link SourceCodeRetention} strategies. * - * @return a model with all available severity filters + * @return a model with all {@link SourceCodeRetention} strategies. */ @POST - public ListBoxModel doFillMinimumSeverityItems() { + @SuppressWarnings("unused") // used by Stapler view data binding + public ListBoxModel doFillSourceCodeRetentionItems() { if (JENKINS.hasPermission(Jenkins.READ)) { - return model.getAllSeverityFilters(); + return SourceCodeRetention.fillItems(); } return new ListBoxModel(); - } /** - * Returns the model with the possible reference jobs. + * Returns a model with all available severity filters. * - * @param project - * the project that is configured - * @return the model with the possible reference jobs - * @deprecated not used anymore, part of forensics plugin + * @return a model with all available severity filters */ - @Deprecated @POST - public ComboBoxModel doFillReferenceJobNameItems(@AncestorInPath final BuildableItem project) { - if (JENKINS.hasPermission(Item.CONFIGURE, project)) { - return model.getAllJobs(); + public ListBoxModel doFillMinimumSeverityItems() { + if (JENKINS.hasPermission(Jenkins.READ)) { + return model.getAllSeverityFilters(); } - return new ComboBoxModel(); + return new ListBoxModel(); } /** diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/IssuesPublisher.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/IssuesPublisher.java index 171c8d8861..3c64b25361 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/IssuesPublisher.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/IssuesPublisher.java @@ -24,13 +24,14 @@ import io.jenkins.plugins.analysis.core.model.ResultAction; import io.jenkins.plugins.analysis.core.model.ResultSelector; import io.jenkins.plugins.analysis.core.util.HealthDescriptor; -import io.jenkins.plugins.analysis.core.util.QualityGateEvaluator; -import io.jenkins.plugins.analysis.core.util.QualityGateStatus; import io.jenkins.plugins.analysis.core.util.TrendChartType; +import io.jenkins.plugins.analysis.core.util.WarningsQualityGate; +import io.jenkins.plugins.analysis.core.util.WarningsQualityGateEvaluator; import io.jenkins.plugins.forensics.reference.ReferenceFinder; import io.jenkins.plugins.util.JenkinsFacade; import io.jenkins.plugins.util.LogHandler; -import io.jenkins.plugins.util.StageResultHandler; +import io.jenkins.plugins.util.QualityGateResult; +import io.jenkins.plugins.util.ResultHandler; import static io.jenkins.plugins.analysis.core.model.AnalysisHistory.JobResultEvaluationMode.*; import static io.jenkins.plugins.analysis.core.model.AnalysisHistory.QualityGateEvaluationMode.*; @@ -48,35 +49,34 @@ class IssuesPublisher { private final HealthDescriptor healthDescriptor; private final String name; private final Charset sourceCodeEncoding; - private final QualityGateEvaluator qualityGate; + private final List qualityGates; private final String referenceJobName; private final String referenceBuildId; private final QualityGateEvaluationMode qualityGateEvaluationMode; private final JobResultEvaluationMode jobResultEvaluationMode; private final LogHandler logger; - private final StageResultHandler stageResultHandler; + private final ResultHandler notifier; private final boolean failOnErrors; @SuppressWarnings("ParameterNumber") IssuesPublisher(final Run run, final AnnotatedReport report, - final HealthDescriptor healthDescriptor, final QualityGateEvaluator qualityGate, + final HealthDescriptor healthDescriptor, final List qualityGates, final String name, final String referenceJobName, final String referenceBuildId, final boolean ignoreQualityGate, final boolean ignoreFailedBuilds, final Charset sourceCodeEncoding, final LogHandler logger, - final StageResultHandler stageResultHandler, final boolean failOnErrors) { - + final ResultHandler notifier, final boolean failOnErrors) { this.report = report; this.run = run; this.healthDescriptor = healthDescriptor; this.name = name; this.sourceCodeEncoding = sourceCodeEncoding; - this.qualityGate = qualityGate; + this.qualityGates = qualityGates; this.referenceJobName = referenceJobName; this.referenceBuildId = referenceBuildId; qualityGateEvaluationMode = ignoreQualityGate ? IGNORE_QUALITY_GATE : SUCCESSFUL_QUALITY_GATE; jobResultEvaluationMode = ignoreFailedBuilds ? NO_JOB_FAILURE : IGNORE_JOB_RESULT; this.logger = logger; - this.stageResultHandler = stageResultHandler; + this.notifier = notifier; this.failOnErrors = failOnErrors; } @@ -98,7 +98,7 @@ ResultAction attachAction(final TrendChartType trendChartType) { Report issues = report.getReport(); DeltaReport deltaReport = new DeltaReport(issues, createAnalysisHistory(selector, issues), run.getNumber()); - QualityGateStatus qualityGateStatus = evaluateQualityGate(issues, deltaReport); + QualityGateResult qualityGateResult = evaluateQualityGate(issues, deltaReport); reportHealth(issues); issues.logInfo("Created analysis result for %d issues (found %d new issues, fixed %d issues)", @@ -107,8 +107,7 @@ ResultAction attachAction(final TrendChartType trendChartType) { if (failOnErrors && issues.hasErrors()) { issues.logInfo("Failing build because analysis result contains errors"); - stageResultHandler.setResult(Result.FAILURE, - "Some errors have been logged during recording of issues"); + run.setResult(Result.FAILURE); } if (trendChartType == TrendChartType.AGGREGATION_TOOLS) { @@ -124,10 +123,10 @@ ResultAction attachAction(final TrendChartType trendChartType) { AnalysisResult result = new AnalysisHistory(run, selector).getResult() .map(previous -> new AnalysisResult(run, getId(), deltaReport, report.getBlames(), - report.getStatistics(), qualityGateStatus, report.getSizeOfOrigin(), + report.getStatistics(), qualityGateResult, report.getSizeOfOrigin(), previous)) .orElseGet(() -> new AnalysisResult(run, getId(), deltaReport, report.getBlames(), - report.getStatistics(), qualityGateStatus, report.getSizeOfOrigin())); + report.getStatistics(), qualityGateResult, report.getSizeOfOrigin())); ResultAction action = new ResultAction(run, result, healthDescriptor, getId(), name, sourceCodeEncoding, trendChartType); run.addAction(action); @@ -163,26 +162,11 @@ private void reportHealth(final Report filtered) { } } - private QualityGateStatus evaluateQualityGate(final Report issues, final DeltaReport deltaReport) { - QualityGateStatus qualityGateStatus; - if (qualityGate.isEnabled()) { - issues.logInfo("Evaluating quality gates"); - qualityGateStatus = qualityGate.evaluate(deltaReport.getStatistics(), issues::logInfo); - if (qualityGateStatus.isSuccessful()) { - issues.logInfo("-> All quality gates have been passed"); - } - else { - issues.logInfo("-> Some quality gates have been missed: overall result is %s", qualityGateStatus); - } - if (!qualityGateStatus.isSuccessful()) { - stageResultHandler.setResult(qualityGateStatus.getResult(), - "Some quality gates have been missed: overall result is " + qualityGateStatus.getResult()); - } - } - else { - issues.logInfo("No quality gates have been set - skipping"); - qualityGateStatus = QualityGateStatus.INACTIVE; - } + private QualityGateResult evaluateQualityGate(final Report issues, final DeltaReport deltaReport) { + var evaluator = new WarningsQualityGateEvaluator(qualityGates, deltaReport.getStatistics()); + var log = new FilteredLog("Errors while evaluating quality gates:"); + var qualityGateStatus = evaluator.evaluate(notifier, log); + issues.mergeLogMessages(log); return qualityGateStatus; } diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/IssuesRecorder.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/IssuesRecorder.java index 765ce46b5b..a90077115e 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/IssuesRecorder.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/IssuesRecorder.java @@ -55,17 +55,15 @@ import io.jenkins.plugins.analysis.core.steps.WarningChecksPublisher.AnnotationScope; import io.jenkins.plugins.analysis.core.util.HealthDescriptor; import io.jenkins.plugins.analysis.core.util.ModelValidation; -import io.jenkins.plugins.analysis.core.util.QualityGate; -import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateResult; -import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateType; -import io.jenkins.plugins.analysis.core.util.QualityGateEvaluator; import io.jenkins.plugins.analysis.core.util.TrendChartType; +import io.jenkins.plugins.analysis.core.util.WarningsQualityGate; import io.jenkins.plugins.checks.steps.ChecksInfo; import io.jenkins.plugins.prism.SourceCodeDirectory; +import io.jenkins.plugins.prism.SourceCodeRetention; import io.jenkins.plugins.util.JenkinsFacade; import io.jenkins.plugins.util.LogHandler; +import io.jenkins.plugins.util.ResultHandler; import io.jenkins.plugins.util.RunResultHandler; -import io.jenkins.plugins.util.StageResultHandler; import io.jenkins.plugins.util.ValidationUtilities; /** @@ -76,7 +74,7 @@ * Additional features: *

*
    - *
  • It provides a {@link QualityGateEvaluator} that is checked after each run. If the quality gate is not passed, + *
  • It evaluates the quality gates after each run. If the quality gate is not passed, * then the build will be set to {@link Result#UNSTABLE} or {@link Result#FAILURE}, depending on the configuration * properties.
  • *
  • It provides thresholds for the build health that could be adjusted in the configuration screen. @@ -95,8 +93,8 @@ public class IssuesRecorder extends Recorder { private List analysisTools = new ArrayList<>(); private String sourceCodeEncoding = StringUtils.EMPTY; - private String sourceDirectory = StringUtils.EMPTY; private Set sourceDirectories = new HashSet<>(); // @since 9.11.0 + private SourceCodeRetention sourceCodeRetention = SourceCodeRetention.EVERY_BUILD; private boolean ignoreQualityGate = false; // by default, a successful quality gate is mandatory; private boolean ignoreFailedBuilds = true; // by default, failed builds are ignored; @@ -117,14 +115,6 @@ public class IssuesRecorder extends Recorder { private boolean quiet = false; private boolean isBlameDisabled; - /** - * Not used anymore. - * - * @deprecated since 8.5.0 - */ - @Deprecated - private transient boolean isForensicsDisabled; - private boolean skipPublishingChecks; // by default, checks will be published private boolean publishAllIssues; // by default, only new issues will be published @@ -136,7 +126,7 @@ public class IssuesRecorder extends Recorder { private String id; private String name; - private List qualityGates = new ArrayList<>(); + private List qualityGates = new ArrayList<>(); private TrendChartType trendChartType = TrendChartType.AGGREGATION_TOOLS; @@ -159,14 +149,8 @@ public IssuesRecorder() { * @return this */ protected Object readResolve() { - if (sourceDirectory == null) { - sourceDirectory = StringUtils.EMPTY; - } if (sourceDirectories == null) { sourceDirectories = new HashSet<>(); - if (StringUtils.isNotBlank(sourceDirectory)) { - sourceDirectories.add(new SourceCodeDirectory(sourceDirectory)); - } } if (trendChartType == null) { trendChartType = TrendChartType.AGGREGATION_TOOLS; @@ -180,6 +164,9 @@ protected Object readResolve() { if (scm == null) { scm = StringUtils.EMPTY; } + if (sourceCodeRetention == null) { + sourceCodeRetention = SourceCodeRetention.EVERY_BUILD; + } return this; } @@ -207,26 +194,12 @@ public String getScm() { */ @SuppressWarnings("unused") // used by Stapler view data binding @DataBoundSetter - public void setQualityGates(final List qualityGates) { + public void setQualityGates(final List qualityGates) { this.qualityGates = qualityGates; } - /** - * Appends the specified quality gates to the end of the list of quality gates. - * - * @param size - * the minimum number of issues that fails the quality gate - * @param type - * the type of the quality gate - * @param result - * determines whether the quality gate is a warning or failure - */ - public void addQualityGate(final int size, final QualityGateType type, final QualityGateResult result) { - qualityGates.add(new QualityGate(size, type, result)); - } - @SuppressWarnings("unused") // used by Stapler view data binding - public List getQualityGates() { + public List getQualityGates() { return qualityGates; } @@ -352,24 +325,8 @@ public void setSourceCodeEncoding(final String sourceCodeEncoding) { this.sourceCodeEncoding = sourceCodeEncoding; } - public String getSourceDirectory() { - return sourceDirectory; - } - /** - * Sets the path to the directory that contains the source code. If not relative and thus not part of the workspace - * then this directory needs to be added in Jenkins global configuration to prevent accessing of forbidden resources. - * - * @param sourceDirectory - * directory containing the source code - */ - @DataBoundSetter - public void setSourceDirectory(final String sourceDirectory) { - this.sourceDirectory = sourceDirectory; - } - - /** - * Sets the paths to the directories that contain the source code. If not relative and thus not part of the workspace + * Sets the paths to the directories that contain the source code. If not relative and thus not part of the workspace, * then these directories need to be added in Jenkins global configuration to prevent accessing of forbidden resources. * * @param sourceDirectories @@ -384,6 +341,21 @@ public List getSourceDirectories() { return new ArrayList<>(sourceDirectories); } + /** + * Defines the retention strategy for source code files. + * + * @param sourceCodeRetention + * the retention strategy for source code files + */ + @DataBoundSetter + public void setSourceCodeRetention(final SourceCodeRetention sourceCodeRetention) { + this.sourceCodeRetention = sourceCodeRetention; + } + + public SourceCodeRetention getSourceCodeRetention() { + return sourceCodeRetention; + } + /** * Returns whether the results for each configured static analysis result should be aggregated into a single result * or if every tool should get an individual result. @@ -445,32 +417,6 @@ public void setSkipBlames(final boolean skipBlames) { isBlameDisabled = skipBlames; } - /** - * Not used anymore. - * - * @return {@code true} if SCM forensics should be disabled - * @deprecated Forensics will be automatically skipped if the Forensics recorder is not activated. - */ - @SuppressWarnings("PMD.BooleanGetMethodName") - @Deprecated - public boolean getForensicsDisabled() { - return isForensicsDisabled; - } - - /** - * Not used anymore. - * - * @param forensicsDisabled - * not used - * - * @deprecated Forensics will be automatically skipped if the Forensics recorder is not activated. - */ - @DataBoundSetter - @Deprecated - public void setForensicsDisabled(final boolean forensicsDisabled) { - isForensicsDisabled = forensicsDisabled; - } - /** * Returns whether publishing checks should be skipped. * @@ -738,26 +684,11 @@ public boolean perform(final AbstractBuild build, final Launcher launcher, return true; } - /** - * Executes the build step. Used from {@link RecordIssuesStep} to provide a {@link StageResultHandler} that has - * Pipeline-specific behavior. - * - * @param run - * the run of the pipeline or freestyle job - * @param workspace - * workspace of the build - * @param listener - * the logger - * @param statusHandler - * reports the status for the build or for the stage - * - * @return the created results - */ List perform(final Run run, final FilePath workspace, final TaskListener listener, - final StageResultHandler statusHandler) throws InterruptedException, IOException { + final ResultHandler resultHandler) throws InterruptedException, IOException { Result overallResult = run.getResult(); if (isEnabledForFailure || overallResult == null || overallResult.isBetterOrEqualTo(Result.UNSTABLE)) { - return record(run, workspace, listener, statusHandler); + return record(run, workspace, listener, resultHandler); } else { LogHandler logHandler = new LogHandler(listener, createLoggerPrefix()); @@ -772,7 +703,7 @@ private String createLoggerPrefix() { } private List record(final Run run, final FilePath workspace, final TaskListener listener, - final StageResultHandler statusHandler) throws IOException, InterruptedException { + final ResultHandler resultHandler) throws IOException, InterruptedException { List results = new ArrayList<>(); if (isAggregatingResults && analysisTools.size() > 1) { AnnotatedReport totalIssues = new AnnotatedReport(StringUtils.defaultIfEmpty(id, DEFAULT_ID)); @@ -780,7 +711,7 @@ private List record(final Run run, final FilePath workspac totalIssues.add(scanWithTool(run, workspace, listener, tool), tool.getActualId()); } String toolName = StringUtils.defaultIfEmpty(getName(), Messages.Tool_Default_Name()); - results.add(publishResult(run, listener, toolName, totalIssues, toolName, statusHandler)); + results.add(publishResult(run, listener, toolName, totalIssues, toolName, resultHandler)); } else { for (Tool tool : analysisTools) { @@ -795,7 +726,7 @@ private List record(final Run run, final FilePath workspac name, id); } results.add( - publishResult(run, listener, tool.getActualName(), report, getReportName(tool), statusHandler)); + publishResult(run, listener, tool.getActualName(), report, getReportName(tool), resultHandler)); } } return results; @@ -822,7 +753,8 @@ private String getReportName(final Tool tool) { private AnnotatedReport scanWithTool(final Run run, final FilePath workspace, final TaskListener listener, final Tool tool) throws IOException, InterruptedException { IssuesScanner issuesScanner = new IssuesScanner(tool, getFilters(), getSourceCodeCharset(), - workspace, getSourceCodePaths(), run, new FilePath(run.getRootDir()), listener, + workspace, getSourceCodePaths(), getSourceCodeRetention(), + run, new FilePath(run.getRootDir()), listener, scm, isBlameDisabled ? BlameMode.DISABLED : BlameMode.ENABLED, skipPostProcessing ? PostProcessingMode.DISABLED : PostProcessingMode.ENABLED, quiet); @@ -842,7 +774,7 @@ private Charset getCharset(final String encoding) { } /** - * Publishes the results as {@link Action} in the job using an {@link IssuesPublisher}. Afterwards, all affected + * Publishes the results as {@link Action} in the job using an {@link IssuesPublisher}. Afterward, all affected * files are copied to Jenkins' build folder so that they are available to show warnings in the UI. * * @param run @@ -855,15 +787,13 @@ private Charset getCharset(final String encoding) { * the analysis report to publish * @param reportName * the name of the report (might be empty) - * @param statusHandler + * @param resultHandler * the status handler to use * * @return the created results */ AnalysisResult publishResult(final Run run, final TaskListener listener, final String loggerName, - final AnnotatedReport annotatedReport, final String reportName, final StageResultHandler statusHandler) { - QualityGateEvaluator qualityGate = new QualityGateEvaluator(); - qualityGate.addAll(qualityGates); + final AnnotatedReport annotatedReport, final String reportName, final ResultHandler resultHandler) { LogHandler logHandler = new LogHandler(listener, loggerName); logHandler.setQuiet(quiet); @@ -873,9 +803,9 @@ AnalysisResult publishResult(final Run run, final TaskListener listener, f logHandler.logErrorMessages(report.getErrorMessages()); IssuesPublisher publisher = new IssuesPublisher(run, annotatedReport, - new HealthDescriptor(healthy, unhealthy, minimumSeverity), qualityGate, + new HealthDescriptor(healthy, unhealthy, minimumSeverity), qualityGates, reportName, getReferenceJobName(), getReferenceBuildId(), ignoreQualityGate, ignoreFailedBuilds, - getSourceCodeCharset(), logHandler, statusHandler, failOnError); + getSourceCodeCharset(), logHandler, resultHandler, failOnError); ResultAction action = publisher.attachAction(trendChartType); if (!skipPublishingChecks) { @@ -951,6 +881,20 @@ public ComboBoxModel doFillSourceCodeEncodingItems(@AncestorInPath final Buildab return new ComboBoxModel(); } + /** + * Returns a model with all {@link SourceCodeRetention} strategies. + * + * @return a model with all {@link SourceCodeRetention} strategies. + */ + @POST + @SuppressWarnings("unused") // used by Stapler view data binding + public ListBoxModel doFillSourceCodeRetentionItems() { + if (JENKINS.hasPermission(Jenkins.READ)) { + return SourceCodeRetention.fillItems(); + } + return new ListBoxModel(); + } + /** * Returns a model with all available severity filters. * diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/IssuesScanner.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/IssuesScanner.java index 8f2e6ce8d6..4b0dbd415c 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/IssuesScanner.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/IssuesScanner.java @@ -37,9 +37,7 @@ import io.jenkins.plugins.analysis.core.filter.RegexpFilter; import io.jenkins.plugins.analysis.core.model.ReportLocations; -import io.jenkins.plugins.analysis.core.model.SourceDirectory; import io.jenkins.plugins.analysis.core.model.Tool; -import io.jenkins.plugins.analysis.core.model.WarningsPluginConfiguration; import io.jenkins.plugins.analysis.core.util.AffectedFilesResolver; import io.jenkins.plugins.analysis.core.util.ConsoleLogHandler; import io.jenkins.plugins.analysis.core.util.FileFinder; @@ -52,6 +50,7 @@ import io.jenkins.plugins.forensics.miner.RepositoryStatistics; import io.jenkins.plugins.prism.PermittedSourceCodeDirectory; import io.jenkins.plugins.prism.PrismConfiguration; +import io.jenkins.plugins.prism.SourceCodeRetention; import io.jenkins.plugins.prism.SourceDirectoryFilter; import io.jenkins.plugins.util.LogHandler; @@ -66,6 +65,7 @@ class IssuesScanner { private final FilePath workspace; private final Set sourceDirectories; + private final SourceCodeRetention sourceCodeRetention; private final Run run; private final FilePath jenkinsRootDir; private final Charset sourceCodeEncoding; @@ -87,7 +87,8 @@ enum PostProcessingMode { @SuppressWarnings("checkstyle:ParameterNumber") IssuesScanner(final Tool tool, final List filters, final Charset sourceCodeEncoding, - final FilePath workspace, final Set sourceDirectories, final Run run, + final FilePath workspace, final Set sourceDirectories, + final SourceCodeRetention sourceCodeRetention, final Run run, final FilePath jenkinsRootDir, final TaskListener listener, final String scm, final BlameMode blameMode, final PostProcessingMode postProcessingMode, final boolean quiet) { @@ -96,6 +97,7 @@ enum PostProcessingMode { this.tool = tool; this.workspace = workspace; this.sourceDirectories = sourceDirectories; + this.sourceCodeRetention = sourceCodeRetention; this.run = run; this.jenkinsRootDir = jenkinsRootDir; this.listener = listener; @@ -151,19 +153,11 @@ private ReportPostProcessor createPostProcessor(final Report report) { } private Set getPermittedSourceDirectories() { - Set permittedSourceDirectories = PrismConfiguration.getInstance() + return PrismConfiguration.getInstance() .getSourceDirectories() .stream() .map(PermittedSourceCodeDirectory::getPath) .collect(Collectors.toSet()); - List permittedSourceCodeDirectoriesOfWarningsPlugin - = WarningsPluginConfiguration.getInstance() - .getSourceDirectories() - .stream() - .map(SourceDirectory::getPath) - .collect(Collectors.toList()); - permittedSourceDirectories.addAll(permittedSourceCodeDirectoriesOfWarningsPlugin); - return permittedSourceDirectories; } private Blamer createBlamer(final Report report) { @@ -187,12 +181,18 @@ private Blamer createBlamer(final Report report) { private void copyAffectedFiles(final Report report, final FilePath buildFolder) throws InterruptedException { - report.logInfo("Copying affected files to Jenkins' build folder '%s'", buildFolder); + var log = new FilteredLog("Errors while processing affected files"); + if (sourceCodeRetention != SourceCodeRetention.NEVER) { + report.logInfo("Copying affected files to Jenkins' build folder '%s'", buildFolder); + + Set permittedSourceDirectories = getPermittedSourceDirectories(); + permittedSourceDirectories.add(workspace.getRemote()); + new AffectedFilesResolver().copyAffectedFilesToBuildFolder( + report, workspace, permittedSourceDirectories, buildFolder); + } + sourceCodeRetention.cleanup(run, AFFECTED_FILES_FOLDER_NAME, log); - Set permittedSourceDirectories = getPermittedSourceDirectories(); - permittedSourceDirectories.add(workspace.getRemote()); - new AffectedFilesResolver().copyAffectedFilesToBuildFolder( - report, workspace, permittedSourceDirectories, buildFolder); + report.mergeLogMessages(log); } private FilePath createAffectedFilesFolder(final Report report) throws InterruptedException { diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/PublishIssuesStep.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/PublishIssuesStep.java index a2697f5dbb..6da1f008b4 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/PublishIssuesStep.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/PublishIssuesStep.java @@ -31,15 +31,12 @@ import io.jenkins.plugins.analysis.core.model.StaticAnalysisLabelProvider; import io.jenkins.plugins.analysis.core.steps.WarningChecksPublisher.AnnotationScope; import io.jenkins.plugins.analysis.core.util.HealthDescriptor; -import io.jenkins.plugins.analysis.core.util.QualityGate; -import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateResult; -import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateType; -import io.jenkins.plugins.analysis.core.util.QualityGateEvaluator; import io.jenkins.plugins.analysis.core.util.TrendChartType; +import io.jenkins.plugins.analysis.core.util.WarningsQualityGate; import io.jenkins.plugins.checks.steps.ChecksInfo; import io.jenkins.plugins.util.LogHandler; import io.jenkins.plugins.util.PipelineResultHandler; -import io.jenkins.plugins.util.StageResultHandler; +import io.jenkins.plugins.util.ResultHandler; import io.jenkins.plugins.util.ValidationUtilities; /** @@ -72,7 +69,7 @@ public class PublishIssuesStep extends Step implements Serializable { private int unhealthy; private Severity minimumSeverity = Severity.WARNING_LOW; - private List qualityGates = new ArrayList<>(); + private List qualityGates = new ArrayList<>(); private TrendChartType trendChartType = TrendChartType.AGGREGATION_TOOLS; @@ -188,7 +185,7 @@ public void setPublishAllIssues(final boolean publishAllIssues) { /** * If {@code true}, then the result of the quality gate is ignored when selecting a reference build. This option is - * disabled by default so a failing quality gate will be passed from build to build until the original reason for + * disabled by default, so a failing quality gate will be passed from build to build until the original reason for * the failure has been resolved. * * @param ignoreQualityGate @@ -319,7 +316,7 @@ public int getHealthy() { } /** - * Sets the healthy threshold, i.e. the number of issues when health is reported as 100%. + * Sets the healthy threshold, i.e., the number of issues when health is reported as 100%. * * @param healthy * the number of issues when health is reported as 100% @@ -334,7 +331,7 @@ public int getUnhealthy() { } /** - * Sets the healthy threshold, i.e. the number of issues when health is reported as 0%. + * Sets the healthy threshold, i.e., the number of issues when health is reported as 0%. * * @param unhealthy * the number of issues when health is reported as 0% @@ -392,445 +389,15 @@ public TrendChartType getTrendChartType() { */ @DataBoundSetter @SuppressWarnings("unused") // Used by Stapler - public void setQualityGates(final List qualityGates) { + public void setQualityGates(final List qualityGates) { this.qualityGates = qualityGates; } @SuppressWarnings("WeakerAccess") // Required by Stapler - public List getQualityGates() { + public List getQualityGates() { return qualityGates; } - /** - * Appends the specified quality gates to the end of the list of quality gates. - * - * @param size - * the minimum number of issues that fails the quality gate - * @param type - * the type of the quality gate - * @param result - * determines whether the quality gate is a warning or failure - */ - private void addQualityGate(final int size, final QualityGateType type, final QualityGateResult result) { - qualityGates.add(new QualityGate(size, type, result)); - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link PublishIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setUnstableTotalAll(final int size) { - addQualityGate(size, QualityGateType.TOTAL, QualityGateResult.UNSTABLE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link PublishIssuesStep#getQualityGates()} - */ - @Deprecated - public int getUnstableTotalAll() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link PublishIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setUnstableTotalHigh(final int size) { - addQualityGate(size, QualityGateType.TOTAL_HIGH, QualityGateResult.UNSTABLE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link PublishIssuesStep#getQualityGates()} - */ - @Deprecated - public int getUnstableTotalHigh() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link PublishIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setUnstableNewAll(final int size) { - addQualityGate(size, QualityGateType.NEW, QualityGateResult.UNSTABLE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link PublishIssuesStep#getQualityGates()} - */ - @Deprecated - public int getUnstableNewAll() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link PublishIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setUnstableTotalNormal(final int size) { - addQualityGate(size, QualityGateType.TOTAL_NORMAL, QualityGateResult.UNSTABLE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link PublishIssuesStep#getQualityGates()} - */ - @Deprecated - public int getUnstableTotalNormal() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link PublishIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setUnstableTotalLow(final int size) { - addQualityGate(size, QualityGateType.TOTAL_LOW, QualityGateResult.UNSTABLE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link PublishIssuesStep#getQualityGates()} - */ - @Deprecated - public int getUnstableTotalLow() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link PublishIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setUnstableNewHigh(final int size) { - addQualityGate(size, QualityGateType.NEW_HIGH, QualityGateResult.UNSTABLE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link PublishIssuesStep#getQualityGates()} - */ - @Deprecated - public int getUnstableNewHigh() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link PublishIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setUnstableNewNormal(final int size) { - addQualityGate(size, QualityGateType.NEW_NORMAL, QualityGateResult.UNSTABLE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link PublishIssuesStep#getQualityGates()} - */ - @Deprecated - public int getUnstableNewNormal() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link PublishIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setUnstableNewLow(final int size) { - addQualityGate(size, QualityGateType.NEW_LOW, QualityGateResult.UNSTABLE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link PublishIssuesStep#getQualityGates()} - */ - @Deprecated - public int getUnstableNewLow() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link PublishIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setFailedTotalAll(final int size) { - addQualityGate(size, QualityGateType.TOTAL, QualityGateResult.FAILURE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link PublishIssuesStep#getQualityGates()} - */ - @Deprecated - public int getFailedTotalAll() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link PublishIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setFailedTotalHigh(final int size) { - addQualityGate(size, QualityGateType.TOTAL_HIGH, QualityGateResult.FAILURE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link PublishIssuesStep#getQualityGates()} - */ - @Deprecated - public int getFailedTotalHigh() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link PublishIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setFailedTotalNormal(final int size) { - addQualityGate(size, QualityGateType.TOTAL_NORMAL, QualityGateResult.FAILURE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link PublishIssuesStep#getQualityGates()} - */ - @Deprecated - public int getFailedTotalNormal() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link PublishIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setFailedTotalLow(final int size) { - addQualityGate(size, QualityGateType.TOTAL_LOW, QualityGateResult.FAILURE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link PublishIssuesStep#getQualityGates()} - */ - @Deprecated - public int getFailedTotalLow() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link PublishIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setFailedNewAll(final int size) { - addQualityGate(size, QualityGateType.NEW, QualityGateResult.FAILURE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link PublishIssuesStep#getQualityGates()} - */ - @Deprecated - public int getFailedNewAll() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link PublishIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setFailedNewHigh(final int size) { - addQualityGate(size, QualityGateType.NEW_HIGH, QualityGateResult.FAILURE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link PublishIssuesStep#getQualityGates()} - */ - @Deprecated - public int getFailedNewHigh() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link PublishIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setFailedNewNormal(final int size) { - addQualityGate(size, QualityGateType.NEW_NORMAL, QualityGateResult.FAILURE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link PublishIssuesStep#getQualityGates()} - */ - @Deprecated - public int getFailedNewNormal() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link PublishIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setFailedNewLow(final int size) { - addQualityGate(size, QualityGateType.NEW_LOW, QualityGateResult.FAILURE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link PublishIssuesStep#getQualityGates()} - */ - @Deprecated - public int getFailedNewLow() { - return 0; - } - @Override public StepExecution start(final StepContext stepContext) { return new Execution(stepContext, this); @@ -866,9 +433,6 @@ static class Execution extends AnalysisExecution { @Override protected ResultAction run() throws IOException, InterruptedException, IllegalStateException { - QualityGateEvaluator qualityGate = new QualityGateEvaluator(); - qualityGate.addAll(new ArrayList<>(step.getQualityGates())); - AnnotatedReport report; if (step.reports.size() > 1) { report = new AnnotatedReport(StringUtils.defaultIfEmpty(step.getId(), IssuesRecorder.DEFAULT_ID)); @@ -884,14 +448,14 @@ protected ResultAction run() throws IOException, InterruptedException, IllegalSt } report.addAll(step.reports); - StageResultHandler statusHandler = new PipelineResultHandler(getRun(), + ResultHandler notifier = new PipelineResultHandler(getRun(), getContext().get(FlowNode.class)); IssuesPublisher publisher = new IssuesPublisher(getRun(), report, new HealthDescriptor(step.getHealthy(), step.getUnhealthy(), - step.getMinimumSeverityAsSeverity()), qualityGate, + step.getMinimumSeverityAsSeverity()), step.getQualityGates(), StringUtils.defaultString(step.getName()), step.getReferenceJobName(), step.getReferenceBuildId(), step.getIgnoreQualityGate(), step.getIgnoreFailedBuilds(), - getCharset(step.getSourceCodeEncoding()), getLogger(report), statusHandler, step.getFailOnError()); + getCharset(step.getSourceCodeEncoding()), getLogger(report), notifier, step.getFailOnError()); ResultAction action = publisher.attachAction(step.getTrendChartType()); if (!step.isSkipPublishingChecks()) { diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/RecordIssuesStep.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/RecordIssuesStep.java index 5955bfa5ab..82b73a10a5 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/RecordIssuesStep.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/RecordIssuesStep.java @@ -35,15 +35,14 @@ import io.jenkins.plugins.analysis.core.model.ResultAction; import io.jenkins.plugins.analysis.core.model.StaticAnalysisLabelProvider; import io.jenkins.plugins.analysis.core.model.Tool; -import io.jenkins.plugins.analysis.core.util.QualityGate; -import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateResult; -import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateType; -import io.jenkins.plugins.analysis.core.util.QualityGateEvaluator; import io.jenkins.plugins.analysis.core.util.TrendChartType; +import io.jenkins.plugins.analysis.core.util.WarningsQualityGate; import io.jenkins.plugins.checks.steps.ChecksInfo; import io.jenkins.plugins.prism.SourceCodeDirectory; +import io.jenkins.plugins.prism.SourceCodeRetention; import io.jenkins.plugins.util.PipelineResultHandler; -import io.jenkins.plugins.util.StageResultHandler; +import io.jenkins.plugins.util.QualityGateEvaluator; +import io.jenkins.plugins.util.ResultHandler; import io.jenkins.plugins.util.ValidationUtilities; /** @@ -71,8 +70,8 @@ public class RecordIssuesStep extends Step implements Serializable { private List analysisTools = new ArrayList<>(); private String sourceCodeEncoding = StringUtils.EMPTY; - private String sourceDirectory = StringUtils.EMPTY; private Set sourceDirectories = new HashSet<>(); // @since 9.11.0 + private SourceCodeRetention sourceCodeRetention = SourceCodeRetention.EVERY_BUILD; private boolean ignoreQualityGate = false; // by default, a successful quality gate is mandatory; private boolean ignoreFailedBuilds = true; // by default, failed builds are ignored; @@ -97,7 +96,7 @@ public class RecordIssuesStep extends Step implements Serializable { private String id; private String name; - private List qualityGates = new ArrayList<>(); + private List qualityGates = new ArrayList<>(); private TrendChartType trendChartType = TrendChartType.AGGREGATION_TOOLS; @@ -140,445 +139,15 @@ public String getScm() { */ @SuppressWarnings("unused") // used by Stapler view data binding @DataBoundSetter - public void setQualityGates(final List qualityGates) { + public void setQualityGates(final List qualityGates) { this.qualityGates = qualityGates; } - /** - * Appends the specified quality gates to the end of the list of quality gates. - * - * @param size - * the minimum number of issues that fails the quality gate - * @param type - * the type of the quality gate - * @param result - * determines whether the quality gate is a warning or failure - */ - public void addQualityGate(final int size, final QualityGateType type, final QualityGateResult result) { - qualityGates.add(new QualityGate(size, type, result)); - } - @SuppressWarnings({"unused", "WeakerAccess"}) // used by Stapler view data binding - public List getQualityGates() { + public List getQualityGates() { return qualityGates; } - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link RecordIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setUnstableTotalAll(final int size) { - addQualityGate(size, QualityGateType.TOTAL, QualityGateResult.UNSTABLE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link RecordIssuesStep#getQualityGates()} - */ - @Deprecated - public int getUnstableTotalAll() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link RecordIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setUnstableTotalHigh(final int size) { - addQualityGate(size, QualityGateType.TOTAL_HIGH, QualityGateResult.UNSTABLE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link RecordIssuesStep#getQualityGates()} - */ - @Deprecated - public int getUnstableTotalHigh() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link RecordIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setUnstableNewAll(final int size) { - addQualityGate(size, QualityGateType.NEW, QualityGateResult.UNSTABLE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link RecordIssuesStep#getQualityGates()} - */ - @Deprecated - public int getUnstableNewAll() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link RecordIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setUnstableTotalNormal(final int size) { - addQualityGate(size, QualityGateType.TOTAL_NORMAL, QualityGateResult.UNSTABLE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link RecordIssuesStep#getQualityGates()} - */ - @Deprecated - public int getUnstableTotalNormal() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link RecordIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setUnstableTotalLow(final int size) { - addQualityGate(size, QualityGateType.TOTAL_LOW, QualityGateResult.UNSTABLE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link RecordIssuesStep#getQualityGates()} - */ - @Deprecated - public int getUnstableTotalLow() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link RecordIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setUnstableNewHigh(final int size) { - addQualityGate(size, QualityGateType.NEW_HIGH, QualityGateResult.UNSTABLE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link RecordIssuesStep#getQualityGates()} - */ - @Deprecated - public int getUnstableNewHigh() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link RecordIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setUnstableNewNormal(final int size) { - addQualityGate(size, QualityGateType.NEW_NORMAL, QualityGateResult.UNSTABLE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link RecordIssuesStep#getQualityGates()} - */ - @Deprecated - public int getUnstableNewNormal() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link RecordIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setUnstableNewLow(final int size) { - addQualityGate(size, QualityGateType.NEW_LOW, QualityGateResult.UNSTABLE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link RecordIssuesStep#getQualityGates()} - */ - @Deprecated - public int getUnstableNewLow() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link RecordIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setFailedTotalAll(final int size) { - addQualityGate(size, QualityGateType.TOTAL, QualityGateResult.FAILURE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link RecordIssuesStep#getQualityGates()} - */ - @Deprecated - public int getFailedTotalAll() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link RecordIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setFailedTotalHigh(final int size) { - addQualityGate(size, QualityGateType.TOTAL_HIGH, QualityGateResult.FAILURE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link RecordIssuesStep#getQualityGates()} - */ - @Deprecated - public int getFailedTotalHigh() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link RecordIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setFailedTotalNormal(final int size) { - addQualityGate(size, QualityGateType.TOTAL_NORMAL, QualityGateResult.FAILURE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link RecordIssuesStep#getQualityGates()} - */ - @Deprecated - public int getFailedTotalNormal() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link RecordIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setFailedTotalLow(final int size) { - addQualityGate(size, QualityGateType.TOTAL_LOW, QualityGateResult.FAILURE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link RecordIssuesStep#getQualityGates()} - */ - @Deprecated - public int getFailedTotalLow() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link RecordIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setFailedNewAll(final int size) { - addQualityGate(size, QualityGateType.NEW, QualityGateResult.FAILURE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link RecordIssuesStep#getQualityGates()} - */ - @Deprecated - public int getFailedNewAll() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link RecordIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setFailedNewHigh(final int size) { - addQualityGate(size, QualityGateType.NEW_HIGH, QualityGateResult.FAILURE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link RecordIssuesStep#getQualityGates()} - */ - @Deprecated - public int getFailedNewHigh() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link RecordIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setFailedNewNormal(final int size) { - addQualityGate(size, QualityGateType.NEW_NORMAL, QualityGateResult.FAILURE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link RecordIssuesStep#getQualityGates()} - */ - @Deprecated - public int getFailedNewNormal() { - return 0; - } - - /** - * Sets the quality gate. - * - * @param size - * number of issues - * - * @deprecated replaced by {@link RecordIssuesStep#addQualityGate(int, QualityGate.QualityGateType, - * QualityGate.QualityGateResult)} - */ - @Deprecated - @DataBoundSetter - public void setFailedNewLow(final int size) { - addQualityGate(size, QualityGateType.NEW_LOW, QualityGateResult.FAILURE); - } - - /** - * Gets the quality gate. - * - * @return 0 - * @deprecated replaced by {@link RecordIssuesStep#getQualityGates()} - */ - @Deprecated - public int getFailedNewLow() { - return 0; - } - /** * Defines the ID of the results. The ID is used as URL of the results and as name in UI elements. If no ID is * given, then the ID of the associated result object is used. @@ -742,25 +311,9 @@ public void setSourceCodeEncoding(final String sourceCodeEncoding) { this.sourceCodeEncoding = sourceCodeEncoding; } - public String getSourceDirectory() { - return sourceDirectory; - } - - /** - * Sets the path to the folder that contains the source code. If not relative and thus not part of the workspace - * then this folder needs to be added in Jenkins global configuration. - * - * @param sourceDirectory - * a folder containing the source code - */ - @DataBoundSetter - public void setSourceDirectory(final String sourceDirectory) { - this.sourceDirectory = sourceDirectory; - } - /** * Sets the paths to the directories that contain the source code. If not relative and thus not part of the - * workspace then these directories need to be added in Jenkins global configuration to prevent accessing of + * workspace, then these directories need to be added in Jenkins global configuration to prevent accessing of * forbidden resources. * * @param sourceDirectories @@ -776,11 +329,22 @@ public List getSourceDirectories() { } private List getAllSourceDirectories() { - Set directories = new HashSet<>(getSourceDirectories()); - if (StringUtils.isNotBlank(getSourceDirectory())) { - directories.add(new SourceCodeDirectory(getSourceDirectory())); - } - return new ArrayList<>(directories); + return new ArrayList<>(new HashSet<>(getSourceDirectories())); + } + + /** + * Defines the retention strategy for source code files. + * + * @param sourceCodeRetention + * the retention strategy for source code files + */ + @DataBoundSetter + public void setSourceCodeRetention(final SourceCodeRetention sourceCodeRetention) { + this.sourceCodeRetention = sourceCodeRetention; + } + + public SourceCodeRetention getSourceCodeRetention() { + return sourceCodeRetention; } /** @@ -815,30 +379,6 @@ public void setQuiet(final boolean quiet) { this.quiet = quiet; } - /** - * Returns whether SCM blaming should be disabled. - * - * @return {@code true} if SCM blaming should be disabled - * @deprecated use {@link #isSkipBlames()} - */ - @SuppressWarnings("PMD.BooleanGetMethodName") - @Deprecated - public boolean getBlameDisabled() { - return isBlameDisabled; - } - - /** - * Determines whether to skip the SCM blaming. - * - * @param blameDisabled {@code true} if SCM blaming should be disabled - * @deprecated use {@link #setSkipBlames(boolean)} - */ - @Deprecated - @DataBoundSetter - public void setBlameDisabled(final boolean blameDisabled) { - isBlameDisabled = blameDisabled; - } - /** * Returns whether SCM blaming should be disabled. * @@ -853,32 +393,6 @@ public void setSkipBlames(final boolean skipBlames) { isBlameDisabled = skipBlames; } - /** - * Not used anymore. - * - * @return {@code true} if SCM forensics should be disabled - * @deprecated Forensics will be automatically skipped if the Forensics recorder is not activated. - */ - @SuppressWarnings("PMD.BooleanGetMethodName") - @Deprecated - public boolean getForensicsDisabled() { - return false; - } - - /** - * Not used anymore. - * - * @param forensicsDisabled - * not used - * - * @deprecated Forensics will be automatically skipped if the Forensics recorder is not activated. - */ - @DataBoundSetter - @Deprecated - public void setForensicsDisabled(final boolean forensicsDisabled) { - // do nothing - } - /** * Returns whether post-processing of the issues should be disabled. * @@ -940,7 +454,7 @@ public void setEnabledForFailure(final boolean enabledForFailure) { /** * If {@code true}, then the result of the quality gate is ignored when selecting a reference build. This option is - * disabled by default so a failing quality gate will be passed from build to build until the original reason for + * disabled by default, so a failing quality gate will be passed from build to build until the original reason for * the failure has been resolved. * * @param ignoreQualityGate @@ -1054,7 +568,7 @@ public int getHealthy() { } /** - * Sets the healthy threshold, i.e. the number of issues when health is reported as 100%. + * Sets the healthy threshold, i.e., the number of issues when health is reported as 100%. * * @param healthy * the number of issues when health is reported as 100% @@ -1069,7 +583,7 @@ public int getUnhealthy() { } /** - * Sets the healthy threshold, i.e. the number of issues when health is reported as 0%. + * Sets the healthy threshold, i.e., the number of issues when health is reported as 0%. * * @param unhealthy * the number of issues when health is reported as 0% @@ -1154,7 +668,7 @@ protected List run() throws IOException, InterruptedException { recorder.setFilters(step.getFilters()); recorder.setEnabledForFailure(step.getEnabledForFailure()); recorder.setAggregatingResults(step.getAggregatingResults()); - recorder.setBlameDisabled(step.getBlameDisabled()); + recorder.setBlameDisabled(step.isSkipBlames()); recorder.setSkipPostProcessing(step.isSkipPostProcessing()); recorder.setScm(step.getScm()); recorder.setSkipPublishingChecks(step.isSkipPublishingChecks()); @@ -1167,13 +681,14 @@ protected List run() throws IOException, InterruptedException { recorder.setSourceDirectories(step.getAllSourceDirectories()); recorder.setChecksInfo(getContext().get(ChecksInfo.class)); recorder.setQuiet(step.isQuiet()); - StageResultHandler statusHandler = new PipelineResultHandler(getRun(), - getContext().get(FlowNode.class)); + + // FIXME: change base class + ResultHandler notifier = new PipelineResultHandler(getRun(), getContext().get(FlowNode.class)); FilePath workspace = getWorkspace(); workspace.mkdirs(); - return recorder.perform(getRun(), workspace, getTaskListener(), statusHandler); + return recorder.perform(getRun(), workspace, getTaskListener(), notifier); } } diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/ScanForIssuesStep.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/ScanForIssuesStep.java index 21cb893306..6d8ac823cf 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/ScanForIssuesStep.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/ScanForIssuesStep.java @@ -30,6 +30,7 @@ import io.jenkins.plugins.analysis.core.steps.IssuesScanner.BlameMode; import io.jenkins.plugins.analysis.core.steps.IssuesScanner.PostProcessingMode; import io.jenkins.plugins.prism.SourceCodeDirectory; +import io.jenkins.plugins.prism.SourceCodeRetention; /** * Scan files or the console log for issues. @@ -39,8 +40,8 @@ public class ScanForIssuesStep extends Step { private Tool tool; private String sourceCodeEncoding = StringUtils.EMPTY; - private String sourceDirectory = StringUtils.EMPTY; private Set sourceDirectories = new HashSet<>(); // @since 9.11.0 + private SourceCodeRetention sourceCodeRetention = SourceCodeRetention.EVERY_BUILD; private boolean isBlameDisabled; private boolean skipPostProcessing; // @since 10.6.0: by default, post-processing will be enabled private boolean quiet; @@ -129,32 +130,6 @@ public void setBlameDisabled(final boolean blameDisabled) { isBlameDisabled = blameDisabled; } - /** - * Not used anymore. - * - * @return {@code true} if SCM forensics should be disabled - * @deprecated Forensics will be automatically skipped if the Forensics recorder is not activated. - */ - @SuppressWarnings("PMD.BooleanGetMethodName") - @Deprecated - public boolean getForensicsDisabled() { - return false; - } - - /** - * Not used anymore. - * - * @param forensicsDisabled - * not used - * - * @deprecated Forensics will be automatically skipped if the Forensics recorder is not activated. - */ - @DataBoundSetter - @Deprecated - public void setForensicsDisabled(final boolean forensicsDisabled) { - // do nothing - } - /** * Returns whether post-processing of the issues should be disabled. * @@ -185,25 +160,9 @@ public void setSourceCodeEncoding(final String sourceCodeEncoding) { this.sourceCodeEncoding = sourceCodeEncoding; } - public String getSourceDirectory() { - return sourceDirectory; - } - - /** - * Sets the path to the folder that contains the source code. If not relative and thus not part of the workspace - * then this folder needs to be added in Jenkins global configuration. - * - * @param sourceDirectory - * a folder containing the source code - */ - @DataBoundSetter - public void setSourceDirectory(final String sourceDirectory) { - this.sourceDirectory = sourceDirectory; - } - /** * Sets the paths to the directories that contain the source code. If not relative and thus not part of the - * workspace then these directories need to be added in Jenkins global configuration to prevent accessing of + * workspace, then these directories need to be added in Jenkins global configuration to prevent accessing of * forbidden resources. * * @param sourceDirectories @@ -219,14 +178,24 @@ public List getSourceDirectories() { } private Set getAllSourceDirectories() { - Set directories = new HashSet<>(); - if (StringUtils.isNotBlank(getSourceDirectory())) { - directories.add(getSourceDirectory()); - } - directories.addAll(getSourceDirectories().stream() + return getSourceDirectories().stream() .map(SourceCodeDirectory::getPath) - .collect(Collectors.toSet())); - return directories; + .collect(Collectors.toSet()); + } + + /** + * Defines the retention strategy for source code files. + * + * @param sourceCodeRetention + * the retention strategy for source code files + */ + @DataBoundSetter + public void setSourceCodeRetention(final SourceCodeRetention sourceCodeRetention) { + this.sourceCodeRetention = sourceCodeRetention; + } + + public SourceCodeRetention getSourceCodeRetention() { + return sourceCodeRetention; } @Override @@ -249,6 +218,7 @@ static class Execution extends AnalysisExecution { private final Set sourceDirectories; private final String scm; private final boolean quiet; + private final SourceCodeRetention sourceCodeRetention; /** * Creates a new instance of the step execution object. @@ -266,6 +236,7 @@ static class Execution extends AnalysisExecution { isBlameDisabled = step.getBlameDisabled(); filters = step.getFilters(); sourceDirectories = step.getAllSourceDirectories(); + sourceCodeRetention = step.getSourceCodeRetention(); scm = step.getScm(); skipPostProcessing = step.isSkipPostProcessing(); quiet = step.isQuiet(); @@ -278,7 +249,7 @@ protected AnnotatedReport run() throws IOException, InterruptedException, Illega IssuesScanner issuesScanner = new IssuesScanner(tool, filters, getCharset(sourceCodeEncoding), workspace, sourceDirectories, - getRun(), new FilePath(getRun().getRootDir()), listener, + sourceCodeRetention, getRun(), new FilePath(getRun().getRootDir()), listener, scm, isBlameDisabled ? BlameMode.DISABLED : BlameMode.ENABLED, skipPostProcessing ? PostProcessingMode.DISABLED : PostProcessingMode.ENABLED, quiet); diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/WarningChecksPublisher.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/WarningChecksPublisher.java index 3b0dde51e7..5dbdbb707f 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/WarningChecksPublisher.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/steps/WarningChecksPublisher.java @@ -27,7 +27,6 @@ import io.jenkins.plugins.analysis.core.model.ResultAction; import io.jenkins.plugins.analysis.core.model.StaticAnalysisLabelProvider; import io.jenkins.plugins.analysis.core.util.IssuesStatistics; -import io.jenkins.plugins.analysis.core.util.QualityGateStatus; import io.jenkins.plugins.checks.api.ChecksAnnotation; import io.jenkins.plugins.checks.api.ChecksAnnotation.ChecksAnnotationBuilder; import io.jenkins.plugins.checks.api.ChecksAnnotation.ChecksAnnotationLevel; @@ -40,6 +39,7 @@ import io.jenkins.plugins.checks.api.ChecksStatus; import io.jenkins.plugins.checks.steps.ChecksInfo; import io.jenkins.plugins.util.JenkinsFacade; +import io.jenkins.plugins.util.QualityGateStatus; import static j2html.TagCreator.*; @@ -98,7 +98,7 @@ ChecksDetails extractChecksDetails(final AnnotationScope annotationScope) { return new ChecksDetailsBuilder() .withName(checksName) .withStatus(ChecksStatus.COMPLETED) - .withConclusion(extractChecksConclusion(result.getQualityGateStatus())) + .withConclusion(extractChecksConclusion(result.getQualityGateResult().getOverallStatus())) .withOutput(new ChecksOutputBuilder() .withTitle(extractChecksTitle(totals)) .withSummary(summary) @@ -205,7 +205,9 @@ private ChecksConclusion extractChecksConclusion(final QualityGateStatus status) case PASSED: return ChecksConclusion.SUCCESS; case FAILED: + case ERROR: case WARNING: + case NOTE: return ChecksConclusion.FAILURE; default: throw new IllegalArgumentException("Unsupported quality gate status: " + status); diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/AffectedFilesResolver.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/AffectedFilesResolver.java index a4366099d5..be2c91efa9 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/AffectedFilesResolver.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/AffectedFilesResolver.java @@ -7,6 +7,9 @@ import java.util.Set; import java.util.stream.Collectors; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.StringUtils; + import edu.hm.hafner.analysis.Issue; import edu.hm.hafner.analysis.Report; import edu.hm.hafner.util.FilteredLog; @@ -15,7 +18,6 @@ import hudson.FilePath; import hudson.model.Run; -import hudson.remoting.VirtualChannel; import io.jenkins.plugins.prism.FilePermissionEnforcer; @@ -26,8 +28,10 @@ * @author Ullrich Hafner */ public class AffectedFilesResolver { - /** Sub folder with the affected files. */ + /** Folder with the affected files within Jenkins' build results. */ public static final String AFFECTED_FILES_FOLDER_NAME = "files-with-issues"; + private static final String ZIP_EXTENSION = ".zip"; + private static final String TEXT_EXTENSION = ".tmp"; /** * Returns whether the affected file in Jenkins' build folder does exist and is readable. @@ -40,7 +44,8 @@ public class AffectedFilesResolver { * @return the file */ public static boolean hasAffectedFile(final Run run, final Issue issue) { - return canAccess(getFile(run, issue.getFileName())); + return canAccess(getFile(run, issue.getFileName())) + || canAccess(getZipFile(run, issue.getFileName())); } private static boolean canAccess(final Path file) { @@ -60,7 +65,35 @@ private static boolean canAccess(final Path file) { * if the file could not be found */ static InputStream asStream(final Run build, final String fileName) throws IOException { - return Files.newInputStream(getFile(build, fileName)); + try { + var file = getFile(build, fileName); + if (canAccess(file)) { + return Files.newInputStream(file); + } + + return extractFromZip(build, fileName); + } + catch (InterruptedException e) { + throw new IOException(e); + } + } + + private static InputStream extractFromZip(final Run build, final String fileName) + throws IOException, InterruptedException { + Path tempDir = Files.createTempDirectory(AFFECTED_FILES_FOLDER_NAME); + FilePath unzippedSourcesDir = new FilePath(tempDir.toFile()); + try { + var zipFile = getZipFile(build, fileName); + FilePath inputZipFile = new FilePath(zipFile.toFile()); + inputZipFile.unzip(unzippedSourcesDir); + StringUtils.removeEnd(zipFile.toString(), ZIP_EXTENSION); + var sourceFile = tempDir.resolve(FilenameUtils.getName(fileName)); + + return Files.newInputStream(sourceFile); + } + finally { + unzippedSourcesDir.deleteRecursive(); + } } /** @@ -74,9 +107,27 @@ static InputStream asStream(final Run build, final String fileName) throws * @return the file */ public static Path getFile(final Run run, final String fileName) { + return getPath(run, getTempName(fileName)); // Warnings plugin < 11.0.0 + } + + /** + * Returns the affected file in Jenkins' build folder. + * + * @param run + * the run referencing the build folder + * @param fileName + * the file name in the folder of affected files + * + * @return the file + */ + public static Path getZipFile(final Run run, final String fileName) { + return getPath(run, getZipName(fileName)); + } + + private static Path getPath(final Run run, final String zipName) { return run.getRootDir().toPath() .resolve(AFFECTED_FILES_FOLDER_NAME) - .resolve(getTempName(fileName)); + .resolve(zipName); } /** @@ -88,7 +139,11 @@ public static Path getFile(final Run run, final String fileName) { * @return the temporary name */ private static String getTempName(final String fileName) { - return Integer.toHexString(fileName.hashCode()) + ".tmp"; + return Integer.toHexString(fileName.hashCode()) + TEXT_EXTENSION; + } + + private static String getZipName(final String fileName) { + return getTempName(fileName) + ZIP_EXTENSION; } /** @@ -111,28 +166,6 @@ public void copyAffectedFilesToBuildFolder(final Report report, final FilePath w copyAffectedFilesToBuildFolder(report, new RemoteFacade(workspace, permittedSourceDirectories, buildFolder)); } - /** - * Copies all files with issues from the workspace to the build folder. - * - * @param report - * the issues - * @param channel - * virtual channel to access the files on the agent - * @param buildFolder - * directory to store the copied files in - * @param permittedSourceDirectories - * paths to the affected files on the agent - * - * @throws InterruptedException - * if the user cancels the processing - * @deprecated use {@link #copyAffectedFilesToBuildFolder(Report, FilePath, Set, FilePath)} - */ - @Deprecated - public void copyAffectedFilesToBuildFolder(final Report report, final VirtualChannel channel, - final FilePath buildFolder, final Set permittedSourceDirectories) throws InterruptedException { - // do nothing - } - @VisibleForTesting @SuppressWarnings("PMD.CognitiveComplexity") void copyAffectedFilesToBuildFolder(final Report report, final RemoteFacade remoteFacade) @@ -170,7 +203,6 @@ void copyAffectedFilesToBuildFolder(final Report report, final RemoteFacade remo log.getErrorMessages().forEach(report::logError); report.logInfo("-> %d copied, %d not in workspace, %d not-found, %d with I/O error", copied, notInWorkspace, notFound, log.size()); - log.logSummary(); } static class RemoteFacade { @@ -218,7 +250,7 @@ boolean isInWorkspace(final String fileName) { } public void copy(final String from, final String to) throws IOException, InterruptedException { - createFile(from).copyTo(computeBuildFolderFileName(to)); + createFile(from).zip(computeBuildFolderFileName(to)); } public boolean existsInBuildFolder(final String fileName) { @@ -231,7 +263,7 @@ public boolean existsInBuildFolder(final String fileName) { } private FilePath computeBuildFolderFileName(final String fileName) { - return buildFolder.child(getTempName(fileName)); + return buildFolder.child(getZipName(fileName)); } } } diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/IssuesStatisticsBuilder.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/IssuesStatisticsBuilder.java index da969e2fd4..e3bb6d0984 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/IssuesStatisticsBuilder.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/IssuesStatisticsBuilder.java @@ -113,46 +113,4 @@ void clear() { fixedSize = 0; } - - /** - * Computed automatically since 6.1.0. - * - * @param unused - * not used - * - * @return this - * @deprecated Computed automatically. - */ - @Deprecated - public IssuesStatisticsBuilder setTotalSize(final int unused) { - return this; - } - - /** - * Computed automatically since 6.1.0. - * - * @param unused - * not used - * - * @return this - * @deprecated Computed automatically. - */ - @Deprecated - public IssuesStatisticsBuilder setNewSize(final int unused) { - return this; - } - - /** - * Computed automatically since 6.1.0. - * - * @param unused - * not used - * - * @return this - * @deprecated Computed automatically. - */ - @Deprecated - public IssuesStatisticsBuilder setDeltaSize(final int unused) { - return this; - } } diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/QualityGateEvaluator.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/QualityGateEvaluator.java deleted file mode 100644 index e6b5ce0180..0000000000 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/QualityGateEvaluator.java +++ /dev/null @@ -1,110 +0,0 @@ -package io.jenkins.plugins.analysis.core.util; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import com.google.errorprone.annotations.FormatMethod; - -import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateResult; -import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateType; - -/** - * Evaluates a set of quality gates for a static analysis report. - * - * @author Ullrich Hafner - */ -public class QualityGateEvaluator { - private final List qualityGates = new ArrayList<>(); - - /** - * Enforces this quality gate for the specified run. - * - * @param report - * the report to evaluate - * @param logger - * the logger that reports the passed and failed quality gate thresholds - * - * @return result of the evaluation, expressed by a build state - */ - public QualityGateStatus evaluate(final IssuesStatistics report, final FormattedLogger logger) { - if (qualityGates.isEmpty()) { - logger.print("-> INACTIVE - No quality gate defined"); - - return QualityGateStatus.INACTIVE; - } - - QualityGateStatus status = QualityGateStatus.PASSED; - - for (QualityGate qualityGate : qualityGates) { - if (qualityGate.getThreshold() > 0) { - int actualSize = qualityGate.getActualSizeMethodReference().apply(report); - if (actualSize >= qualityGate.getThreshold()) { - logger.print("-> %s - %s: %d - Quality Gate: %d", - qualityGate.getStatus(), qualityGate.getName(), actualSize, qualityGate.getThreshold()); - if (qualityGate.getStatus().isWorseThan(status)) { - status = qualityGate.getStatus(); - } - } - else { - logger.print("-> PASSED - %s: %d - Quality Gate: %d", - qualityGate.getName(), actualSize, qualityGate.getThreshold()); - } - } - } - - return status; - } - - /** - * Appends the specified quality gates to the end of the list of quality gates. - * - * @param size - * the minimum number of issues that fails the quality gate - * @param type - * the type of the quality gate - * @param strength - * determines whether the quality gate is a warning or failure - */ - public void add(final int size, final QualityGateType type, final QualityGateResult strength) { - qualityGates.add(new QualityGate(size, type, strength)); - } - - /** - * Appends all of the quality gates in the specified collection to the end of the list of quality gates. - * - * @param additionalQualityGates - * the quality gates to add - */ - public void addAll(final Collection additionalQualityGates) { - this.qualityGates.addAll(additionalQualityGates); - } - - /** - * Returns whether at least one quality gate has been added. - * - * @return {@code true} if at least one quality gate has been added, {@code false} otherwise - */ - public boolean isEnabled() { - return !qualityGates.isEmpty(); - } - - /** - * Logs results of the quality gate evaluation. - */ - @FunctionalInterface - public interface FormattedLogger { - /** - * Logs the specified message. - * - * @param format - * A format string - * @param args - * Arguments referenced by the format specifiers in the format string. If there are more arguments than - * format specifiers, the extra arguments are ignored. The number of arguments is variable and may be - * zero. - */ - @FormatMethod - void print(String format, Object... args); - } -} diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/QualityGateStatus.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/QualityGateStatus.java deleted file mode 100644 index e192839595..0000000000 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/QualityGateStatus.java +++ /dev/null @@ -1,92 +0,0 @@ -package io.jenkins.plugins.analysis.core.util; - -import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.Whitelisted; -import hudson.model.BallColor; -import hudson.model.Result; - -import io.jenkins.plugins.analysis.core.util.QualityGateEvaluator.FormattedLogger; - -/** - * Result of a {@link QualityGateEvaluator#evaluate(IssuesStatistics, FormattedLogger)} call. - * - * @author Ullrich Hafner - */ -public enum QualityGateStatus { - /** Quality gate is inactive, so result evaluation is not available. */ - INACTIVE(Result.NOT_BUILT), - - /** Quality gate has been passed. */ - PASSED(Result.SUCCESS), - - /** Quality gate has been missed: severity is a warning. */ - WARNING(Result.UNSTABLE), - - /** Quality gate has been missed: severity is an error. */ - FAILED(Result.FAILURE); - - private final Result result; - - QualityGateStatus(final Result result) { - this.result = result; - } - - /** - * Returns the associated {@link Result} color. - * - * @return Jenkins' {@link Result} color - * @deprecated BallColor is not used anymore, build status icons are now rendered on the UI side only - */ - @Deprecated - public BallColor getColor() { - return result.color; - } - - /** - * Returns the associated {@link Result} icon class to be used in the UI. - * - * @return Jenkins' {@link Result} icon class - */ - public String getIconClass() { - return getColor().getIconClassName(); - } - - /** - * Returns the localized description be used in the UI. - * - * @return the localized description - */ - public String getDescription() { - return getColor().getDescription(); - } - - /** - * Returns whether the quality gate has been passed (or has not been activated at all). - * - * @return {@code true} if the quality gate has been passed, {@code false} otherwise - */ - @Whitelisted - public boolean isSuccessful() { - return this == PASSED || this == INACTIVE; - } - - /** - * Returns the associated {@link Result}. - * - * @return the associated {@link Result} - */ - public Result getResult() { - return result; - } - - /** - * Returns whether this status is worse than the specified status. - * - * @param other - * the other status - * - * @return {@code true} if this status is worse than the other status, {@code false} otherwise - */ - public boolean isWorseThan(final QualityGateStatus other) { - return ordinal() > other.ordinal(); - } -} diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/StaticAnalysisRun.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/StaticAnalysisRun.java index 924c96dd61..3fb04cd96f 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/StaticAnalysisRun.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/StaticAnalysisRun.java @@ -7,6 +7,9 @@ import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.Whitelisted; import hudson.model.Run; +import io.jenkins.plugins.util.QualityGateResult; +import io.jenkins.plugins.util.QualityGateStatus; + /** * Provides detailed information for the results of a static analysis run. */ @@ -48,13 +51,20 @@ public interface StaticAnalysisRun extends AnalysisBuildResult { int getSuccessfulSinceBuild(); /** - * Returns the {@link QualityGateStatus} of the {@link QualityGateEvaluator} evaluation of the static analysis run. + * Returns the {@link QualityGateStatus} of the quality gates evaluation of the static analysis run. * * @return the quality gate status */ - @Whitelisted QualityGateStatus getQualityGateStatus(); + /** + * Returns the {@link QualityGateResult} of the quality gates evaluation of the static analysis run. + * + * @return the quality gate status + */ + @Whitelisted + QualityGateResult getQualityGateResult(); + /** * Returns the reference static analysis run that has been used to compute the new issues. * diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/QualityGate.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/WarningsQualityGate.java similarity index 58% rename from plugin/src/main/java/io/jenkins/plugins/analysis/core/util/QualityGate.java rename to plugin/src/main/java/io/jenkins/plugins/analysis/core/util/WarningsQualityGate.java index 63175213d4..f0f4dbfd8e 100644 --- a/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/QualityGate.java +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/WarningsQualityGate.java @@ -1,19 +1,16 @@ package io.jenkins.plugins.analysis.core.util; -import java.io.Serializable; -import java.util.Objects; import java.util.function.Function; import edu.hm.hafner.util.VisibleForTesting; import org.kohsuke.stapler.AncestorInPath; import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.verb.POST; import hudson.Extension; -import hudson.model.AbstractDescribableImpl; import hudson.model.BuildableItem; -import hudson.model.Descriptor; import hudson.model.Item; import hudson.util.FormValidation; import hudson.util.ListBoxModel; @@ -21,81 +18,70 @@ import io.jenkins.plugins.analysis.core.util.IssuesStatistics.StatisticProperties; import io.jenkins.plugins.util.JenkinsFacade; - -import static io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateResult.*; +import io.jenkins.plugins.util.QualityGate; /** * Defines a quality gate based on a specific threshold of issues (total, new, delta) in the current build. After a - * build has been finished, a set of {@link QualityGate quality gates} will be evaluated and the overall quality gate - * status will be reported in Jenkins UI. + * build has been finished, a set of {@link WarningsQualityGate quality gates} will be evaluated and the overall quality + * gate status will be reported in Jenkins UI. * * @author Ullrich Hafner */ -public class QualityGate extends AbstractDescribableImpl implements Serializable { - private static final long serialVersionUID = -397278599489416668L; +public class WarningsQualityGate extends QualityGate { + private static final long serialVersionUID = -3560049414586166711L; - private final int threshold; private final QualityGateType type; - private final QualityGateStatus status; /** - * Creates a new instance of {@link QualityGate}. + * Creates a new instance of {@link WarningsQualityGate}. * - * @param threshold - * the minimum number of issues that fails the quality gate * @param type * the type of the quality gate - * @param unstable - * determines whether the build result will be set to unstable or failed if the quality gate is failed */ @DataBoundConstructor - public QualityGate(final int threshold, final QualityGateType type, final boolean unstable) { - super(); - - this.threshold = threshold; + public WarningsQualityGate(final QualityGateType type) { this.type = type; - status = unstable ? QualityGateStatus.WARNING : QualityGateStatus.FAILED; - } - - @SuppressWarnings("PMD.BooleanGetMethodName") - public boolean getUnstable() { - return status == QualityGateStatus.WARNING; - } - - public QualityGateType getType() { - return type; - } - - @SuppressWarnings("PMD.BooleanGetMethodName") - public boolean getWarning() { - return status == QualityGateStatus.WARNING; } /** - * Creates a new instance of {@link QualityGate}. + * Creates a new instance of {@link WarningsQualityGate}. * * @param threshold * the minimum number of issues that fails the quality gate * @param type * the type of the quality gate - * @param result - * determines whether the quality gate is a warning or failure + * @param criticality + * the criticality of the quality gate */ - public QualityGate(final int threshold, final QualityGateType type, final QualityGateResult result) { - super(); - - this.threshold = threshold; + public WarningsQualityGate(final int threshold, final QualityGateType type, + final QualityGateCriticality criticality) { this.type = type; - status = result.status; + + setIntegerThreshold(threshold); + setCriticality(criticality); + } + + public boolean isUnstable() { + return getCriticality() == QualityGateCriticality.UNSTABLE + || getCriticality() == QualityGateCriticality.NOTE; } /** - * Returns the minimum number of issues that will fail the quality gate. + * Sets the criticality of the quality gate. * - * @return minimum number of issues + * @param unstable + * the criticality of the quality gate + * @deprecated use {@link #setCriticality(QualityGateCriticality)} instead */ - public int getThreshold() { - return threshold; + @DataBoundSetter + @Deprecated + public void setUnstable(final boolean unstable) { + if (unstable) { + setCriticality(QualityGateCriticality.UNSTABLE); + } + else { + setCriticality(QualityGateCriticality.FAILURE); + } } /** @@ -107,31 +93,13 @@ public Function getActualSizeMethodReference() { return type.getSizeGetter(); } - /** - * Returns the human-readable name of the quality gate. - * - * @return the human-readable name - */ + @Override public String getName() { return type.getDisplayName(); } - /** - * Returns the quality gate status to set if the quality gate is failed. - * - * @return the status - */ - public QualityGateStatus getStatus() { - return status; - } - - /** - * Returns the quality gate status to set if the quality gate is failed. - * - * @return the status - */ - public QualityGateResult getResult() { - return status == QualityGateStatus.WARNING ? UNSTABLE : FAILURE; + public QualityGateType getType() { + return type; } @Override @@ -142,39 +110,15 @@ public boolean equals(final Object o) { if (o == null || getClass() != o.getClass()) { return false; } - QualityGate that = (QualityGate) o; - return threshold == that.threshold && type == that.type && status == that.status; + + WarningsQualityGate that = (WarningsQualityGate) o; + + return type == that.type; } @Override public int hashCode() { - return Objects.hash(threshold, type, status); - } - - /** - * Determines the Jenkins build result if the quality gate is failed. - */ - public enum QualityGateResult { - /** The build will be marked as unstable. */ - UNSTABLE(QualityGateStatus.WARNING), - - /** The build will be marked as failed. */ - FAILURE(QualityGateStatus.FAILED); - - private final QualityGateStatus status; - - QualityGateResult(final QualityGateStatus status) { - this.status = status; - } - - /** - * Returns the status. - * - * @return the status - */ - public QualityGateStatus getStatus() { - return status; - } + return type != null ? type.hashCode() : 0; } /** @@ -225,15 +169,15 @@ public Function getSizeGetter() { } /** - * Descriptor of the {@link QualityGate}. + * Descriptor of the {@link WarningsQualityGate}. */ @Extension - public static class QualityGateDescriptor extends Descriptor { + public static class WarningsQualityGateDescriptor extends QualityGateDescriptor { private final ModelValidation modelValidation = new ModelValidation(); private final JenkinsFacade jenkins; @VisibleForTesting - QualityGateDescriptor(final JenkinsFacade jenkinsFacade) { + WarningsQualityGateDescriptor(final JenkinsFacade jenkinsFacade) { super(); jenkins = jenkinsFacade; @@ -242,7 +186,7 @@ public static class QualityGateDescriptor extends Descriptor { /** * Creates a new descriptor. */ - public QualityGateDescriptor() { + public WarningsQualityGateDescriptor() { this(new JenkinsFacade()); } diff --git a/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/WarningsQualityGateEvaluator.java b/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/WarningsQualityGateEvaluator.java new file mode 100644 index 0000000000..c7a4f721eb --- /dev/null +++ b/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/WarningsQualityGateEvaluator.java @@ -0,0 +1,40 @@ +package io.jenkins.plugins.analysis.core.util; + +import java.util.Collection; + +import io.jenkins.plugins.util.QualityGateEvaluator; +import io.jenkins.plugins.util.QualityGateResult; +import io.jenkins.plugins.util.QualityGateStatus; + +/** + * Evaluates a given set of quality gates. + * + * @author Johannes Walter + */ +public class WarningsQualityGateEvaluator extends QualityGateEvaluator { + private final IssuesStatistics statistics; + + public WarningsQualityGateEvaluator(final Collection qualityGates, + final IssuesStatistics statistics) { + super(qualityGates); + + this.statistics = statistics; + } + + @Override + protected void evaluate(final WarningsQualityGate qualityGate, final QualityGateResult result) { + if (qualityGate.getThreshold() > 0) { + int actualSize = qualityGate.getActualSizeMethodReference().apply(statistics); + var actualValue = String.valueOf(actualSize); + if (actualSize >= qualityGate.getThreshold()) { + result.add(qualityGate, qualityGate.getStatus(), actualValue); + } + else { + result.add(qualityGate, QualityGateStatus.PASSED, actualValue); + } + } + else { + result.add(qualityGate, QualityGateStatus.INACTIVE, "Threshold too small: " + qualityGate.getThreshold()); + } + } +} diff --git a/plugin/src/main/resources/io/jenkins/plugins/analysis/core/model/ResultAction/summary.jelly b/plugin/src/main/resources/io/jenkins/plugins/analysis/core/model/ResultAction/summary.jelly index 79fa243bd8..415da6ec6e 100644 --- a/plugin/src/main/resources/io/jenkins/plugins/analysis/core/model/ResultAction/summary.jelly +++ b/plugin/src/main/resources/io/jenkins/plugins/analysis/core/model/ResultAction/summary.jelly @@ -1,6 +1,6 @@ - + @@ -28,10 +28,12 @@ - + - + @@ -82,18 +84,15 @@
  • -
  • - ${%Quality gate}: ${s.qualityGateStatus.description} - - - - - - -
  • + + + + + +
diff --git a/plugin/src/main/resources/io/jenkins/plugins/analysis/core/steps/IssuesRecorder/help-sourceCodeRetention.html b/plugin/src/main/resources/io/jenkins/plugins/analysis/core/steps/IssuesRecorder/help-sourceCodeRetention.html new file mode 100644 index 0000000000..c004607b03 --- /dev/null +++ b/plugin/src/main/resources/io/jenkins/plugins/analysis/core/steps/IssuesRecorder/help-sourceCodeRetention.html @@ -0,0 +1,21 @@ +
+ Select the strategy that should be used to store the affected source code files. + Storing the affected source code files along with the issues consumes a lot of space on your hard disk for large + projects. So if your server has not enough free space available to store the sources for all builds, + it might make more sense to store only the sources of the last build. + In this case, the plugin will automatically discard old results before the new sources are stored. + If you do not need the source files at all, you can deactivate the storing of source code files. + + The following options are supported: + +
+
NEVER
+
Never store source code files.
+
LAST_BUILD
+
Store source code files of the last build, delete older artifacts.
+
EVERY_BUILD
+
Store source code files for all builds, never delete those files automatically.
+
MODIFIED
+
Store only changed source code files for all builds, never delete those files automatically.
+
+
diff --git a/plugin/src/main/resources/io/jenkins/plugins/analysis/core/steps/RecordIssuesStep/help-sourceCodeRetention.html b/plugin/src/main/resources/io/jenkins/plugins/analysis/core/steps/RecordIssuesStep/help-sourceCodeRetention.html new file mode 100644 index 0000000000..c004607b03 --- /dev/null +++ b/plugin/src/main/resources/io/jenkins/plugins/analysis/core/steps/RecordIssuesStep/help-sourceCodeRetention.html @@ -0,0 +1,21 @@ +
+ Select the strategy that should be used to store the affected source code files. + Storing the affected source code files along with the issues consumes a lot of space on your hard disk for large + projects. So if your server has not enough free space available to store the sources for all builds, + it might make more sense to store only the sources of the last build. + In this case, the plugin will automatically discard old results before the new sources are stored. + If you do not need the source files at all, you can deactivate the storing of source code files. + + The following options are supported: + +
+
NEVER
+
Never store source code files.
+
LAST_BUILD
+
Store source code files of the last build, delete older artifacts.
+
EVERY_BUILD
+
Store source code files for all builds, never delete those files automatically.
+
MODIFIED
+
Store only changed source code files for all builds, never delete those files automatically.
+
+
diff --git a/plugin/src/main/resources/io/jenkins/plugins/analysis/core/steps/ScanForIssuesStep/help-sourceCodeRetention.html b/plugin/src/main/resources/io/jenkins/plugins/analysis/core/steps/ScanForIssuesStep/help-sourceCodeRetention.html new file mode 100644 index 0000000000..c004607b03 --- /dev/null +++ b/plugin/src/main/resources/io/jenkins/plugins/analysis/core/steps/ScanForIssuesStep/help-sourceCodeRetention.html @@ -0,0 +1,21 @@ +
+ Select the strategy that should be used to store the affected source code files. + Storing the affected source code files along with the issues consumes a lot of space on your hard disk for large + projects. So if your server has not enough free space available to store the sources for all builds, + it might make more sense to store only the sources of the last build. + In this case, the plugin will automatically discard old results before the new sources are stored. + If you do not need the source files at all, you can deactivate the storing of source code files. + + The following options are supported: + +
+
NEVER
+
Never store source code files.
+
LAST_BUILD
+
Store source code files of the last build, delete older artifacts.
+
EVERY_BUILD
+
Store source code files for all builds, never delete those files automatically.
+
MODIFIED
+
Store only changed source code files for all builds, never delete those files automatically.
+
+
diff --git a/plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/QualityGate/config.jelly b/plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/WarningsQualityGate/config.jelly similarity index 57% rename from plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/QualityGate/config.jelly rename to plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/WarningsQualityGate/config.jelly index d77aa6daf2..364452cb40 100644 --- a/plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/QualityGate/config.jelly +++ b/plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/WarningsQualityGate/config.jelly @@ -1,16 +1,16 @@ - - + + - - + + diff --git a/plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/QualityGate/config.properties b/plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/WarningsQualityGate/config.properties similarity index 100% rename from plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/QualityGate/config.properties rename to plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/WarningsQualityGate/config.properties diff --git a/plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/WarningsQualityGate/help-criticality.html b/plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/WarningsQualityGate/help-criticality.html new file mode 100644 index 0000000000..8655cba352 --- /dev/null +++ b/plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/WarningsQualityGate/help-criticality.html @@ -0,0 +1,31 @@ +
+ When a quality gate has been missed, this property determines whether the result of the associated step + or the overall build will be marked as unstable or failure. + + The following enum values are possible for freestyle jobs: + +
+
UNSTABLE
+
+ Set the step and build status to unstable if the quality gate has been missed. +
+
FAILURE
+
+ Fail the step and build if the quality gate has been missed. +
+
+ + For Pipelines two additional fine-grained options are available, that allow setting the status of the step without + touching the overall build status: + +
+
NOTE
+
+ Set the step to unstable if the quality gate has been missed. +
+
ERROR
+
+ Fail the step if the quality gate has been missed. +
+
+
diff --git a/plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/QualityGate/help-threshold.html b/plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/WarningsQualityGate/help-threshold.html similarity index 70% rename from plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/QualityGate/help-threshold.html rename to plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/WarningsQualityGate/help-threshold.html index 9483446c77..1ff7a911a3 100644 --- a/plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/QualityGate/help-threshold.html +++ b/plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/WarningsQualityGate/help-threshold.html @@ -1,4 +1,4 @@
- The threshold defines the minimum number of warnings that will fail a build. Values less or equal zero are ignored. + The threshold defines the minimum number of warnings that will miss the quality gate. Values less or equal zero are ignored. So if you want to fail a build that has one warning, set this field to 1.
diff --git a/plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/QualityGate/help-type.html b/plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/WarningsQualityGate/help-type.html similarity index 90% rename from plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/QualityGate/help-type.html rename to plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/WarningsQualityGate/help-type.html index ab00ee452f..ce8a214390 100644 --- a/plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/QualityGate/help-type.html +++ b/plugin/src/main/resources/io/jenkins/plugins/analysis/core/util/WarningsQualityGate/help-type.html @@ -6,12 +6,12 @@
Selects the total number of issues in the current build.
New
Selects the total number of new issues in the current build with respect to the reference build. - New issues will be calculated by a sophisticated algorithm, + New issues will be calculated by a sophisticated algorithm that tries to track issues from build to build, even if the source code has been modified. Note that this algorithm sometimes detects outstanding warnings as new, e.g., if a source file has been refactored heavily.
Delta
-
Selects the difference of the total number of issues of the current build subtracted by the total +
Selects the difference between the total number of issues in the current build subtracted by the total number of issues in the reference build. This is a simple subtraction, so if you have a build that adds a new warning and removes a completely different warning, then the result will be zero.
diff --git a/plugin/src/main/resources/issues/number.jelly b/plugin/src/main/resources/issues/number.jelly deleted file mode 100644 index 87910a60b3..0000000000 --- a/plugin/src/main/resources/issues/number.jelly +++ /dev/null @@ -1,64 +0,0 @@ - - - - Generates an input field <input type="number" ... /> to be used inside <f:entry/>. - The minimum number is set to 0, the step size to 10. - - - Used for databinding. TBD. - - - This becomes @name of the <input> tag. - If @field is specified, this value is inferred from it. - - - The initial value of the field. This becomes the @value of the <input> tag. - If @field is specified, the current property from the "instance" object - will be set as the initial value automatically, - which is the recommended approach. - - - The default value of the text box, in case both @value is and 'instance[field]' is null. - - - - Additional CSS class(es) to add (such as client-side validation clazz="required", - "number" or "positive-number"; these may be combined, as clazz="required number"). - - - Override the default error message when client-side validation fails, - as with clazz="required", etc. - - - If specified, the value entered in this input field will be checked (via AJAX) - against this URL, and errors will be rendered under the text field. - - If @field is specified, this will be inferred automatically, - which is the recommended approach. - - - - - - - - - - - - - - ${customizedFields.add(name)} - - diff --git a/plugin/src/main/resources/issues/publish-parameters.jelly b/plugin/src/main/resources/issues/publish-parameters.jelly index 2cdf738dac..98128fb369 100644 --- a/plugin/src/main/resources/issues/publish-parameters.jelly +++ b/plugin/src/main/resources/issues/publish-parameters.jelly @@ -53,11 +53,11 @@ - + - + diff --git a/plugin/src/main/resources/issues/scan-parameters.jelly b/plugin/src/main/resources/issues/scan-parameters.jelly index 670b18b776..d1b198bb67 100644 --- a/plugin/src/main/resources/issues/scan-parameters.jelly +++ b/plugin/src/main/resources/issues/scan-parameters.jelly @@ -20,6 +20,10 @@ + + + + diff --git a/plugin/src/main/resources/issues/scan-parameters.properties b/plugin/src/main/resources/issues/scan-parameters.properties index 1db1120aa6..83e5a2be04 100644 --- a/plugin/src/main/resources/issues/scan-parameters.properties +++ b/plugin/src/main/resources/issues/scan-parameters.properties @@ -8,4 +8,4 @@ title.skipPostProcessing=Disable detection of missing package and module names title.filter=Issue Filters description.filter=Issues will be matched with all the specified filters. If no filter is \ defined, then all issues will be published. Filters with empty regular expression will be ignored. - +sourceCodeRetention.title=Source Code Retention Strategy diff --git a/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/AnalysisHistoryTest.java b/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/AnalysisHistoryTest.java index 2430cbcf1a..07036d88d0 100644 --- a/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/AnalysisHistoryTest.java +++ b/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/AnalysisHistoryTest.java @@ -17,7 +17,11 @@ import io.jenkins.plugins.analysis.core.model.AnalysisHistory.JobResultEvaluationMode; import io.jenkins.plugins.analysis.core.model.AnalysisHistory.QualityGateEvaluationMode; -import io.jenkins.plugins.analysis.core.util.QualityGateStatus; +import io.jenkins.plugins.analysis.core.util.WarningsQualityGate; +import io.jenkins.plugins.analysis.core.util.WarningsQualityGate.QualityGateType; +import io.jenkins.plugins.util.QualityGate.QualityGateCriticality; +import io.jenkins.plugins.util.QualityGateResult; +import io.jenkins.plugins.util.QualityGateStatus; import static io.jenkins.plugins.analysis.core.model.AnalysisHistory.JobResultEvaluationMode.*; import static io.jenkins.plugins.analysis.core.model.AnalysisHistory.QualityGateEvaluationMode.*; @@ -117,7 +121,7 @@ void baselineResultIsPreviousResultIfAlreadySet() { @MethodSource("createTestDataForIgnoredQualityGateAndIgnoredBuildResult") @DisplayName("Ignore job result + ignore quality gate -> history with one previous build") void shouldTestFirstIterationOfLoopIgnoreStatusAndResult(final String name, - final ExpectedResult expectedResult, final QualityGateStatus qualityGateStatus, final Result jobStatus) { + final ExpectedResult expectedResult, final QualityGateResult qualityGateStatus, final Result jobStatus) { runTest(IGNORE_QUALITY_GATE, IGNORE_JOB_RESULT, qualityGateStatus, jobStatus, expectedResult); } @@ -125,7 +129,7 @@ void shouldTestFirstIterationOfLoopIgnoreStatusAndResult(final String name, @MethodSource("createTestDataForIgnoredQualityGateAndNoFailedBuild") @DisplayName("No job failure + ignore quality gate -> history with one previous build") void shouldTestFirstIterationOfLoopIgnoreStatus(final String name, - final ExpectedResult expectedResult, final QualityGateStatus qualityGateStatus, final Result jobStatus) { + final ExpectedResult expectedResult, final QualityGateResult qualityGateStatus, final Result jobStatus) { runTest(IGNORE_QUALITY_GATE, NO_JOB_FAILURE, qualityGateStatus, jobStatus, expectedResult); } @@ -133,7 +137,7 @@ void shouldTestFirstIterationOfLoopIgnoreStatus(final String name, @MethodSource("createTestDataForSuccessfulQualityGateAndIgnoredBuildResult") @DisplayName("Ignore job result + successful quality gate -> history with one previous build") void shouldTestFirstIterationOfLoopIgnoreResult(final String name, - final ExpectedResult expectedResult, final QualityGateStatus qualityGateStatus, final Result jobStatus) { + final ExpectedResult expectedResult, final QualityGateResult qualityGateStatus, final Result jobStatus) { runTest(SUCCESSFUL_QUALITY_GATE, IGNORE_JOB_RESULT, qualityGateStatus, jobStatus, expectedResult); } @@ -141,13 +145,13 @@ void shouldTestFirstIterationOfLoopIgnoreResult(final String name, @MethodSource("createTestDataForSuccessfulQualityGateAndNoFailedBuild") @DisplayName("No job failure + successful quality gate -> history with one previous build") void shouldTestFirstIterationOfLoop(final String name, - final ExpectedResult expectedResult, final QualityGateStatus qualityGateStatus, final Result jobStatus) { + final ExpectedResult expectedResult, final QualityGateResult qualityGateStatus, final Result jobStatus) { runTest(SUCCESSFUL_QUALITY_GATE, NO_JOB_FAILURE, qualityGateStatus, jobStatus, expectedResult); } private void runTest(final QualityGateEvaluationMode qualityGateEvaluationMode, final JobResultEvaluationMode jobResultEvaluationMode, - final QualityGateStatus qualityGateStatus, final Result jobStatus, final ExpectedResult expectedResult) { + final QualityGateResult qualityGateStatus, final Result jobStatus, final ExpectedResult expectedResult) { ResultSelector resultSelector = mock(ResultSelector.class); Run baseline = createBuild(qualityGateStatus, jobStatus, resultSelector); @@ -164,13 +168,13 @@ private void runTest(final QualityGateEvaluationMode qualityGateEvaluationMode, } } - private Run createBuild(final QualityGateStatus qualityGateStatus, final Result jobStatus, + private Run createBuild(final QualityGateResult qualityGateStatus, final Result jobStatus, final ResultSelector resultSelector) { Run baseline = createBuildWithResult(jobStatus); AnalysisResult result = mock(AnalysisResult.class); when(result.getOwner()).thenAnswer(a -> baseline); - when(result.getQualityGateStatus()).thenReturn(qualityGateStatus); + when(result.getQualityGateResult()).thenReturn(qualityGateStatus); ResultAction resultAction = mock(ResultAction.class); when(resultAction.getResult()).thenReturn(result); @@ -197,48 +201,55 @@ private static Stream createTestDataForSuccessfulQualityGateAndNoFail return Stream.of( new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.SUCCESS) - .setQualityGateStatus(QualityGateStatus.INACTIVE) + .setQualityGateResult(createResult(QualityGateStatus.INACTIVE)) .setTestName("Job should have analysis result (SUCCESS, quality gate is not active)") .build(), new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.SUCCESS) - .setQualityGateStatus(QualityGateStatus.PASSED) + .setQualityGateResult(createResult(QualityGateStatus.PASSED)) .setTestName("Job should have analysis result (SUCCESS, quality gate has been passed)") .build(), new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.UNSTABLE) - .setQualityGateStatus(QualityGateStatus.INACTIVE) + .setQualityGateResult(createResult(QualityGateStatus.INACTIVE)) .setTestName("Job should have analysis result (UNSTABLE, quality gate is not active)") .build(), new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.UNSTABLE) - .setQualityGateStatus(QualityGateStatus.PASSED) + .setQualityGateResult(createResult(QualityGateStatus.PASSED)) .setTestName("Job should have analysis result (UNSTABLE, quality gate has been passed)") .build(), new BuildHistoryBuilder().setExpectedResult(NONE) .setJobResult(Result.SUCCESS) - .setQualityGateStatus(QualityGateStatus.FAILED) + .setQualityGateResult(createResult(QualityGateStatus.FAILED)) .setTestName("Job should have no analysis result if quality gate has been missed (SUCCESS)") .build(), new BuildHistoryBuilder().setExpectedResult(NONE) .setJobResult(Result.SUCCESS) - .setQualityGateStatus(QualityGateStatus.WARNING) + .setQualityGateResult(createResult(QualityGateStatus.WARNING)) .setTestName("Job should have no analysis result if quality gate has a warning (SUCCESS)") .build(), new BuildHistoryBuilder().setExpectedResult(NONE) .setJobResult(Result.FAILURE) - .setQualityGateStatus(QualityGateStatus.INACTIVE) + .setQualityGateResult(createResult(QualityGateStatus.INACTIVE)) .setTestName("Job should have no analysis result even if quality gate is not active (FAILED)") .build(), new BuildHistoryBuilder().setExpectedResult(NONE) .setJobResult(Result.FAILURE) - .setQualityGateStatus(QualityGateStatus.PASSED) + .setQualityGateResult(createResult(QualityGateStatus.PASSED)) .setTestName("Job should have no analysis result even if quality gate has been passed (FAILED)") .build() ); } + private static QualityGateResult createResult(final QualityGateStatus qualityGateStatus) { + var result = new QualityGateResult(); + result.add(new WarningsQualityGate(0, QualityGateType.TOTAL, QualityGateCriticality.UNSTABLE), + qualityGateStatus, "message"); + return result; + } + /** * Method to provide test element that return an present optional. * @@ -248,50 +259,50 @@ private static Stream createTestDataForIgnoredQualityGateAndIgnoredBu return Stream.of( new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.SUCCESS) - .setQualityGateStatus(QualityGateStatus.INACTIVE) + .setQualityGateResult(createResult(QualityGateStatus.INACTIVE)) .setTestName("Job should have analysis result (SUCCESS, quality gate is not active)") .build(), new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.SUCCESS) - .setQualityGateStatus(QualityGateStatus.PASSED) + .setQualityGateResult(createResult(QualityGateStatus.PASSED)) .setTestName("Job should have analysis result (SUCCESS, quality gate has been passed)") .build(), new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.UNSTABLE) - .setQualityGateStatus(QualityGateStatus.INACTIVE) + .setQualityGateResult(createResult(QualityGateStatus.INACTIVE)) .setTestName("Job should have analysis result (UNSTABLE, quality gate is not active)") .build(), new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.UNSTABLE) - .setQualityGateStatus(QualityGateStatus.PASSED) + .setQualityGateResult(createResult(QualityGateStatus.PASSED)) .setTestName("Job should have analysis result (UNSTABLE, quality gate has been passed)") .build(), new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.SUCCESS) - .setQualityGateStatus(QualityGateStatus.FAILED) + .setQualityGateResult(createResult(QualityGateStatus.FAILED)) .setTestName("Job should have analysis result if quality gate has been missed (SUCCESS)") .build(), new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.SUCCESS) - .setQualityGateStatus(QualityGateStatus.WARNING) + .setQualityGateResult(createResult(QualityGateStatus.WARNING)) .setTestName("Job should have analysis result if quality gate has a warning (SUCCESS)") .build(), new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.FAILURE) - .setQualityGateStatus(QualityGateStatus.INACTIVE) + .setQualityGateResult(createResult(QualityGateStatus.INACTIVE)) .setTestName("Job should have analysis result even if quality gate is not active (FAILED)") .build(), new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.FAILURE) - .setQualityGateStatus(QualityGateStatus.PASSED) + .setQualityGateResult(createResult(QualityGateStatus.PASSED)) .setTestName("Job should have analysis result even if quality gate has been passed (FAILED)") .build() ); } /** - * Method to provide test element that return an present optional. + * Method to provide test element that return a present optional. * * @return list of test data objects */ @@ -299,44 +310,44 @@ private static Stream createTestDataForSuccessfulQualityGateAndIgnore return Stream.of( new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.SUCCESS) - .setQualityGateStatus(QualityGateStatus.INACTIVE) + .setQualityGateResult(createResult(QualityGateStatus.INACTIVE)) .setTestName("Job should have analysis result (SUCCESS, quality gate is not active)") .build(), new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.SUCCESS) - .setQualityGateStatus(QualityGateStatus.PASSED) + .setQualityGateResult(createResult(QualityGateStatus.PASSED)) .setTestName("Job should have analysis result (SUCCESS, quality gate has been passed)") .build(), new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.UNSTABLE) - .setQualityGateStatus(QualityGateStatus.INACTIVE) + .setQualityGateResult(createResult(QualityGateStatus.INACTIVE)) .setTestName("Job should have analysis result (UNSTABLE, quality gate is not active)") .build(), new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.UNSTABLE) - .setQualityGateStatus(QualityGateStatus.PASSED) + .setQualityGateResult(createResult(QualityGateStatus.PASSED)) .setTestName("Job should have analysis result (UNSTABLE, quality gate has been passed)") .build(), new BuildHistoryBuilder().setExpectedResult(NONE) .setJobResult(Result.SUCCESS) - .setQualityGateStatus(QualityGateStatus.FAILED) + .setQualityGateResult(createResult(QualityGateStatus.FAILED)) .setTestName("Job should have no analysis result if quality gate has been missed (SUCCESS)") .build(), new BuildHistoryBuilder().setExpectedResult(NONE) .setJobResult(Result.SUCCESS) - .setQualityGateStatus(QualityGateStatus.WARNING) + .setQualityGateResult(createResult(QualityGateStatus.WARNING)) .setTestName("Job should have no analysis result if quality gate has a warning (SUCCESS)") .build(), new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.FAILURE) - .setQualityGateStatus(QualityGateStatus.INACTIVE) + .setQualityGateResult(createResult(QualityGateStatus.INACTIVE)) .setTestName("Job should have analysis result even if quality gate is not active (FAILED)") .build(), new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.FAILURE) - .setQualityGateStatus(QualityGateStatus.PASSED) + .setQualityGateResult(createResult(QualityGateStatus.PASSED)) .setTestName("Job should have analysis result even if quality gate has been passed (FAILED)") .build() ); @@ -351,44 +362,44 @@ private static Stream createTestDataForIgnoredQualityGateAndNoFailedB return Stream.of( new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.SUCCESS) - .setQualityGateStatus(QualityGateStatus.INACTIVE) + .setQualityGateResult(createResult(QualityGateStatus.INACTIVE)) .setTestName("Job should have analysis result (SUCCESS, quality gate is not active)") .build(), new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.SUCCESS) - .setQualityGateStatus(QualityGateStatus.PASSED) + .setQualityGateResult(createResult(QualityGateStatus.PASSED)) .setTestName("Job should have analysis result (SUCCESS, quality gate has been passed)") .build(), new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.UNSTABLE) - .setQualityGateStatus(QualityGateStatus.INACTIVE) + .setQualityGateResult(createResult(QualityGateStatus.INACTIVE)) .setTestName("Job should have analysis result (UNSTABLE, quality gate is not active)") .build(), new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.UNSTABLE) - .setQualityGateStatus(QualityGateStatus.PASSED) + .setQualityGateResult(createResult(QualityGateStatus.PASSED)) .setTestName("Job should have analysis result (UNSTABLE, quality gate has been passed)") .build(), new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.SUCCESS) - .setQualityGateStatus(QualityGateStatus.FAILED) + .setQualityGateResult(createResult(QualityGateStatus.FAILED)) .setTestName("Job should have analysis result if quality gate has been missed (SUCCESS)") .build(), new BuildHistoryBuilder().setExpectedResult(FIRST) .setJobResult(Result.SUCCESS) - .setQualityGateStatus(QualityGateStatus.WARNING) + .setQualityGateResult(createResult(QualityGateStatus.WARNING)) .setTestName("Job should have analysis result if quality gate has a warning (SUCCESS)") .build(), new BuildHistoryBuilder().setExpectedResult(NONE) .setJobResult(Result.FAILURE) - .setQualityGateStatus(QualityGateStatus.INACTIVE) + .setQualityGateResult(createResult(QualityGateStatus.INACTIVE)) .setTestName("Job should have no analysis result even if quality gate is not active (FAILED)") .build(), new BuildHistoryBuilder().setExpectedResult(NONE) .setJobResult(Result.FAILURE) - .setQualityGateStatus(QualityGateStatus.PASSED) + .setQualityGateResult(createResult(QualityGateStatus.PASSED)) .setTestName("Job should have no analysis result even if quality gate has been passed (FAILED)") .build() ); @@ -408,7 +419,7 @@ enum ExpectedResult { private static class BuildHistoryBuilder { private String testName; private ExpectedResult expectedResult; - private QualityGateStatus qualityGateStatus; + private QualityGateResult qualityGateResult; private Result jobResult; BuildHistoryBuilder setTestName(final String testName) { @@ -421,8 +432,8 @@ BuildHistoryBuilder setExpectedResult(final ExpectedResult expectedResult) { return this; } - BuildHistoryBuilder setQualityGateStatus(final QualityGateStatus qualityGateStatus) { - this.qualityGateStatus = qualityGateStatus; + BuildHistoryBuilder setQualityGateResult(final QualityGateResult result) { + this.qualityGateResult = result; return this; } @@ -437,7 +448,7 @@ BuildHistoryBuilder setJobResult(final Result jobResult) { * @return test arg */ Arguments build() { - return Arguments.of(testName, expectedResult, qualityGateStatus, jobResult); + return Arguments.of(testName, expectedResult, qualityGateResult, jobResult); } } } diff --git a/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/AnalysisResultTest.java b/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/AnalysisResultTest.java index 3d466462e6..fd40f666fb 100644 --- a/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/AnalysisResultTest.java +++ b/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/AnalysisResultTest.java @@ -1,7 +1,5 @@ package io.jenkins.plugins.analysis.core.model; -import java.io.IOException; -import java.nio.file.Path; import java.util.Collections; import org.junit.jupiter.api.Test; @@ -9,13 +7,11 @@ import edu.hm.hafner.util.ResourceTest; -import hudson.XmlFile; import hudson.model.Run; -import hudson.util.XStream2; -import io.jenkins.plugins.analysis.core.util.QualityGateStatus; import io.jenkins.plugins.forensics.blame.Blames; import io.jenkins.plugins.forensics.miner.RepositoryStatistics; +import io.jenkins.plugins.util.QualityGateResult; import static io.jenkins.plugins.analysis.core.assertions.Assertions.*; import static org.mockito.Mockito.*; @@ -26,18 +22,6 @@ * @author Ullrich Hafner */ class AnalysisResultTest extends ResourceTest { - @Test - void shouldRestoreResultBeforeIssuesStatisticsField() throws IOException { - XStream2 reportXmlStream = new XStream2(); - - Path xml = getResourceAsFile("result.xml"); - XmlFile xmlFile = new XmlFile(reportXmlStream, xml.toFile()); - AnalysisResult restored = (AnalysisResult) xmlFile.read(); - - assertThat(restored).hasTotalSize(14).hasNewSize(9).hasFixedSize(0); - assertThat(restored.getTotals()).hasTotalSize(14).hasNewSize(9).hasFixedSize(0); - } - @Test @Issue("SECURITY-2090") void constructorShouldThrowExceptionIfIdHasInvalidPattern() { @@ -45,6 +29,6 @@ void constructorShouldThrowExceptionIfIdHasInvalidPattern() { .isThrownBy( () -> new AnalysisResult(mock(Run.class), "../../invalid-id", mock(DeltaReport.class), new Blames(), new RepositoryStatistics(), - QualityGateStatus.PASSED, Collections.emptyMap())); + new QualityGateResult(), Collections.emptyMap())); } } diff --git a/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/JobActionTest.java b/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/JobActionTest.java index 27e757ead5..aa8a2a2a7e 100644 --- a/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/JobActionTest.java +++ b/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/JobActionTest.java @@ -32,7 +32,7 @@ class JobActionTest { void shouldUseLabelProvider() { StaticAnalysisLabelProvider labelProvider = mock(StaticAnalysisLabelProvider.class); when(labelProvider.getLinkName()).thenReturn(LINK_NAME); - when(labelProvider.getRawLinkName()).thenReturn(LINK_NAME); + when(labelProvider.getLinkName()).thenReturn(LINK_NAME); when(labelProvider.getTrendName()).thenReturn(TREND_NAME); when(labelProvider.getId()).thenReturn(ID); diff --git a/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/ResetQualityGateCommandTest.java b/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/ResetQualityGateCommandTest.java index 224f9c7dfb..9348773b2b 100644 --- a/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/ResetQualityGateCommandTest.java +++ b/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/ResetQualityGateCommandTest.java @@ -13,8 +13,9 @@ import hudson.model.FreeStyleProject; import hudson.model.Item; -import io.jenkins.plugins.analysis.core.util.QualityGateStatus; import io.jenkins.plugins.util.JenkinsFacade; +import io.jenkins.plugins.util.QualityGateResult; +import io.jenkins.plugins.util.QualityGateStatus; import static io.jenkins.plugins.analysis.core.testutil.Assertions.*; import static org.mockito.Mockito.*; @@ -128,7 +129,10 @@ private ResultAction createResultAction(final QualityGateStatus status, final St ResultAction resultAction = mock(ResultAction.class); AnalysisResult result = mock(AnalysisResult.class); - when(result.getQualityGateStatus()).thenReturn(status); + var qualityGateResult = mock(QualityGateResult.class); + when(qualityGateResult.getOverallStatus()).thenReturn(status); + when(qualityGateResult.isSuccessful()).thenReturn(status.isSuccessful()); + when(result.getQualityGateResult()).thenReturn(qualityGateResult); // Reference build is set FreeStyleBuild referenceBuild = mock(FreeStyleBuild.class); diff --git a/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/SummaryModelTest.java b/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/SummaryModelTest.java index 6d0083a3ec..c1bdbd667b 100644 --- a/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/SummaryModelTest.java +++ b/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/SummaryModelTest.java @@ -18,7 +18,8 @@ import hudson.model.Run; import io.jenkins.plugins.analysis.core.model.SummaryModel.LabelProviderFactoryFacade; -import io.jenkins.plugins.analysis.core.util.QualityGateStatus; +import io.jenkins.plugins.util.QualityGateResult; +import io.jenkins.plugins.util.QualityGateStatus; import static io.jenkins.plugins.analysis.core.assertions.Assertions.*; import static org.mockito.Mockito.*; @@ -173,7 +174,9 @@ void shouldUseQualityStatusOfResult() { Lists.immutable.of(ERROR_MESSAGE), 0); QualityGateStatus qualityGateStatus = QualityGateStatus.FAILED; - when(analysisResult.getQualityGateStatus()).thenReturn(qualityGateStatus); + var result = mock(QualityGateResult.class); + when(result.getOverallStatus()).thenReturn(qualityGateStatus); + when(analysisResult.getQualityGateResult()).thenReturn(result); SummaryModel summary = createSummary(analysisResult); @@ -223,7 +226,9 @@ private AnalysisResult createAnalysisResult(final Map sizesPerO when(analysisRun.getFixedSize()).thenReturn(fixedSize); when(analysisRun.getErrorMessages()).thenReturn(errorMessages); when(analysisRun.getNoIssuesSinceBuild()).thenReturn(numberOfIssuesSinceBuild); - when(analysisRun.getQualityGateStatus()).thenReturn(QualityGateStatus.INACTIVE); + var qualityGateResult = mock(QualityGateResult.class); + when(qualityGateResult.getOverallStatus()).thenReturn(QualityGateStatus.INACTIVE); + when(analysisRun.getQualityGateResult()).thenReturn(qualityGateResult); when(analysisRun.getIssues()).thenReturn(createReport(sizesPerOrigin.keySet())); Run build = mock(Run.class); when(build.getNumber()).thenReturn(2); diff --git a/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/TabLabelProviderTest.java b/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/TabLabelProviderTest.java index 807868be84..0d2d31b743 100644 --- a/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/TabLabelProviderTest.java +++ b/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/TabLabelProviderTest.java @@ -14,7 +14,6 @@ * @author Tobias Redl */ class TabLabelProviderTest { - private TabLabelProvider createTabLabelProvider(final String fileName) { Issue issue = mock(Issue.class); when(issue.getFileName()).thenReturn(fileName); diff --git a/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/WarningsPluginConfigurationTest.java b/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/WarningsPluginConfigurationTest.java deleted file mode 100644 index 09b53c9ade..0000000000 --- a/plugin/src/test/java/io/jenkins/plugins/analysis/core/model/WarningsPluginConfigurationTest.java +++ /dev/null @@ -1,99 +0,0 @@ -package io.jenkins.plugins.analysis.core.model; - -import java.util.Arrays; -import java.util.List; - -import org.junit.jupiter.api.Test; - -import edu.hm.hafner.util.PathUtil; - -import hudson.FilePath; -import hudson.remoting.VirtualChannel; - -import io.jenkins.plugins.util.GlobalConfigurationFacade; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -/** - * Tests the class {@link WarningsPluginConfiguration}. - * - * @author Ullrich Hafner - */ -class WarningsPluginConfigurationTest { - private static final PathUtil PATH_UTIL = new PathUtil(); - - private static final String FIRST = "/One"; - private static final String SECOND = "/Two"; - private static final String ABSOLUTE_NOT_EXISTING = "/Three"; - private static final String RELATIVE = "Relative"; - - private static final String NORMALIZED = PATH_UTIL.getAbsolutePath("/workspace"); - - private static final List SOURCE_ROOTS - = Arrays.asList(new SourceDirectory(FIRST), new SourceDirectory(SECOND)); - - @Test - void shouldHaveNoRootFoldersWhenCreated() { - WarningsPluginConfiguration configuration = createConfiguration(); - - assertThat(configuration.getSourceDirectories()).isEmpty(); - - assertThat(get(configuration, "")).isEqualTo(NORMALIZED); - assertThat(get(configuration, "-")).isEqualTo(NORMALIZED); - assertThat(get(configuration, ABSOLUTE_NOT_EXISTING)).isEqualTo(NORMALIZED); - assertThat(get(configuration, RELATIVE)).isEqualTo(getWorkspaceChild(RELATIVE)); - } - - @Test - void shouldSaveConfigurationIfFoldersAreAdded() { - GlobalConfigurationFacade facade = mock(GlobalConfigurationFacade.class); - WarningsPluginConfiguration configuration = new WarningsPluginConfiguration(facade); - - configuration.setSourceDirectories(SOURCE_ROOTS); - - verify(facade).save(); - assertThat(configuration.getSourceDirectories()).isEqualTo(SOURCE_ROOTS); - - assertThat(get(configuration, FIRST)).isEqualTo(FIRST); - assertThat(get(configuration, RELATIVE)).isEqualTo(getWorkspaceChild(RELATIVE)); - assertThat(get(configuration, ABSOLUTE_NOT_EXISTING)).isEqualTo(NORMALIZED); - } - - @Test - void shouldNormalizePath() { - WarningsPluginConfiguration configuration = createConfiguration(); - - configuration.setSourceDirectories( - Arrays.asList(new SourceDirectory("/absolute/unix"), new SourceDirectory("C:\\absolute\\windows"))); - - String relativeUnix = "relative/unix"; - String relativeWindows = "relative\\windows"; - String absoluteUnix = "/absolute/unix"; - String absoluteWindows = "C:\\absolute\\windows"; - String absoluteWindowsNormalized = "C:/absolute/windows"; - - assertThat(get(configuration, relativeUnix)).isEqualTo(getWorkspaceChild(relativeUnix)); - assertThat(get(configuration, relativeWindows)).isEqualTo(getWorkspaceChild(relativeWindows)); - assertThat(get(configuration, absoluteUnix)).isEqualTo(absoluteUnix); - assertThat(get(configuration, absoluteWindows)).isEqualTo(normalize(absoluteWindows)); - assertThat(get(configuration, absoluteWindowsNormalized)).isEqualTo(absoluteWindowsNormalized); - } - - private String getWorkspaceChild(final String expected) { - return PATH_UTIL.createAbsolutePath(NORMALIZED, expected); - } - - private String normalize(final String remote) { - return PATH_UTIL.getAbsolutePath(remote); - } - - private String get(final WarningsPluginConfiguration configuration, final String absoluteUnix) { - FilePath path = new FilePath((VirtualChannel) null, NORMALIZED); - return normalize(configuration.getPermittedSourceDirectory(path, absoluteUnix).getRemote()); - } - - private WarningsPluginConfiguration createConfiguration() { - return new WarningsPluginConfiguration(mock(GlobalConfigurationFacade.class)); - } -} diff --git a/plugin/src/test/java/io/jenkins/plugins/analysis/core/steps/WarningChecksPublisherITest.java b/plugin/src/test/java/io/jenkins/plugins/analysis/core/steps/WarningChecksPublisherITest.java index 9ffed175c8..8b3f0a946a 100644 --- a/plugin/src/test/java/io/jenkins/plugins/analysis/core/steps/WarningChecksPublisherITest.java +++ b/plugin/src/test/java/io/jenkins/plugins/analysis/core/steps/WarningChecksPublisherITest.java @@ -20,8 +20,8 @@ import io.jenkins.plugins.analysis.core.steps.WarningChecksPublisher.AnnotationScope; import io.jenkins.plugins.analysis.core.testutil.IntegrationTestWithJenkinsPerSuite; -import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateResult; -import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateType; +import io.jenkins.plugins.analysis.core.util.WarningsQualityGate; +import io.jenkins.plugins.analysis.core.util.WarningsQualityGate.QualityGateType; import io.jenkins.plugins.analysis.warnings.CheckStyle; import io.jenkins.plugins.analysis.warnings.MsBuild; import io.jenkins.plugins.analysis.warnings.PVSStudio; @@ -37,6 +37,7 @@ import io.jenkins.plugins.checks.api.ChecksStatus; import io.jenkins.plugins.checks.util.CapturingChecksPublisher; import io.jenkins.plugins.checks.util.CapturingChecksPublisher.Factory; +import io.jenkins.plugins.util.QualityGate.QualityGateCriticality; import static io.jenkins.plugins.analysis.core.assertions.Assertions.*; @@ -111,7 +112,8 @@ private void configureScanner(final WorkflowJob job, final String fileName, fina void shouldConcludeChecksAsSuccessWhenQualityGateIsPassed() { FreeStyleProject project = createFreeStyleProjectWithWorkspaceFilesWithSuffix(NEW_CHECKSTYLE_REPORT); enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(10, QualityGateType.TOTAL, QualityGateResult.UNSTABLE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(10, QualityGateType.TOTAL, QualityGateCriticality.UNSTABLE)))); Run build = buildSuccessfully(project); WarningChecksPublisher publisher = new WarningChecksPublisher(getResultAction(build), TaskListener.NULL, null); @@ -125,7 +127,7 @@ void shouldConcludeChecksAsSuccessWhenQualityGateIsPassed() { */ @Test void shouldConcludeChecksAsFailureWhenQualityGateIsFailed() { - assertChecksConclusionIsFailureWithQualityGateResult(QualityGateResult.FAILURE); + assertChecksConclusionIsFailureWithQualityGateResult(QualityGateCriticality.FAILURE); } /** @@ -133,7 +135,7 @@ void shouldConcludeChecksAsFailureWhenQualityGateIsFailed() { */ @Test void shouldConcludeChecksAsFailureWhenQualityGateResultIsUnstable() { - assertChecksConclusionIsFailureWithQualityGateResult(QualityGateResult.UNSTABLE); + assertChecksConclusionIsFailureWithQualityGateResult(QualityGateCriticality.UNSTABLE); } /** @@ -264,10 +266,10 @@ void shouldUseDefaultChecksNamePublishIssues() { assertThat(publishedChecks).hasSize(1); - assertThat(publishedChecks.get(0).getName()).isPresent().get().isEqualTo("CheckStyle"); + assertThat(publishedChecks.get(0).getName()).contains("CheckStyle"); assertThat(publishedChecks.get(0).getOutput()).isPresent().hasValueSatisfying( - output -> assertThat(output.getTitle()).isPresent().get().isEqualTo("No new issues, 6 total")); + output -> assertThat(output.getTitle()).contains("No new issues, 6 total")); } /** @@ -295,10 +297,10 @@ private void buildCheckForNewAndOutstandingWarnings(final AnnotationScope scope, assertThat(publishedChecks).hasSize(1); ChecksDetails details = publishedChecks.get(0); - assertThat(details.getName()).isPresent().get().isEqualTo("CheckStyle"); + assertThat(details.getName()).contains("CheckStyle"); assertThat(details.getOutput()).isPresent().hasValueSatisfying( output -> { - assertThat(output.getTitle()).isPresent().get().isEqualTo("2 new issues, 6 total"); + assertThat(output.getTitle()).contains("2 new issues, 6 total"); assertThat(output.getChecksAnnotations()).hasSize(expectedSize); }); } @@ -317,9 +319,9 @@ void shouldUseDefaultChecksNameRecordIssues() { assertThat(publishedChecks).hasSize(1); ChecksDetails details = publishedChecks.get(0); - assertThat(details.getName()).isPresent().get().isEqualTo("CheckStyle"); + assertThat(details.getName()).contains("CheckStyle"); assertThat(details.getOutput()).isPresent().hasValueSatisfying( - output -> assertThat(output.getTitle()).isPresent().get().isEqualTo("No new issues, 6 total")); + output -> assertThat(output.getTitle()).contains("No new issues, 6 total")); } /** @@ -337,10 +339,10 @@ void shouldHonorWithChecksContextPublishIssues() { assertThat(publishedChecks).hasSize( 2); // First from 'In progress' check provided by withChecks, second from publishIssues - publishedChecks.forEach(check -> assertThat(check.getName()).isPresent().get().isEqualTo("Custom Checks Name")); + publishedChecks.forEach(check -> assertThat(check.getName()).contains("Custom Checks Name")); assertThat(publishedChecks.get(1).getOutput()).isPresent().hasValueSatisfying( - output -> assertThat(output.getTitle()).isPresent().get().isEqualTo("No new issues, 6 total")); + output -> assertThat(output.getTitle()).contains("No new issues, 6 total")); } /** @@ -358,10 +360,10 @@ void shouldHonorWithChecksContextRecordIssues() { assertThat(publishedChecks).hasSize( 2); // First from 'In progress' check provided by withChecks, second from recordIssues - publishedChecks.forEach(check -> assertThat(check.getName()).isPresent().get().isEqualTo("Custom Checks Name")); + publishedChecks.forEach(check -> assertThat(check.getName()).contains("Custom Checks Name")); assertThat(publishedChecks.get(1).getOutput()).isPresent().hasValueSatisfying( - output -> assertThat(output.getTitle()).isPresent().get().isEqualTo("No new issues, 6 total")); + output -> assertThat(output.getTitle()).contains("No new issues, 6 total")); } /** @@ -452,15 +454,15 @@ private IssuesRecorder enableAndConfigureCheckstyle(final AbstractProject return item; } - private void assertChecksConclusionIsFailureWithQualityGateResult(final QualityGateResult qualityGateResult) { + private void assertChecksConclusionIsFailureWithQualityGateResult(final QualityGateCriticality criticality) { FreeStyleProject project = createFreeStyleProjectWithWorkspaceFilesWithSuffix(NEW_CHECKSTYLE_REPORT); - enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(1, QualityGateType.TOTAL, qualityGateResult)); + enableAndConfigureCheckstyle(project, recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(1, QualityGateType.TOTAL, criticality)))); - Run build = buildWithResult(project, qualityGateResult.getStatus().getResult()); + Run build = buildWithResult(project, criticality.getStatus().getResult()); assertThat(getAnalysisResult(build)) .hasTotalSize(6) - .hasQualityGateStatus(qualityGateResult.getStatus()); + .hasQualityGateStatus(criticality.getStatus()); WarningChecksPublisher publisher = new WarningChecksPublisher(getResultAction(build), TaskListener.NULL, null); assertThat(publisher.extractChecksDetails(AnnotationScope.PUBLISH_NEW_ISSUES).getConclusion()) diff --git a/plugin/src/test/java/io/jenkins/plugins/analysis/core/util/QualityGateEvaluatorTest.java b/plugin/src/test/java/io/jenkins/plugins/analysis/core/util/QualityGateEvaluatorTest.java index e3978b4bd9..ecd532da13 100644 --- a/plugin/src/test/java/io/jenkins/plugins/analysis/core/util/QualityGateEvaluatorTest.java +++ b/plugin/src/test/java/io/jenkins/plugins/analysis/core/util/QualityGateEvaluatorTest.java @@ -5,66 +5,65 @@ import java.util.function.Function; import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.DefaultLocale; -import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateResult; -import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateType; -import io.jenkins.plugins.analysis.core.util.QualityGateEvaluator.FormattedLogger; +import edu.hm.hafner.util.FilteredLog; + +import io.jenkins.plugins.analysis.core.util.WarningsQualityGate.QualityGateType; +import io.jenkins.plugins.util.NullResultHandler; +import io.jenkins.plugins.util.QualityGate.QualityGateCriticality; +import io.jenkins.plugins.util.QualityGateResult; import static io.jenkins.plugins.analysis.core.assertions.Assertions.*; -/** - * Tests the class {@link QualityGateEvaluator}. - * - * @author Ullrich Hafner - */ @SuppressWarnings("PMD.MoreThanOneLogger") +@DefaultLocale("en") class QualityGateEvaluatorTest { @Test void shouldBeInactiveIfGatesAreEmpty() { - Logger logger = new Logger(); - IssuesStatisticsBuilder builder = new IssuesStatisticsBuilder(); - - QualityGateEvaluator qualityGate = new QualityGateEvaluator(); + var log = new FilteredLog(); + var result = evaluate(List.of(), new IssuesStatisticsBuilder(), log); - assertThat(qualityGate.evaluate(builder.build(), logger)).isEqualTo(QualityGateStatus.INACTIVE); - - assertThat(logger.getMessages()).containsExactly( - "-> INACTIVE - No quality gate defined"); + assertThat(result.getOverallStatus()) + .isEqualTo(io.jenkins.plugins.util.QualityGateStatus.INACTIVE); + assertThat(log.getInfoMessages()) + .containsExactly("No quality gates have been set - skipping"); } @Test void shouldHandleNegativeDeltaValues() { - Logger logger = new Logger(); + List qualityGates = new ArrayList<>(); + qualityGates.add(addQualityGate(1, QualityGateType.DELTA, QualityGateCriticality.UNSTABLE)); - IssuesStatisticsBuilder builder = new IssuesStatisticsBuilder(); + IssuesStatisticsBuilder builder = new IssuesStatisticsBuilder().setDeltaErrorSize(-1); - QualityGateEvaluator qualityGate = new QualityGateEvaluator(); + var result = evaluate(qualityGates, builder, new FilteredLog()); - qualityGate.add(1, QualityGateType.DELTA, QualityGateResult.UNSTABLE); - assertThat(qualityGate.evaluate(builder.setDeltaErrorSize(-1).build(), logger)).isEqualTo(QualityGateStatus.PASSED); - assertThat(logger.getMessages()).containsExactly( - "-> PASSED - " + QualityGateType.DELTA.getDisplayName() + ": -1 - Quality Gate: 1"); + assertThat(result.getOverallStatus()).isEqualTo(io.jenkins.plugins.util.QualityGateStatus.PASSED); + assertThat(result.getMessages()).hasSize(1).first().asString() + .contains("≪Success≫", QualityGateType.DELTA.getDisplayName(), "Actual value: -1", "Quality gate: 1.00"); } @Test void shouldPassIfSizesAreZero() { - Logger logger = new Logger(); + List qualityGates = new ArrayList<>(); + qualityGates.add(addQualityGate(1, QualityGateType.TOTAL, QualityGateCriticality.UNSTABLE)); IssuesStatisticsBuilder builder = new IssuesStatisticsBuilder(); - QualityGateEvaluator qualityGate = new QualityGateEvaluator(); + var result = evaluate(qualityGates, builder, new FilteredLog()); + assertThat(result.getOverallStatus()).isEqualTo(io.jenkins.plugins.util.QualityGateStatus.PASSED); + assertThat(result.getMessages()).hasSize(1).first().asString() + .contains("≪Success≫", QualityGateType.TOTAL.getDisplayName(), "Actual value: 0", "Quality gate: 1.00"); - qualityGate.add(1, QualityGateType.TOTAL, QualityGateResult.UNSTABLE); - assertThat(qualityGate.evaluate(builder.build(), logger)).isEqualTo(QualityGateStatus.PASSED); - assertThat(logger.getMessages()).containsExactly( - "-> PASSED - " + QualityGateType.TOTAL.getDisplayName() + ": 0 - Quality Gate: 1"); + qualityGates.add(addQualityGate(1, QualityGateType.NEW, QualityGateCriticality.UNSTABLE)); - logger.clear(); - qualityGate.add(1, QualityGateType.NEW, QualityGateResult.UNSTABLE); - assertThat(qualityGate.evaluate(builder.build(), logger)).isEqualTo(QualityGateStatus.PASSED); - assertThat(logger.getMessages()).containsExactly( - "-> PASSED - " + QualityGateType.TOTAL.getDisplayName() + ": 0 - Quality Gate: 1", - "-> PASSED - " + QualityGateType.NEW.getDisplayName() + ": 0 - Quality Gate: 1"); + result = evaluate(qualityGates, builder, new FilteredLog()); + assertThat(result.getOverallStatus()).isEqualTo(io.jenkins.plugins.util.QualityGateStatus.PASSED); + assertThat(result.getMessages()).hasSize(2).first().asString() + .contains("≪Success≫", QualityGateType.TOTAL.getDisplayName(), "Actual value: 0", "Quality gate: 1.00"); + assertThat(result.getMessages()).hasSize(2).last().asString() + .contains("≪Success≫", QualityGateType.NEW.getDisplayName(), "Actual value: 0", "Quality gate: 1.00"); } @Test @@ -95,107 +94,125 @@ private void evaluateQualityGateFor(final IssuesStatisticsBuilder builder, final QualityGateType type) { builder.clear(); - Logger logger = new Logger(); + List qualityGates = new ArrayList<>(); + qualityGates.add(addQualityGate(1, type, QualityGateCriticality.UNSTABLE)); - QualityGateEvaluator qualityGate = new QualityGateEvaluator(); + var result = evaluate(qualityGates, builder, new FilteredLog()); + assertThat(result.getOverallStatus()).isEqualTo(io.jenkins.plugins.util.QualityGateStatus.PASSED); + assertThat(result.getMessages()).hasSize(1).first().asString() + .contains("≪Success≫", type.getDisplayName(), "Actual value: 0", "Quality gate: 1.00"); - qualityGate.add(1, type, QualityGateResult.UNSTABLE); - - assertThat(qualityGate.evaluate(builder.build(), logger)).isEqualTo(QualityGateStatus.PASSED); - assertThat(logger.getMessages()).containsExactly( - "-> PASSED - " + type.getDisplayName() + ": 0 - Quality Gate: 1"); - - logger.clear(); setter.apply(1); - assertThat(qualityGate.evaluate(builder.build(), logger)).isEqualTo(QualityGateStatus.WARNING); - assertThat(logger.getMessages()).containsExactly( - "-> WARNING - " + type.getDisplayName() + ": 1 - Quality Gate: 1"); + result = evaluate(qualityGates, builder, new FilteredLog()); + assertThat(result.getOverallStatus()).isEqualTo(io.jenkins.plugins.util.QualityGateStatus.WARNING); + assertThat(result.getMessages()).hasSize(1).first().asString() + .contains("≪Unstable≫", type.getDisplayName(), "Actual value: 1", "Quality gate: 1.00"); } @Test void shouldFailIfSizeIsEqual() { - Logger logger = new Logger(); + List qualityGates = new ArrayList<>(); + qualityGates.add(addQualityGate(1, QualityGateType.TOTAL, QualityGateCriticality.UNSTABLE)); IssuesStatisticsBuilder builder = new IssuesStatisticsBuilder(); + builder.setTotalNormalSize(1); + + var result = evaluate(qualityGates, builder, new FilteredLog()); + + assertThat(result.getOverallStatus()).isEqualTo(io.jenkins.plugins.util.QualityGateStatus.WARNING); + assertThat(result.getMessages()).hasSize(1).first().asString() + .contains("≪Unstable≫", QualityGateType.TOTAL.getDisplayName(), "Actual value: 1", "Quality gate: 1.00"); - QualityGateEvaluator qualityGate = new QualityGateEvaluator(); + qualityGates.add(addQualityGate(1, QualityGateType.NEW, QualityGateCriticality.UNSTABLE)); + builder.setNewNormalSize(1); - qualityGate.add(1, QualityGateType.TOTAL, QualityGateResult.UNSTABLE); - assertThat(qualityGate.evaluate(builder.setTotalNormalSize(1).build(), logger)).isEqualTo(QualityGateStatus.WARNING); - assertThat(logger.getMessages()).containsExactly( - "-> WARNING - " + QualityGateType.TOTAL.getDisplayName() + ": 1 - Quality Gate: 1"); + result = evaluate(qualityGates, builder, new FilteredLog()); - logger.clear(); - qualityGate.add(1, QualityGateType.NEW, QualityGateResult.UNSTABLE); - assertThat(qualityGate.evaluate(builder.setNewNormalSize(1).build(), logger)).isEqualTo(QualityGateStatus.WARNING); - assertThat(logger.getMessages()).containsExactly( - "-> WARNING - " + QualityGateType.TOTAL.getDisplayName() + ": 1 - Quality Gate: 1", - "-> WARNING - " + QualityGateType.NEW.getDisplayName() + ": 1 - Quality Gate: 1"); + assertThat(result.getOverallStatus()).isEqualTo(io.jenkins.plugins.util.QualityGateStatus.WARNING); + assertThat(result.getMessages()).hasSize(2).first().asString() + .contains("≪Unstable≫", QualityGateType.TOTAL.getDisplayName(), "Actual value: 1", "Quality gate: 1.00"); + assertThat(result.getMessages()).hasSize(2).last().asString() + .contains("≪Unstable≫", QualityGateType.NEW.getDisplayName(), "Actual value: 1", "Quality gate: 1.00"); + } + + private QualityGateResult evaluate(final List qualityGates, + final IssuesStatisticsBuilder builder, final FilteredLog log) { + return createEvaluator(qualityGates, builder).evaluate(new NullResultHandler(), log); + } + + private WarningsQualityGate addQualityGate(final int threshold, final QualityGateType qualityGateType, + final QualityGateCriticality qualityGateCriticality) { + return new WarningsQualityGate(threshold, qualityGateType, qualityGateCriticality); } @Test void shouldIgnoreThresholdZero() { - Logger logger = new Logger(); + List qualityGates = new ArrayList<>(); + qualityGates.add(addQualityGate(0, QualityGateType.TOTAL, QualityGateCriticality.UNSTABLE)); IssuesStatisticsBuilder builder = new IssuesStatisticsBuilder(); + builder.setTotalNormalSize(1); - QualityGateEvaluator qualityGate = new QualityGateEvaluator(); + var result = evaluate(qualityGates, builder, new FilteredLog()); + assertThat(result.getOverallStatus()).isEqualTo(io.jenkins.plugins.util.QualityGateStatus.INACTIVE); + assertThat(result.getMessages()).hasSize(1).first().asString() + .contains("≪Not built≫", QualityGateType.TOTAL.getDisplayName(), "Actual value: Threshold too small: 0.0", "Quality gate: 0.00"); - qualityGate.add(0, QualityGateType.TOTAL, QualityGateResult.UNSTABLE); - assertThat(qualityGate.evaluate(builder.setTotalNormalSize(1).build(), logger)).isEqualTo(QualityGateStatus.PASSED); - assertThat(logger.getMessages()).isEmpty(); + qualityGates.add(addQualityGate(0, QualityGateType.NEW, QualityGateCriticality.UNSTABLE)); + builder.setNewNormalSize(1); - qualityGate.add(0, QualityGateType.NEW, QualityGateResult.UNSTABLE); - assertThat(qualityGate.evaluate(builder.setNewNormalSize(1).build(), logger)).isEqualTo(QualityGateStatus.PASSED); - assertThat(logger.getMessages()).isEmpty(); + result = evaluate(qualityGates, builder, new FilteredLog()); + + assertThat(result.getOverallStatus()).isEqualTo(io.jenkins.plugins.util.QualityGateStatus.INACTIVE); + assertThat(result.getMessages()).hasSize(2).first().asString() + .contains("≪Not built≫", QualityGateType.TOTAL.getDisplayName(), "Actual value: Threshold too small: 0.0", "Quality gate: 0.00"); + assertThat(result.getMessages()).hasSize(2).last().asString() + .contains("≪Not built≫", QualityGateType.NEW.getDisplayName(), "Actual value: Threshold too small: 0.0", "Quality gate: 0.00"); } @Test void shouldOverrideWarningWithFailure() { - Logger logger = new Logger(); + List qualityGates = new ArrayList<>(); + qualityGates.add(addQualityGate(1, QualityGateType.TOTAL, QualityGateCriticality.UNSTABLE)); + qualityGates.add(addQualityGate(2, QualityGateType.TOTAL, QualityGateCriticality.FAILURE)); IssuesStatisticsBuilder builder = new IssuesStatisticsBuilder(); + builder.setTotalNormalSize(1); - QualityGateEvaluator qualityGate = new QualityGateEvaluator(); + var result = evaluate(qualityGates, builder, new FilteredLog()); + assertThat(result.getOverallStatus()).isEqualTo(io.jenkins.plugins.util.QualityGateStatus.WARNING); + assertThat(result.getMessages()).hasSize(2).first().asString() + .contains("≪Unstable≫", QualityGateType.TOTAL.getDisplayName(), "Actual value: 1", "Quality gate: 1.00"); + assertThat(result.getMessages()).hasSize(2).last().asString() + .contains("≪Success≫", QualityGateType.TOTAL.getDisplayName(), "Actual value: 1", "Quality gate: 2.00"); - qualityGate.add(1, QualityGateType.TOTAL, QualityGateResult.UNSTABLE); - qualityGate.add(2, QualityGateType.TOTAL, QualityGateResult.FAILURE); - assertThat(qualityGate.evaluate(builder.setTotalNormalSize(1).build(), logger)).isEqualTo(QualityGateStatus.WARNING); - assertThat(logger.getMessages()).containsExactly( - "-> WARNING - " + QualityGateType.TOTAL.getDisplayName() + ": 1 - Quality Gate: 1", - "-> PASSED - " + QualityGateType.TOTAL.getDisplayName() + ": 1 - Quality Gate: 2"); + builder.setTotalNormalSize(2); - logger.clear(); - assertThat(qualityGate.evaluate(builder.setTotalNormalSize(2).build(), logger)).isEqualTo(QualityGateStatus.FAILED); - assertThat(logger.getMessages()).containsExactly( - "-> WARNING - " + QualityGateType.TOTAL.getDisplayName() + ": 2 - Quality Gate: 1", - "-> FAILED - " + QualityGateType.TOTAL.getDisplayName() + ": 2 - Quality Gate: 2"); + result = evaluate(qualityGates, builder, new FilteredLog()); - QualityGateEvaluator other = new QualityGateEvaluator(); + assertThat(result.getOverallStatus()).isEqualTo(io.jenkins.plugins.util.QualityGateStatus.FAILED); + assertThat(result.getMessages()).hasSize(2).first().asString() + .contains("≪Unstable≫", QualityGateType.TOTAL.getDisplayName(), "Actual value: 2", "Quality gate: 1.00"); + assertThat(result.getMessages()).hasSize(2).last().asString() + .contains("≪Failed≫", QualityGateType.TOTAL.getDisplayName(), "Actual value: 2", "Quality gate: 2.00"); - other.add(2, QualityGateType.TOTAL, QualityGateResult.FAILURE); - other.add(1, QualityGateType.TOTAL, QualityGateResult.UNSTABLE); - assertThat(other.evaluate(builder.setTotalNormalSize(1).build(), logger)).isEqualTo(QualityGateStatus.WARNING); - assertThat(other.evaluate(builder.setTotalNormalSize(2).build(), logger)).isEqualTo(QualityGateStatus.FAILED); - } + List other = new ArrayList<>(); + other.add(addQualityGate(2, QualityGateType.TOTAL, QualityGateCriticality.FAILURE)); + other.add(addQualityGate(1, QualityGateType.TOTAL, QualityGateCriticality.UNSTABLE)); - /** - * Logger for the tests that provides a way verify and clear the messages. - */ - private static class Logger implements FormattedLogger { - private final List messages = new ArrayList<>(); + builder.setTotalNormalSize(1); + result = evaluate(other, builder, new FilteredLog()); - @Override - public void print(final String format, final Object... args) { - messages.add(String.format(format, args)); - } + assertThat(result.getOverallStatus()).isEqualTo(io.jenkins.plugins.util.QualityGateStatus.WARNING); - List getMessages() { - return messages; - } + builder.setTotalNormalSize(2); + result = evaluate(other, builder, new FilteredLog()); + + assertThat(result.getOverallStatus()).isEqualTo(io.jenkins.plugins.util.QualityGateStatus.FAILED); + } - void clear() { - messages.clear(); - } + private WarningsQualityGateEvaluator createEvaluator( + final List qualityGates, final IssuesStatisticsBuilder builder) { + return new WarningsQualityGateEvaluator(qualityGates, builder.build()); } } diff --git a/plugin/src/test/java/io/jenkins/plugins/analysis/core/util/QualityGateStatusTest.java b/plugin/src/test/java/io/jenkins/plugins/analysis/core/util/QualityGateStatusTest.java deleted file mode 100644 index c1438389b3..0000000000 --- a/plugin/src/test/java/io/jenkins/plugins/analysis/core/util/QualityGateStatusTest.java +++ /dev/null @@ -1,48 +0,0 @@ -package io.jenkins.plugins.analysis.core.util; - -import org.junit.jupiter.api.Test; - -import hudson.model.Result; - -import static io.jenkins.plugins.analysis.core.assertions.Assertions.*; - -/** - * Tests the class {@link QualityGateStatus}. - * - * @author Ullrich Hafner - */ -class QualityGateStatusTest { - @Test - void shouldIdentifySuccessfulStatus() { - assertThat(QualityGateStatus.PASSED).isSuccessful().hasColor(Result.SUCCESS.color); - assertThat(QualityGateStatus.INACTIVE).isSuccessful().hasColor(Result.NOT_BUILT.color); - assertThat(QualityGateStatus.WARNING).isNotSuccessful().hasColor(Result.UNSTABLE.color); - assertThat(QualityGateStatus.FAILED).isNotSuccessful().hasColor(Result.FAILURE.color); - } - - @Test - void shouldDefineOrder() { - assertThat(QualityGateStatus.FAILED.isWorseThan(QualityGateStatus.INACTIVE)).isTrue(); - assertThat(QualityGateStatus.FAILED.isWorseThan(QualityGateStatus.PASSED)).isTrue(); - assertThat(QualityGateStatus.FAILED.isWorseThan(QualityGateStatus.WARNING)).isTrue(); - - assertThat(QualityGateStatus.FAILED.isWorseThan(QualityGateStatus.FAILED)).isFalse(); - - assertThat(QualityGateStatus.WARNING.isWorseThan(QualityGateStatus.INACTIVE)).isTrue(); - assertThat(QualityGateStatus.WARNING.isWorseThan(QualityGateStatus.PASSED)).isTrue(); - - assertThat(QualityGateStatus.WARNING.isWorseThan(QualityGateStatus.FAILED)).isFalse(); - assertThat(QualityGateStatus.WARNING.isWorseThan(QualityGateStatus.WARNING)).isFalse(); - - assertThat(QualityGateStatus.PASSED.isWorseThan(QualityGateStatus.INACTIVE)).isTrue(); - - assertThat(QualityGateStatus.PASSED.isWorseThan(QualityGateStatus.PASSED)).isFalse(); - assertThat(QualityGateStatus.PASSED.isWorseThan(QualityGateStatus.FAILED)).isFalse(); - assertThat(QualityGateStatus.PASSED.isWorseThan(QualityGateStatus.WARNING)).isFalse(); - - assertThat(QualityGateStatus.INACTIVE.isWorseThan(QualityGateStatus.INACTIVE)).isFalse(); - assertThat(QualityGateStatus.INACTIVE.isWorseThan(QualityGateStatus.PASSED)).isFalse(); - assertThat(QualityGateStatus.INACTIVE.isWorseThan(QualityGateStatus.FAILED)).isFalse(); - assertThat(QualityGateStatus.INACTIVE.isWorseThan(QualityGateStatus.WARNING)).isFalse(); - } -} diff --git a/plugin/src/test/java/io/jenkins/plugins/analysis/core/util/QualityGateTest.java b/plugin/src/test/java/io/jenkins/plugins/analysis/core/util/QualityGateTest.java index 0aab4017bc..f49f5cc327 100644 --- a/plugin/src/test/java/io/jenkins/plugins/analysis/core/util/QualityGateTest.java +++ b/plugin/src/test/java/io/jenkins/plugins/analysis/core/util/QualityGateTest.java @@ -7,12 +7,13 @@ import hudson.model.BuildableItem; import hudson.model.Item; -import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateDescriptor; -import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateResult; -import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateType; +import io.jenkins.plugins.analysis.core.util.WarningsQualityGate.QualityGateType; +import io.jenkins.plugins.analysis.core.util.WarningsQualityGate.WarningsQualityGateDescriptor; import io.jenkins.plugins.util.JenkinsFacade; +import io.jenkins.plugins.util.QualityGate; +import io.jenkins.plugins.util.QualityGate.QualityGateCriticality; -import static io.jenkins.plugins.analysis.core.testutil.Assertions.*; +import static io.jenkins.plugins.analysis.core.testutil.FormValidationAssert.*; import static org.mockito.Mockito.*; /** @@ -20,13 +21,13 @@ * * @author Ullrich Hafner */ -class QualityGateTest extends SerializableTest { +class QualityGateTest extends SerializableTest { @Test void shouldValidateThreshold() { JenkinsFacade jenkinsFacade = mock(JenkinsFacade.class); when(jenkinsFacade.hasPermission(Item.CONFIGURE, (BuildableItem) null)).thenReturn(true); - QualityGateDescriptor descriptor = new QualityGateDescriptor(jenkinsFacade); + WarningsQualityGateDescriptor descriptor = new WarningsQualityGateDescriptor(jenkinsFacade); assertThat(descriptor.doCheckThreshold(null, 0)) .isError() @@ -40,7 +41,10 @@ void shouldValidateThreshold() { } @Override - protected QualityGate createSerializable() { - return new QualityGate(1, QualityGateType.TOTAL, QualityGateResult.UNSTABLE); + protected WarningsQualityGate createSerializable() { + var qualityGate = new WarningsQualityGate(QualityGateType.TOTAL); + qualityGate.setCriticality(QualityGateCriticality.UNSTABLE); + qualityGate.setIntegerThreshold(1); + return qualityGate; } } diff --git a/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/integrations/ConfigurationAsCodeITest.java b/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/integrations/ConfigurationAsCodeITest.java index a35f25b924..4f8f485e78 100644 --- a/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/integrations/ConfigurationAsCodeITest.java +++ b/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/integrations/ConfigurationAsCodeITest.java @@ -8,9 +8,7 @@ import hudson.model.FreeStyleProject; import hudson.model.TopLevelItem; -import io.jenkins.plugins.analysis.core.model.SourceDirectory; import io.jenkins.plugins.analysis.core.model.Tool; -import io.jenkins.plugins.analysis.core.model.WarningsPluginConfiguration; import io.jenkins.plugins.analysis.core.steps.IssuesRecorder; import io.jenkins.plugins.analysis.core.testutil.IntegrationTestWithJenkinsPerTest; import io.jenkins.plugins.analysis.warnings.Java; @@ -48,19 +46,6 @@ void shouldImportParserSettingsFromYaml() { assertThat(parser.getScript()).isEqualTo("script"); } - /** - * Reads the YAML file with permitted source code directories and verifies that the directories have been loaded. - */ - @Test - void shouldImportSourceDirectoriesFromYaml() { - configureJenkins("sourceDirectories.yaml"); - - List parsers = WarningsPluginConfiguration.getInstance().getSourceDirectories(); - assertThat(parsers.stream().map(SourceDirectory::getPath)) - .hasSize(2) - .containsExactlyInAnyOrder("C:\\Windows", "/absolute"); - } - /** * Reads the YAML file with a freestyle job and verifies that the job has been created. */ diff --git a/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/integrations/FlexiblePublishITest.java b/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/integrations/FlexiblePublishITest.java index 9b5d5498ac..93877c0ac1 100644 --- a/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/integrations/FlexiblePublishITest.java +++ b/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/integrations/FlexiblePublishITest.java @@ -20,11 +20,12 @@ import io.jenkins.plugins.analysis.core.model.AnalysisResult; import io.jenkins.plugins.analysis.core.steps.IssuesRecorder; import io.jenkins.plugins.analysis.core.testutil.IntegrationTestWithJenkinsPerSuite; -import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateResult; -import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateType; -import io.jenkins.plugins.analysis.core.util.QualityGateStatus; +import io.jenkins.plugins.analysis.core.util.WarningsQualityGate; +import io.jenkins.plugins.analysis.core.util.WarningsQualityGate.QualityGateType; import io.jenkins.plugins.analysis.warnings.CheckStyle; import io.jenkins.plugins.analysis.warnings.Java; +import io.jenkins.plugins.util.QualityGate.QualityGateCriticality; +import io.jenkins.plugins.util.QualityGateStatus; import static io.jenkins.plugins.analysis.core.assertions.Assertions.*; @@ -48,14 +49,16 @@ void shouldAnalyseTwoToolsWithDifferentSettings() { checkStyle.setPattern("**/checkstyle*"); IssuesRecorder checkStyleRecorder = new IssuesRecorder(); checkStyleRecorder.setTools(checkStyle); - checkStyleRecorder.addQualityGate(6, QualityGateType.TOTAL, QualityGateResult.FAILURE); + checkStyleRecorder.setQualityGates(List.of( + new WarningsQualityGate(6, QualityGateType.TOTAL, QualityGateCriticality.FAILURE))); Java java = new Java(); java.setPattern("**/java*"); IssuesRecorder javaRecorder = new IssuesRecorder(); javaRecorder.setTools(java); javaRecorder.setEnabledForFailure(true); - javaRecorder.addQualityGate(2, QualityGateType.TOTAL, QualityGateResult.UNSTABLE); + javaRecorder.setQualityGates(List.of( + new WarningsQualityGate(2, QualityGateType.TOTAL, QualityGateCriticality.UNSTABLE))); project.getPublishersList().add(new FlexiblePublisher(Arrays.asList( constructConditionalPublisher(checkStyleRecorder), diff --git a/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/integrations/JobDslITest.java b/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/integrations/JobDslITest.java index 1eb6509b2a..0d4fecd15c 100644 --- a/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/integrations/JobDslITest.java +++ b/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/integrations/JobDslITest.java @@ -15,9 +15,11 @@ import io.jenkins.plugins.analysis.core.steps.IssuesRecorder; import io.jenkins.plugins.analysis.core.testutil.IntegrationTestWithJenkinsPerTest; import io.jenkins.plugins.analysis.core.util.TrendChartType; +import io.jenkins.plugins.analysis.core.util.WarningsQualityGate.QualityGateType; import io.jenkins.plugins.analysis.warnings.Java; import io.jenkins.plugins.casc.ConfigurationAsCode; import io.jenkins.plugins.casc.ConfiguratorException; +import io.jenkins.plugins.util.QualityGate.QualityGateCriticality; import static org.assertj.core.api.Assertions.*; @@ -107,12 +109,15 @@ void shouldCreateFreestyleJobUsingJobDslAndVerifyIssueRecorderWithValuesSet() { assertThat(recorder.getSourceCodeEncoding()).isEqualTo("UTF-8"); assertThat(recorder.getUnhealthy()).isEqualTo(50); assertThat(recorder.getReferenceJobName()).isEqualTo("test-job"); - assertThat(recorder.getQualityGates()).hasSize(1); + assertThat(recorder.getQualityGates()).hasSize(1) + .first().satisfies(gate -> { + assertThat(gate.getThreshold()).isEqualTo(10.0); + assertThat(gate.getType()).isEqualTo(QualityGateType.TOTAL); + assertThat(gate.getCriticality()).isEqualTo(QualityGateCriticality.FAILURE); + }); List tools = recorder.getTools(); - assertThat(tools).hasSize(2); - assertThat(tools.get(0)).isInstanceOf(Java.class); - + assertThat(tools).hasSize(2).first().isInstanceOf(Java.class); } /** diff --git a/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/AffectedFilesResolverITest.java b/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/AffectedFilesResolverITest.java index ebfbc79869..cca4b2b59d 100644 --- a/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/AffectedFilesResolverITest.java +++ b/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/AffectedFilesResolverITest.java @@ -25,8 +25,6 @@ import io.jenkins.plugins.analysis.core.model.IssuesDetail; import io.jenkins.plugins.analysis.core.model.IssuesModel.IssuesRow; import io.jenkins.plugins.analysis.core.model.ResultAction; -import io.jenkins.plugins.analysis.core.model.SourceDirectory; -import io.jenkins.plugins.analysis.core.model.WarningsPluginConfiguration; import io.jenkins.plugins.analysis.core.steps.IssuesRecorder; import io.jenkins.plugins.analysis.core.testutil.IntegrationTestWithJenkinsPerSuite; import io.jenkins.plugins.analysis.core.util.AffectedFilesResolver; @@ -35,6 +33,7 @@ import io.jenkins.plugins.prism.PermittedSourceCodeDirectory; import io.jenkins.plugins.prism.PrismConfiguration; import io.jenkins.plugins.prism.SourceCodeDirectory; +import io.jenkins.plugins.prism.SourceCodeRetention; import static org.assertj.core.api.Assertions.*; @@ -53,6 +52,7 @@ class AffectedFilesResolverITest extends IntegrationTestWithJenkinsPerSuite { private static final String ECLIPSE_REPORT = FOLDER + "/eclipseOneAffectedAndThreeNotExistingFiles.txt"; private static final String ECLIPSE_REPORT_ONE_AFFECTED_AFFECTED_FILE = FOLDER + "/eclipseOneAffectedFile.txt"; private static final int ROW_NUMBER_ACTUAL_AFFECTED_FILE = 0; + private static final String COPY_FILES = "Copying affected files to Jenkins' build folder"; /** * Verifies that the affected source code is copied and shown in the source code view. If the file is deleted in the @@ -78,8 +78,8 @@ private FreeStyleProject createEclipseProject() { return project; } - private void enableEclipseWarnings(final FreeStyleProject project) { - enableWarnings(project, createTool(new Eclipse(), "**/*.txt")); + private IssuesRecorder enableEclipseWarnings(final FreeStyleProject project) { + return enableWarnings(project, createTool(new Eclipse(), "**/*.txt")); } private FreeStyleProject getJobWithWorkspaceFiles() { @@ -223,14 +223,13 @@ void shouldShowFileOutsideWorkspaceIfConfigured() { buildAndVerifyFilesResolving(job, ColumnLink.SHOULD_NOT_HAVE_LINK, "0 copied", "1 not in workspace", "0 not-found", "0 with I/O error"); // Use source directories of old Warnings plugin configuration - WarningsPluginConfiguration.getInstance().setSourceDirectories( - Collections.singletonList(new SourceDirectory(buildsFolder))); + PrismConfiguration.getInstance().setSourceDirectories( + Collections.singletonList(new PermittedSourceCodeDirectory(buildsFolder))); // Second build: copying the affected file is permitted buildAndVerifyFilesResolving(job, ColumnLink.SHOULD_HAVE_LINK, "1 copied", "0 not in workspace", "0 not-found", "0 with I/O error"); - // Use source directories of new Prism plugin configuration - WarningsPluginConfiguration.getInstance().setSourceDirectories(new ArrayList<>()); + PrismConfiguration.getInstance().setSourceDirectories(new ArrayList<>()); // Third build: copying the affected file is forbidden again buildAndVerifyFilesResolving(job, ColumnLink.SHOULD_NOT_HAVE_LINK, "0 copied", "1 not in workspace", "0 not-found", "0 with I/O error"); @@ -242,12 +241,39 @@ void shouldShowFileOutsideWorkspaceIfConfigured() { buildAndVerifyFilesResolving(job, ColumnLink.SHOULD_HAVE_LINK, "1 copied", "0 not in workspace", "0 not-found", "0 with I/O error"); } - private void buildAndVerifyFilesResolving(final FreeStyleProject job, final ColumnLink columnLink, + @Test + void shouldDeleteSourceCodeFilesOfPreviousBuilds() { + FreeStyleProject job = createFreeStyleProject(); + prepareGccLog(job); + + IssuesRecorder recorder = enableWarnings(job, createTool(new Gcc4(), "**/gcc.log")); + recorder.setSourceCodeRetention(SourceCodeRetention.LAST_BUILD); + + String buildsFolder = job.getRootDir().getAbsolutePath(); + + PrismConfiguration.getInstance().setSourceDirectories( + Collections.singletonList(new PermittedSourceCodeDirectory(buildsFolder))); + + Run first = buildAndVerifyFilesResolving(job, ColumnLink.SHOULD_HAVE_LINK, + "1 copied", "0 not in workspace", "0 not-found", "0 with I/O error"); + Run second = buildAndVerifyFilesResolving(job, ColumnLink.SHOULD_HAVE_LINK, + "1 copied", "0 not in workspace", "0 not-found", "0 with I/O error"); + + verifyResolving(ColumnLink.SHOULD_NOT_HAVE_LINK, getAnalysisResult(first)); + assertThat(getConsoleLog(second)).contains("Deleting source code files of build #1"); + } + + private Run buildAndVerifyFilesResolving(final FreeStyleProject job, final ColumnLink columnLink, final String... expectedResolveMessages) { AnalysisResult result = scheduleBuildAndAssertStatus(job, Result.SUCCESS); - assertThat(getConsoleLog(result)).contains(expectedResolveMessages); + verifyResolving(columnLink, result); + + return result.getOwner(); + } + + private void verifyResolving(final ColumnLink columnLink, final AnalysisResult result) { assertThat(result.getIssues()).hasSize(1); IssuesRow firstRow = getIssuesModel(result, 0); @@ -284,14 +310,25 @@ private void prepareGccLog(final FreeStyleProject job) { } } - /** - * Verifies that the {@link AffectedFilesResolver} can find one existing file. - */ @Test void shouldFindOneAffectedFile() { AnalysisResult result = buildEclipseProject(ECLIPSE_REPORT_ONE_AFFECTED_AFFECTED_FILE, SOURCE_AFFECTED_FILE); - assertThat(getConsoleLog(result)).contains("1 copied", "0 not-found", "0 with I/O error"); + assertThat(getConsoleLog(result)) + .contains(COPY_FILES, "1 copied", "0 not-found", "0 with I/O error"); + } + + @Test + void shouldSkipStoringOfAffectedFiles() { + FreeStyleProject project = createFreeStyleProject(); + copyMultipleFilesToWorkspace(project, ECLIPSE_REPORT_ONE_AFFECTED_AFFECTED_FILE, SOURCE_AFFECTED_FILE); + var recorder = enableEclipseWarnings(project); + recorder.setSourceCodeRetention(SourceCodeRetention.NEVER); + + AnalysisResult result = scheduleBuildAndAssertStatus(project, Result.SUCCESS); + + assertThat(getConsoleLog(result)) + .doesNotContain(COPY_FILES, " copied", " not-found", " with I/O error"); } private AnalysisResult buildEclipseProject(final String... files) { diff --git a/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/DryITest.java b/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/DryITest.java index 55b4975240..ee570eb49c 100644 --- a/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/DryITest.java +++ b/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/DryITest.java @@ -13,12 +13,12 @@ import io.jenkins.plugins.analysis.core.model.IssuesDetail; import io.jenkins.plugins.analysis.core.model.ResultAction; import io.jenkins.plugins.analysis.core.testutil.IntegrationTestWithJenkinsPerSuite; -import io.jenkins.plugins.analysis.core.util.QualityGateStatus; import io.jenkins.plugins.analysis.warnings.Cpd; import io.jenkins.plugins.analysis.warnings.DuplicateCodeScanner; import io.jenkins.plugins.analysis.warnings.DuplicateCodeScanner.DryModel.DuplicationRow; import io.jenkins.plugins.datatables.TableColumn; import io.jenkins.plugins.datatables.TableModel; +import io.jenkins.plugins.util.QualityGateStatus; import static io.jenkins.plugins.analysis.core.assertions.Assertions.*; @@ -40,7 +40,7 @@ class DryITest extends IntegrationTestWithJenkinsPerSuite { private static final String CPD_REPORT = FOLDER + "cpd.xml"; /** - * Verifies that the right amount of duplicate code warnings are detected. + * Verifies that the right number of duplicate code warnings is detected. */ @Test void shouldHaveDuplicateCodeWarnings() { @@ -61,7 +61,7 @@ void shouldHaveDuplicateCodeWarnings() { } /** - * Verifies that the priority of the duplicate code warnings are changed corresponding to the defined thresholds for + * Verifies that the priority of the duplicate code warnings is changed corresponding to the defined thresholds for * cpd warnings. */ @Test @@ -115,7 +115,7 @@ void shouldConfigureSeverityThresholdTo5InJobConfigurationForCpd() { } /** - * Verifies that the priority of the duplicate code warnings are changed corresponding to the defined thresholds for + * Verifies that the priority of the duplicate code warnings is changed corresponding to the defined thresholds for * cpd warnings. */ @Test @@ -179,7 +179,7 @@ void shouldDifferInAmountOfDuplicateWarningForPriorities() { } private TableModel getDryTableModel(final Run build) { - IssuesDetail issuesDetail = (IssuesDetail) build.getAction(ResultAction.class).getTarget(); + IssuesDetail issuesDetail = build.getAction(ResultAction.class).getTarget(); return issuesDetail.getTableModel("issues"); } diff --git a/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/FilesScannerITest.java b/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/FilesScannerITest.java index 0d2b740df6..ec2545fd00 100644 --- a/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/FilesScannerITest.java +++ b/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/FilesScannerITest.java @@ -5,6 +5,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.List; import org.junit.jupiter.api.Test; import org.opentest4j.TestAbortedException; @@ -18,10 +19,11 @@ import io.jenkins.plugins.analysis.core.model.IssueReportScanner; import io.jenkins.plugins.analysis.core.steps.IssuesRecorder; import io.jenkins.plugins.analysis.core.testutil.IntegrationTestWithJenkinsPerSuite; -import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateResult; -import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateType; -import io.jenkins.plugins.analysis.core.util.QualityGateStatus; +import io.jenkins.plugins.analysis.core.util.WarningsQualityGate; +import io.jenkins.plugins.analysis.core.util.WarningsQualityGate.QualityGateType; import io.jenkins.plugins.analysis.warnings.CheckStyle; +import io.jenkins.plugins.util.QualityGate.QualityGateCriticality; +import io.jenkins.plugins.util.QualityGateStatus; import static io.jenkins.plugins.analysis.core.assertions.Assertions.*; import static org.assertj.core.api.Assumptions.*; @@ -126,7 +128,8 @@ void filePatternDoesNotMatchAnyFile() { void findIssuesWithMultipleFiles() { FreeStyleProject project = createJobWithWorkspaceFile(MULTIPLE_FILES_WORKSPACE); IssuesRecorder recorder = enableWarnings(project, createTool(new CheckStyle(), "*.xml")); - recorder.addQualityGate(6, QualityGateType.TOTAL, QualityGateResult.FAILURE); + recorder.setQualityGates(List.of( + new WarningsQualityGate(6, QualityGateType.TOTAL, QualityGateCriticality.FAILURE))); AnalysisResult result = scheduleBuildAndAssertStatus(project, Result.FAILURE); @@ -163,7 +166,8 @@ void findIssuesWithMultipleFilesReachableWithSymbolicLinks() { createSymbolicLinkAssumingSupported(realPath, subdirPath.resolve("link_to_actual_files")); IssuesRecorder recorder = enableWarnings(project, createTool(new CheckStyle(), false)); - recorder.addQualityGate(6, QualityGateType.TOTAL, QualityGateResult.FAILURE); + recorder.setQualityGates(List.of( + new WarningsQualityGate(6, QualityGateType.TOTAL, QualityGateCriticality.FAILURE))); AnalysisResult result = scheduleBuildAndAssertStatus(project, Result.FAILURE); @@ -202,13 +206,16 @@ void findNoIssuesWithMultipleFilesReachableWithSymlinksWithSkipSymbolicLinks() { createSymbolicLinkAssumingSupported(realPath, subdirPath.resolve("link_to_actual_files")); IssuesRecorder recorder = enableWarnings(project, createTool(new CheckStyle(), true)); - recorder.addQualityGate(6, QualityGateType.TOTAL, QualityGateResult.FAILURE); + recorder.setQualityGates(List.of( + new WarningsQualityGate(6, QualityGateType.TOTAL, QualityGateCriticality.FAILURE))); AnalysisResult result = scheduleBuildAndAssertStatus(project, Result.SUCCESS); assertThat(result).hasTotalSize(0); assertThat(result).hasInfoMessages( - "-> PASSED - Total (any severity): 0 - Quality Gate: 6"); + "-> All quality gates have been passed", + "-> Details for each quality gate:", + " - [Total (any severity)]: ≪Success≫ - (Actual value: 0, Quality gate: 6.00)"); } private AnalysisModelParser createTool(final AnalysisModelParser tool, final boolean skipSymbolicLinks) { diff --git a/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/MiscIssuesRecorderITest.java b/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/MiscIssuesRecorderITest.java index afdb10d8a4..e00c109135 100644 --- a/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/MiscIssuesRecorderITest.java +++ b/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/MiscIssuesRecorderITest.java @@ -30,7 +30,6 @@ import io.jenkins.plugins.analysis.core.portlets.PullRequestMonitoringPortlet; import io.jenkins.plugins.analysis.core.steps.IssuesRecorder; import io.jenkins.plugins.analysis.core.testutil.IntegrationTestWithJenkinsPerSuite; -import io.jenkins.plugins.analysis.core.util.QualityGateStatus; import io.jenkins.plugins.analysis.warnings.CheckStyle; import io.jenkins.plugins.analysis.warnings.Eclipse; import io.jenkins.plugins.analysis.warnings.FindBugs; @@ -38,6 +37,7 @@ import io.jenkins.plugins.analysis.warnings.Pmd; import io.jenkins.plugins.analysis.warnings.RegisteredParser; import io.jenkins.plugins.analysis.warnings.tasks.OpenTasks; +import io.jenkins.plugins.util.QualityGateStatus; import static io.jenkins.plugins.analysis.core.assertions.Assertions.*; import static net.javacrumbs.jsonunit.assertj.JsonAssertions.*; diff --git a/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/QualityGateITest.java b/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/QualityGateITest.java index ab6ffbdf56..4579ea98a2 100644 --- a/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/QualityGateITest.java +++ b/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/QualityGateITest.java @@ -1,5 +1,6 @@ package io.jenkins.plugins.analysis.warnings.steps; +import java.util.List; import java.util.Map; import java.util.function.Consumer; @@ -9,6 +10,8 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; +import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; +import org.jenkinsci.plugins.workflow.job.WorkflowJob; import hudson.model.AbstractProject; import hudson.model.FreeStyleProject; import hudson.model.Result; @@ -19,26 +22,49 @@ import io.jenkins.plugins.analysis.core.portlets.PullRequestMonitoringPortlet; import io.jenkins.plugins.analysis.core.steps.IssuesRecorder; import io.jenkins.plugins.analysis.core.testutil.IntegrationTestWithJenkinsPerSuite; -import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateResult; -import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateType; -import io.jenkins.plugins.analysis.core.util.QualityGateEvaluator; -import io.jenkins.plugins.analysis.core.util.QualityGateStatus; +import io.jenkins.plugins.analysis.core.util.WarningsQualityGate; +import io.jenkins.plugins.analysis.core.util.WarningsQualityGate.QualityGateType; import io.jenkins.plugins.analysis.warnings.CheckStyle; +import io.jenkins.plugins.util.QualityGate.QualityGateCriticality; +import io.jenkins.plugins.util.QualityGateEvaluator; +import io.jenkins.plugins.util.QualityGateResult.QualityGateResultItem; +import io.jenkins.plugins.util.QualityGateStatus; import static io.jenkins.plugins.analysis.core.assertions.Assertions.*; /** * Tests the {@link QualityGateEvaluator}. The file 'checkstyle-quality-gate.xml' is being used for the tests. It - * contains 11 issues overall, from which 6 have high, 2 have normal and 3 have low severity. + * contains 11 issues overall, from which 6 have high, 2 have normal, and 3 have low severity. * * @author Michaela Reitschuster */ -// TODO: add some tests for severity HIGH class QualityGateITest extends IntegrationTestWithJenkinsPerSuite { private static final Map RESULT_TO_STATUS_MAPPING = Maps.fixedSize.of(Result.UNSTABLE, QualityGateStatus.WARNING, Result.FAILURE, QualityGateStatus.FAILED); private static final String REPORT_FILE = "checkstyle-quality-gate.xml"; + @Test + void shouldUseTwoQualityGates() { + WorkflowJob job = createPipelineWithWorkspaceFilesWithSuffix("checkstyle1.xml", "checkstyle2.xml"); + + job.setDefinition(new CpsFlowDefinition("node {\n" + + " stage ('Integration Test') {\n" + + " recordIssues tools: [checkStyle(pattern: '**/*issues.txt')],\n" + + " qualityGates: [\n" + + " [threshold: 3, type: 'TOTAL', criticality: 'NOTE'],\n" + + " [threshold: 7, type: 'TOTAL', criticality: 'ERROR']]\n" + + " }\n" + + "}", true)); + + AnalysisResult result = scheduleSuccessfulBuild(job); + assertThat(result).hasTotalSize(6); + assertThat(result).hasQualityGateStatus(QualityGateStatus.NOTE); + + assertThat(result.getQualityGateResult().getResultItems()).hasSize(2) + .extracting(QualityGateResultItem::getStatus) + .containsExactly(QualityGateStatus.NOTE, QualityGateStatus.PASSED); + } + /** * Verifies that the first build is always considered stable if the quality gate is set up for delta warnings - even * if there is a warning. @@ -48,7 +74,8 @@ class QualityGateITest extends IntegrationTestWithJenkinsPerSuite { void shouldBePassedForFirstBuildWithDelta() { FreeStyleProject project = createFreeStyleProject(); enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(11, QualityGateType.DELTA, QualityGateResult.UNSTABLE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(11, QualityGateType.DELTA, QualityGateCriticality.UNSTABLE)))); copyMultipleFilesToWorkspaceWithSuffix(project, REPORT_FILE); scheduleBuildAndAssertStatus(project, Result.SUCCESS, QualityGateStatus.PASSED); @@ -62,7 +89,8 @@ void shouldBePassedForFirstBuildWithDelta() { void shouldBePassedForFirstBuildWithNew() { FreeStyleProject project = createFreeStyleProject(); enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(11, QualityGateType.NEW, QualityGateResult.UNSTABLE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(11, QualityGateType.NEW, QualityGateCriticality.UNSTABLE)))); copyMultipleFilesToWorkspaceWithSuffix(project, REPORT_FILE); scheduleBuildAndAssertStatus(project, Result.SUCCESS, QualityGateStatus.PASSED); @@ -76,7 +104,8 @@ void shouldBePassedForFirstBuildWithNew() { void shouldCreateUnstableResult() { FreeStyleProject project = createFreeStyleProjectWithWorkspaceFilesWithSuffix("eclipse.txt"); enableEclipseWarnings(project, - publisher -> publisher.addQualityGate(7, QualityGateType.TOTAL, QualityGateResult.UNSTABLE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(7, QualityGateType.TOTAL, QualityGateCriticality.UNSTABLE)))); AnalysisResult result = scheduleBuildAndAssertStatus(project, Result.UNSTABLE); @@ -91,7 +120,8 @@ void shouldCreateUnstableResult() { void shouldBeUnstableWhenUnstableDeltaAllIsReachedNew() { FreeStyleProject project = createFreeStyleProject(); enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(11, QualityGateType.DELTA, QualityGateResult.UNSTABLE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(11, QualityGateType.DELTA, QualityGateCriticality.UNSTABLE)))); runJobTwice(project, Result.UNSTABLE); } @@ -102,7 +132,8 @@ void shouldBeUnstableWhenUnstableDeltaAllIsReachedNew() { void shouldBeUnstableWhenUnstableNewAllIsReachedNew() { FreeStyleProject project = createFreeStyleProject(); enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(11, QualityGateType.NEW, QualityGateResult.UNSTABLE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(11, QualityGateType.NEW, QualityGateCriticality.UNSTABLE)))); runJobTwice(project, Result.UNSTABLE); } @@ -113,7 +144,8 @@ void shouldBeUnstableWhenUnstableNewAllIsReachedNew() { void shouldBeUnstableWhenUnstableDeltaErrorIsReachedNew() { FreeStyleProject project = createFreeStyleProject(); enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(6, QualityGateType.DELTA_ERROR, QualityGateResult.UNSTABLE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(6, QualityGateType.DELTA_ERROR, QualityGateCriticality.UNSTABLE)))); runJobTwice(project, Result.UNSTABLE); } @@ -125,7 +157,8 @@ void shouldBeUnstableWhenUnstableDeltaErrorIsReachedNew() { void shouldBeUnstableWhenUnstableNewErrorIsReachedNew() { FreeStyleProject project = createFreeStyleProject(); enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(6, QualityGateType.NEW_ERROR, QualityGateResult.UNSTABLE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(6, QualityGateType.NEW_ERROR, QualityGateCriticality.UNSTABLE)))); runJobTwice(project, Result.UNSTABLE); } @@ -136,7 +169,8 @@ void shouldBeUnstableWhenUnstableNewErrorIsReachedNew() { void shouldBeUnstableWhenUnstableDeltaNormalIsReachedNew() { FreeStyleProject project = createFreeStyleProject(); enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(2, QualityGateType.DELTA_NORMAL, QualityGateResult.UNSTABLE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(2, QualityGateType.DELTA_NORMAL, QualityGateCriticality.UNSTABLE)))); runJobTwice(project, Result.UNSTABLE); } @@ -148,7 +182,8 @@ void shouldBeUnstableWhenUnstableDeltaNormalIsReachedNew() { void shouldBeUnstableWhenUnstableNewNormalIsReachedNew() { FreeStyleProject project = createFreeStyleProject(); enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(2, QualityGateType.NEW_NORMAL, QualityGateResult.UNSTABLE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(2, QualityGateType.NEW_NORMAL, QualityGateCriticality.UNSTABLE)))); runJobTwice(project, Result.UNSTABLE); } @@ -160,7 +195,8 @@ void shouldBeUnstableWhenUnstableNewNormalIsReachedNew() { void shouldBeUnstableWhenUnstableDeltaLowIsReachedNew() { FreeStyleProject project = createFreeStyleProject(); enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(3, QualityGateType.DELTA_LOW, QualityGateResult.UNSTABLE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.DELTA_LOW, QualityGateCriticality.UNSTABLE)))); runJobTwice(project, Result.UNSTABLE); } @@ -172,7 +208,8 @@ void shouldBeUnstableWhenUnstableDeltaLowIsReachedNew() { void shouldBeUnstableWhenUnstableNewLowIsReachedNew() { FreeStyleProject project = createFreeStyleProject(); enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(3, QualityGateType.NEW_LOW, QualityGateResult.UNSTABLE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW_LOW, QualityGateCriticality.UNSTABLE)))); runJobTwice(project, Result.UNSTABLE); } @@ -183,7 +220,8 @@ void shouldBeUnstableWhenUnstableNewLowIsReachedNew() { void shouldBeUnstableWhenUnstableTotalAllIsReachedNew() { FreeStyleProject project = createFreeStyleProject(); enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(11, QualityGateType.TOTAL, QualityGateResult.UNSTABLE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(11, QualityGateType.TOTAL, QualityGateCriticality.UNSTABLE)))); runJobTwice(project, Result.UNSTABLE); } @@ -195,7 +233,8 @@ void shouldBeUnstableWhenUnstableTotalAllIsReachedNew() { void shouldBeUnstableWhenUnstableTotalErrorIsReachedNew() { FreeStyleProject project = createFreeStyleProject(); enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(6, QualityGateType.TOTAL_ERROR, QualityGateResult.UNSTABLE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(6, QualityGateType.TOTAL_ERROR, QualityGateCriticality.UNSTABLE)))); runJobTwice(project, Result.UNSTABLE); } @@ -207,7 +246,8 @@ void shouldBeUnstableWhenUnstableTotalErrorIsReachedNew() { void shouldBeUnstableWhenUnstableTotalNormalIsReachedNew() { FreeStyleProject project = createFreeStyleProject(); enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(2, QualityGateType.TOTAL_NORMAL, QualityGateResult.UNSTABLE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(2, QualityGateType.TOTAL_NORMAL, QualityGateCriticality.UNSTABLE)))); runJobTwice(project, Result.UNSTABLE); } @@ -219,7 +259,8 @@ void shouldBeUnstableWhenUnstableTotalNormalIsReachedNew() { void shouldBeUnstableWhenUnstableTotalLowIsReachedNew() { FreeStyleProject project = createFreeStyleProject(); enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(3, QualityGateType.TOTAL_LOW, QualityGateResult.UNSTABLE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.TOTAL_LOW, QualityGateCriticality.UNSTABLE)))); runJobTwice(project, Result.UNSTABLE); } @@ -230,7 +271,8 @@ void shouldBeUnstableWhenUnstableTotalLowIsReachedNew() { void shouldBeFailureWhenFailedNewAllIsReachedNew() { FreeStyleProject project = createFreeStyleProject(); enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(9, QualityGateType.NEW, QualityGateResult.FAILURE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(9, QualityGateType.NEW, QualityGateCriticality.FAILURE)))); runJobTwice(project, Result.FAILURE); } @@ -242,7 +284,8 @@ void shouldBeFailureWhenFailedNewAllIsReachedNew() { void shouldBeFailureWhenFailedNewErrorIsReachedNew() { FreeStyleProject project = createFreeStyleProject(); enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(6, QualityGateType.NEW_ERROR, QualityGateResult.FAILURE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(6, QualityGateType.NEW_ERROR, QualityGateCriticality.FAILURE)))); runJobTwice(project, Result.FAILURE); } @@ -254,7 +297,8 @@ void shouldBeFailureWhenFailedNewErrorIsReachedNew() { void shouldBeFailureWhenFailedNewNormalIsReachedNew() { FreeStyleProject project = createFreeStyleProject(); enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(2, QualityGateType.NEW_NORMAL, QualityGateResult.FAILURE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(2, QualityGateType.NEW_NORMAL, QualityGateCriticality.FAILURE)))); runJobTwice(project, Result.FAILURE); } @@ -266,7 +310,8 @@ void shouldBeFailureWhenFailedNewNormalIsReachedNew() { void shouldBeFailureWhenFailedNewLowIsReachedNew() { FreeStyleProject project = createFreeStyleProject(); enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(3, QualityGateType.NEW_LOW, QualityGateResult.FAILURE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW_LOW, QualityGateCriticality.FAILURE)))); runJobTwice(project, Result.FAILURE); } @@ -277,7 +322,8 @@ void shouldBeFailureWhenFailedNewLowIsReachedNew() { void shouldBeFailureWhenFailureTotalAllIsReachedNew() { FreeStyleProject project = createFreeStyleProject(); enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(11, QualityGateType.TOTAL, QualityGateResult.FAILURE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(11, QualityGateType.TOTAL, QualityGateCriticality.FAILURE)))); runJobTwice(project, Result.FAILURE); } @@ -288,7 +334,8 @@ void shouldBeFailureWhenFailureTotalAllIsReachedNew() { void shouldBeFailureWhenFailureTotalErrorIsReachedNew() { FreeStyleProject project = createFreeStyleProject(); enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(6, QualityGateType.TOTAL_ERROR, QualityGateResult.FAILURE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(6, QualityGateType.TOTAL_ERROR, QualityGateCriticality.FAILURE)))); runJobTwice(project, Result.FAILURE); } @@ -300,7 +347,8 @@ void shouldBeFailureWhenFailureTotalErrorIsReachedNew() { void shouldBeFailureWhenFailureTotalNormalIsReachedNew() { FreeStyleProject project = createFreeStyleProject(); enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(2, QualityGateType.TOTAL_NORMAL, QualityGateResult.FAILURE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(2, QualityGateType.TOTAL_NORMAL, QualityGateCriticality.FAILURE)))); runJobTwice(project, Result.FAILURE); } @@ -311,7 +359,8 @@ void shouldBeFailureWhenFailureTotalNormalIsReachedNew() { void shouldBeFailureWhenFailureTotalLowIsReachedLow() { FreeStyleProject project = createFreeStyleProject(); enableAndConfigureCheckstyle(project, - recorder -> recorder.addQualityGate(3, QualityGateType.TOTAL_LOW, QualityGateResult.FAILURE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.TOTAL_LOW, QualityGateCriticality.FAILURE)))); runJobTwice(project, Result.FAILURE); } @@ -321,10 +370,9 @@ void shouldBeFailureWhenFailureTotalLowIsReachedLow() { @Test void shouldOverrideUnstableWhenFailureAndUnstableThresholdIsReachedNew() { FreeStyleProject project = createFreeStyleProject(); - enableAndConfigureCheckstyle(project, recorder -> { - recorder.addQualityGate(1, QualityGateType.TOTAL, QualityGateResult.UNSTABLE); - recorder.addQualityGate(3, QualityGateType.TOTAL_LOW, QualityGateResult.FAILURE); - }); + enableAndConfigureCheckstyle(project, recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(1, QualityGateType.TOTAL, QualityGateCriticality.UNSTABLE), + new WarningsQualityGate(3, QualityGateType.TOTAL_LOW, QualityGateCriticality.FAILURE)))); runJobTwice(project, Result.FAILURE); } @@ -361,7 +409,7 @@ private void scheduleBuildAndAssertStatus(final AbstractProject job, final try { Run build = getJenkins().assertBuildStatus(result, job.scheduleBuild2(0)); ResultAction action = build.getAction(ResultAction.class); - assertThat(action.getResult()).hasQualityGateStatus(expectedQualityGateStatus); + assertThat(action.getResult().getQualityGateResult().getOverallStatus()).isEqualTo(expectedQualityGateStatus); PullRequestMonitoringPortlet portlet = new PullRequestMonitoringPortlet(action); assertThat(portlet.hasQualityGate()).isTrue(); diff --git a/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/ReferenceFinderITest.java b/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/ReferenceFinderITest.java index 0d7d1bcc6a..e76b9aa276 100644 --- a/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/ReferenceFinderITest.java +++ b/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/ReferenceFinderITest.java @@ -1,5 +1,6 @@ package io.jenkins.plugins.analysis.warnings.steps; +import java.util.List; import java.util.Optional; import java.util.function.Consumer; @@ -18,10 +19,11 @@ import io.jenkins.plugins.analysis.core.model.ResetQualityGateCommand; import io.jenkins.plugins.analysis.core.steps.IssuesRecorder; import io.jenkins.plugins.analysis.core.testutil.IntegrationTestWithJenkinsPerTest; -import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateResult; -import io.jenkins.plugins.analysis.core.util.QualityGate.QualityGateType; -import io.jenkins.plugins.analysis.core.util.QualityGateStatus; +import io.jenkins.plugins.analysis.core.util.WarningsQualityGate; +import io.jenkins.plugins.analysis.core.util.WarningsQualityGate.QualityGateType; import io.jenkins.plugins.analysis.warnings.Java; +import io.jenkins.plugins.util.QualityGate.QualityGateCriticality; +import io.jenkins.plugins.util.QualityGateStatus; import static io.jenkins.plugins.analysis.core.assertions.Assertions.*; @@ -39,8 +41,8 @@ class ReferenceFinderITest extends IntegrationTestWithJenkinsPerTest { private static final String PUBLISH_ISSUES_STEP = "publishIssues issues:[issues]"; /** - * Creates a reference job and starts a build having 2 warnings. Then two builds for the job. Then another job is created that - * uses the first build as a reference. Verifies that the association is correctly stored. + * Creates a reference job and starts a build having 2 warnings. Then two builds for the job. Then another job is + * created that uses the first build as a reference. Verifies that the association is correctly stored. */ // TODO: The functionality within this test is deprecated and will be removed in a future release @Test @@ -108,8 +110,8 @@ void shouldUseOtherJobAsReference() { } /** - * Creates a reference job without builds, then builds another job, referring to the reference job that does - * not contain a valid build. + * Creates a reference job without builds, then builds another job, referring to the reference job that does not + * contain a valid build. */ @Test void shouldHandleMissingJobBuildAsReference() { @@ -142,7 +144,8 @@ void shouldHandleMissingJobBuildAsReference() { void shouldResetReference() { // #1 SUCCESS FreeStyleProject project = createJob(JOB_NAME, "eclipse2Warnings.txt"); - enableWarnings(project, recorder -> recorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE)); + enableWarnings(project, recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE)))); scheduleBuildAndAssertStatus(project, Result.SUCCESS, analysisResult -> assertThat(analysisResult) .hasTotalSize(2) @@ -206,7 +209,8 @@ void shouldResetReference() { void shouldCreateSuccessResultWithIgnoredUnstableInBetween() { // #1 SUCCESS FreeStyleProject project = createJob(JOB_NAME, "eclipse2Warnings.txt"); - enableWarnings(project, recorder -> recorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE)); + enableWarnings(project, recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE)))); Run expectedReference = scheduleBuildAndAssertStatus(project, Result.SUCCESS, analysisResult -> assertThat(analysisResult) .hasTotalSize(2) @@ -244,7 +248,8 @@ private void createResetAction(final Run unstable, final String id) { void shouldCreateUnstableResultWithIgnoredUnstableInBetween() { // #1 SUCCESS FreeStyleProject project = createJob(JOB_NAME, "eclipse2Warnings.txt"); - enableWarnings(project, recorder -> recorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE)); + enableWarnings(project, recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE)))); Run expectedReference = scheduleBuildAndAssertStatus(project, Result.SUCCESS, analysisResult -> assertThat(analysisResult).hasTotalSize(2) .hasNewSize(0) @@ -275,7 +280,8 @@ void shouldCreateSuccessResultWithNotIgnoredUnstableInBetween() { FreeStyleProject project = createJob(JOB_NAME, "eclipse2Warnings.txt"); enableWarnings(project, recorder -> { recorder.setIgnoreQualityGate(true); - recorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE); + recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE))); }); scheduleBuildAndAssertStatus(project, Result.SUCCESS, analysisResult -> assertThat(analysisResult).hasTotalSize(2) @@ -313,15 +319,17 @@ void shouldCreateUnstableResultWithNotIgnoredUnstableInBetween() { // #2 UNSTABLE cleanAndCopy(project, "eclipse4Warnings.txt"); - issuesRecorder.addQualityGate(3, QualityGateType.TOTAL, QualityGateResult.UNSTABLE); + issuesRecorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.TOTAL, QualityGateCriticality.UNSTABLE))); Run expectedReference = scheduleBuildAndAssertStatus(project, Result.UNSTABLE, analysisResult -> assertThat(analysisResult).hasTotalSize(4) .hasQualityGateStatus(QualityGateStatus.WARNING)).getOwner(); // #3 UNSTABLE (Reference #2) cleanAndCopy(project, "eclipse8Warnings.txt"); - issuesRecorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE); - issuesRecorder.addQualityGate(9, QualityGateType.TOTAL, QualityGateResult.UNSTABLE); + issuesRecorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE), + new WarningsQualityGate(9, QualityGateType.TOTAL, QualityGateCriticality.UNSTABLE))); scheduleBuildAndAssertStatus(project, Result.UNSTABLE, analysisResult -> assertThat(analysisResult) .hasTotalSize(8) @@ -341,7 +349,8 @@ void shouldCreateUnstableResultWithOverAllMustBeSuccess() { enableWarnings(project, recorder -> { recorder.setIgnoreFailedBuilds(true); recorder.setEnabledForFailure(true); - recorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE); + recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE))); }); Run expectedReference = scheduleBuildAndAssertStatus(project, Result.SUCCESS, analysisResult -> assertThat(analysisResult).hasTotalSize(2) @@ -385,7 +394,8 @@ void shouldCreateSuccessResultWithOverAllMustBeSuccess() { // #2 FAILURE cleanAndCopy(project, "eclipse2Warnings.txt"); - issuesRecorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE); + issuesRecorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE))); Builder failureStep = addFailureStep(project); scheduleBuildAndAssertStatus(project, Result.FAILURE, analysisResult -> assertThat(analysisResult).hasTotalSize(2) @@ -421,7 +431,8 @@ void shouldCreateUnstableResultWithOverAllMustNotBeSuccess() { // #2 FAILURE cleanAndCopy(project, "eclipse2Warnings.txt"); - issuesRecorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE); + issuesRecorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE))); Builder failureStep = addFailureStep(project); Run expectedReference = scheduleBuildAndAssertStatus(project, Result.FAILURE, analysisResult -> assertThat(analysisResult).hasTotalSize(2) @@ -450,7 +461,8 @@ void shouldCreateSuccessResultWithOverAllMustNotBeSuccess() { enableWarnings(project, recorder -> { recorder.setIgnoreFailedBuilds(false); recorder.setEnabledForFailure(true); - recorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE); + recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE))); }); scheduleBuildAndAssertStatus(project, Result.SUCCESS, analysisResult -> assertThat(analysisResult).hasTotalSize(2) @@ -484,7 +496,8 @@ void shouldCreateSuccessResultWithIgnoredUnstableInBetweenWithReferenceBuild() { // #1 SUCCESS FreeStyleProject reference = createJob(REFERENCE_JOB_NAME, "eclipse2Warnings.txt"); enableWarnings(reference, - recorder -> recorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE)); + recorder -> recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE)))); Run expectedReference = scheduleBuildAndAssertStatus(reference, Result.SUCCESS, analysisResult -> assertThat(analysisResult).hasTotalSize(2) .hasNewSize(0) @@ -500,9 +513,11 @@ void shouldCreateSuccessResultWithIgnoredUnstableInBetweenWithReferenceBuild() { // #1 SUCCESS (Reference #1) FreeStyleProject project = createJob(JOB_NAME, "eclipse4Warnings.txt"); enableWarnings(project, recorder -> { - recorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE); + recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE))); recorder.setReferenceJobName(REFERENCE_JOB_NAME); - recorder.addQualityGate(7, QualityGateType.TOTAL, QualityGateResult.UNSTABLE); + recorder.setQualityGates(List.of( + new WarningsQualityGate(7, QualityGateType.TOTAL, QualityGateCriticality.UNSTABLE))); }); scheduleBuildAndAssertStatus(project, Result.SUCCESS, analysisResult -> assertThat(analysisResult) .hasTotalSize(4) @@ -520,7 +535,8 @@ void shouldCreateUnstableResultWithIgnoredUnstableInBetweenWithReferenceBuild() // #1 SUCCESS FreeStyleProject reference = createJob(REFERENCE_JOB_NAME, "eclipse2Warnings.txt"); enableWarnings(reference, recorder -> { - recorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE); + recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE))); recorder.setIgnoreQualityGate(false); }); Run expectedReference = scheduleBuildAndAssertStatus(reference, Result.SUCCESS, @@ -538,7 +554,8 @@ void shouldCreateUnstableResultWithIgnoredUnstableInBetweenWithReferenceBuild() // #1 SUCCESS (Reference #1) FreeStyleProject project = createJob(JOB_NAME, "eclipse8Warnings.txt"); enableWarnings(project, recorder -> { - recorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE); + recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE))); recorder.setReferenceJobName(REFERENCE_JOB_NAME); recorder.setIgnoreQualityGate(false); }); @@ -560,7 +577,8 @@ void shouldCreateSuccessResultWithNotIgnoredUnstableInBetweenWithReferenceBuild( FreeStyleProject reference = createJob(REFERENCE_JOB_NAME, "eclipse2Warnings.txt"); enableWarnings(reference, recorder -> { recorder.setIgnoreQualityGate(true); - recorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE); + recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE))); }); scheduleBuildAndAssertStatus(reference, Result.SUCCESS, analysisResult -> assertThat(analysisResult).hasTotalSize(2) @@ -577,7 +595,8 @@ void shouldCreateSuccessResultWithNotIgnoredUnstableInBetweenWithReferenceBuild( // #1 SUCCESS (Reference #2) FreeStyleProject project = createJob(JOB_NAME, "eclipse8Warnings.txt"); enableWarnings(project, recorder -> { - recorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE); + recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE))); recorder.setReferenceJobName(REFERENCE_JOB_NAME); recorder.setIgnoreQualityGate(true); }); @@ -604,7 +623,8 @@ void shouldCreateUnstableResultWithNotIgnoredUnstableInBetweenWithReferenceBuild // #2 UNSTABLE cleanAndCopy(reference, "eclipse4Warnings.txt"); - issuesRecorder.addQualityGate(3, QualityGateType.TOTAL, QualityGateResult.UNSTABLE); + issuesRecorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.TOTAL, QualityGateCriticality.UNSTABLE))); Run expectedReference = scheduleBuildAndAssertStatus(reference, Result.UNSTABLE, analysisResult -> assertThat(analysisResult).hasTotalSize(4) @@ -614,10 +634,11 @@ void shouldCreateUnstableResultWithNotIgnoredUnstableInBetweenWithReferenceBuild // #1 SUCCESS (Reference #2) FreeStyleProject project = createJob(JOB_NAME, "eclipse8Warnings.txt"); enableWarnings(project, recorder -> { - recorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE); + recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE), + new WarningsQualityGate(9, QualityGateType.TOTAL, QualityGateCriticality.UNSTABLE))); recorder.setReferenceJobName(REFERENCE_JOB_NAME); recorder.setIgnoreQualityGate(true); - recorder.addQualityGate(9, QualityGateType.TOTAL, QualityGateResult.UNSTABLE); }); scheduleBuildAndAssertStatus(project, Result.UNSTABLE, analysisResult -> assertThat(analysisResult) .hasTotalSize(8) @@ -637,7 +658,8 @@ void shouldCreateUnstableResultWithOverAllMustBeSuccessWithReferenceBuild() { enableWarnings(reference, recorder -> { recorder.setIgnoreFailedBuilds(true); recorder.setEnabledForFailure(true); - recorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE); + recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE))); }); Run expectedReference = scheduleBuildAndAssertStatus(reference, Result.SUCCESS, analysisResult -> assertThat(analysisResult).hasTotalSize(2) @@ -656,7 +678,8 @@ void shouldCreateUnstableResultWithOverAllMustBeSuccessWithReferenceBuild() { // #1 SUCCESS (Reference #1) FreeStyleProject project = createJob(JOB_NAME, "eclipse6Warnings.txt"); enableWarnings(project, recorder -> { - recorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE); + recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE))); recorder.setReferenceJobName(REFERENCE_JOB_NAME); recorder.setIgnoreFailedBuilds(true); recorder.setEnabledForFailure(true); @@ -687,7 +710,8 @@ void shouldCreateSuccessResultWithOverAllMustBeSuccessWithReferenceBuild() { // #2 FAILURE cleanAndCopy(reference, "eclipse2Warnings.txt"); - issuesRecorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE); + issuesRecorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE))); addFailureStep(reference); scheduleBuildAndAssertStatus(reference, Result.FAILURE, analysisResult -> assertThat(analysisResult).hasTotalSize(2) @@ -697,7 +721,8 @@ void shouldCreateSuccessResultWithOverAllMustBeSuccessWithReferenceBuild() { // #1 SUCCESS (Reference #1) FreeStyleProject project = createJob(JOB_NAME, "eclipse6Warnings.txt"); enableWarnings(project, recorder -> { - recorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE); + recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE))); recorder.setReferenceJobName(REFERENCE_JOB_NAME); recorder.setIgnoreFailedBuilds(true); recorder.setEnabledForFailure(true); @@ -728,7 +753,8 @@ void shouldCreateUnstableResultWithOverAllMustNotBeSuccessWithReferenceBuild() { // #2 FAILURE cleanAndCopy(reference, "eclipse2Warnings.txt"); - issuesRecorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE); + issuesRecorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE))); Builder failureStep = addFailureStep(reference); Run expectedReference = scheduleBuildAndAssertStatus(reference, Result.FAILURE, analysisResult -> assertThat(analysisResult).hasTotalSize(2) @@ -739,7 +765,8 @@ void shouldCreateUnstableResultWithOverAllMustNotBeSuccessWithReferenceBuild() { // #1 UNSTABLE (Reference #2) FreeStyleProject project = createJob(JOB_NAME, "eclipse6Warnings.txt"); enableWarnings(project, recorder -> { - recorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE); + recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE))); recorder.setReferenceJobName(REFERENCE_JOB_NAME); recorder.setIgnoreFailedBuilds(false); recorder.setEnabledForFailure(true); @@ -762,7 +789,8 @@ void shouldCreateSuccessResultWithOverAllMustNotBeSuccessWithReferenceBuild() { enableWarnings(reference, recorder -> { recorder.setIgnoreFailedBuilds(false); recorder.setEnabledForFailure(true); - recorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE); + recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE))); }); scheduleBuildAndAssertStatus(reference, Result.SUCCESS, analysisResult -> assertThat(analysisResult).hasTotalSize(2) @@ -782,7 +810,8 @@ void shouldCreateSuccessResultWithOverAllMustNotBeSuccessWithReferenceBuild() { // #1 UNSTABLE (Reference #2) FreeStyleProject project = createJob(JOB_NAME, "eclipse6Warnings.txt"); enableWarnings(project, recorder -> { - recorder.addQualityGate(3, QualityGateType.NEW, QualityGateResult.UNSTABLE); + recorder.setQualityGates(List.of( + new WarningsQualityGate(3, QualityGateType.NEW, QualityGateCriticality.UNSTABLE))); recorder.setReferenceJobName(REFERENCE_JOB_NAME); recorder.setIgnoreFailedBuilds(false); recorder.setEnabledForFailure(true); diff --git a/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/RemoteApiITest.java b/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/RemoteApiITest.java index 9ae0a1f9f3..2715af5ae6 100644 --- a/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/RemoteApiITest.java +++ b/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/RemoteApiITest.java @@ -48,7 +48,7 @@ class RemoteApiITest extends IntegrationTestWithJenkinsPerSuite { */ @Test void shouldReturnSummaryForTopLevelApiCall() { - // Skip elements with absolute paths or other platform specific information + // Skip elements with absolute paths or other platform-specific information verifyRemoteApi("/checkstyle/api/xml" + "?exclude=/*/errorMessage" + "&exclude=/*/infoMessage" @@ -85,10 +85,14 @@ private void assertThatRemoteApiEquals(final Run build, final String url, void assertXmlApiWithXPathNavigationMatchesExpected() { Run build = buildCheckStyleJob(); - Document actualDocument = callXmlRemoteApi(build.getUrl() + "/checkstyle/api/xml?xpath=/*/qualityGateStatus"); + Document actualDocument = callXmlRemoteApi(build.getUrl() + "/checkstyle/api/xml?xpath=/*/qualityGates"); - assertThat(actualDocument.getDocumentElement().getTagName()).isEqualTo("qualityGateStatus"); - assertThat(actualDocument.getDocumentElement().getFirstChild().getNodeValue()).isEqualTo("INACTIVE"); + var documentElement = actualDocument.getDocumentElement(); + assertThat(documentElement.getTagName()).isEqualTo("qualityGates"); + + var result = documentElement.getFirstChild(); + assertThat(result.getNodeName()).isEqualTo("overallResult"); + assertThat(result.getTextContent()).isEqualTo("INACTIVE"); } /** diff --git a/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/StepsITest.java b/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/StepsITest.java index 6400d1a312..a96e4f1f74 100644 --- a/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/StepsITest.java +++ b/plugin/src/test/java/io/jenkins/plugins/analysis/warnings/steps/StepsITest.java @@ -43,7 +43,6 @@ import io.jenkins.plugins.analysis.core.steps.PublishIssuesStep; import io.jenkins.plugins.analysis.core.steps.ScanForIssuesStep; import io.jenkins.plugins.analysis.core.testutil.IntegrationTestWithJenkinsPerSuite; -import io.jenkins.plugins.analysis.core.util.QualityGateStatus; import io.jenkins.plugins.analysis.warnings.CheckStyle; import io.jenkins.plugins.analysis.warnings.Eclipse; import io.jenkins.plugins.analysis.warnings.FindBugs; @@ -53,6 +52,7 @@ import io.jenkins.plugins.analysis.warnings.Pmd; import io.jenkins.plugins.analysis.warnings.groovy.GroovyParser; import io.jenkins.plugins.analysis.warnings.groovy.ParserConfiguration; +import io.jenkins.plugins.util.QualityGateStatus; import static io.jenkins.plugins.analysis.core.assertions.Assertions.*; import static net.javacrumbs.jsonunit.assertj.JsonAssertions.*; @@ -68,9 +68,6 @@ class StepsITest extends IntegrationTestWithJenkinsPerSuite { private static final String NO_QUALITY_GATE = ""; - /** - * Runs a pipeline and verifies the {@code scanForIssues} step has some allowlisted methods. - */ @Test void shouldParseCheckstyleUsingTheParserRegistry() { WorkflowJob job = createPipelineWithWorkspaceFilesWithSuffix("checkstyle1.xml", "checkstyle2.xml"); @@ -160,7 +157,7 @@ private void configureRecorder(final WorkflowJob job, final String fileName) { + " echo '[totalSize=' + result.getTotals().getTotalSize() + ']' \n" + " echo '[newSize=' + result.getTotals().getNewSize() + ']' \n" + " echo '[fixedSize=' + result.getTotals().getFixedSize() + ']' \n" - + " echo '[qualityGate=' + result.getQualityGateStatus() + ']' \n" + + " echo '[qualityGate=' + result.getQualityGateResult() + ']' \n" + " echo '[id=' + result.getId() + ']' \n" + " result.getIssues().each { issue ->\n" + " echo issue.toString()\n" @@ -194,8 +191,7 @@ void shouldSkipBlaming() { job.setDefinition(new CpsFlowDefinition("node {\n" + " stage ('Integration Test') {\n" - + " recordIssues forensicsDisabled: true, skipBlames: true, tool: checkStyle(pattern: '**/" - + "checkstyle1" + "*')\n" + + " recordIssues skipBlames: true, tool: checkStyle(pattern: '**/checkstyle1" + "*')\n" + " }\n" + "}", true)); Run baseline = buildSuccessfully(job); @@ -274,7 +270,7 @@ private void configurePublisher(final WorkflowJob job, final String fileName, fi + " echo '[name=' + action.getDisplayName() + ']' \n" + " echo '[isSuccessful=' + action.isSuccessful() + ']' \n" + " def result = action.getResult()\n" - + " def status = result.getQualityGateStatus()\n" + + " def status = result.getQualityGateResult()\n" + " echo '[status=' + status + ']' \n" + " echo '[isSuccessfulQualityGate=' + status.isSuccessful() + ']' \n" + " def totals = result.getTotals()\n" @@ -573,56 +569,6 @@ void shouldFailBuildWhenFailBuildOnErrorsIsSet() { scheduleBuildAndAssertStatus(job, Result.FAILURE); } - /** Runs the JavaDoc parser and enforces quality gates. */ - @Test - @org.junitpioneer.jupiter.Issue("JENKINS-58253") - void shouldSupportDeprecatedAttributesInRecord() { - WorkflowJob job = createPipelineWithWorkspaceFilesWithSuffix("javadoc.txt"); - - job.setDefinition(asStage( - "recordIssues tool: javaDoc(pattern:'**/*issues.txt', reportEncoding:'UTF-8'), " - + "unstableTotalAll: 6")); - buildWithResult(job, Result.UNSTABLE); - - job.setDefinition(asStage( - "recordIssues tool: javaDoc(pattern:'**/*issues.txt', reportEncoding:'UTF-8'), " - + "failedTotalAll: 6")); - buildWithResult(job, Result.FAILURE); - - job.setDefinition(asStage( - "recordIssues tool: javaDoc(pattern:'**/*issues.txt', reportEncoding:'UTF-8'), " - + "unstableTotalNormal: 6")); - buildWithResult(job, Result.UNSTABLE); - - job.setDefinition(asStage( - "recordIssues tool: javaDoc(pattern:'**/*issues.txt', reportEncoding:'UTF-8'), " - + "failedTotalNormal: 6")); - buildWithResult(job, Result.FAILURE); - } - - /** Runs the JavaDoc parser and enforces quality gates. */ - @Test - @org.junitpioneer.jupiter.Issue("JENKINS-58253") - void shouldSupportDeprecatedAttributesInPublish() { - WorkflowJob job = createPipelineWithWorkspaceFilesWithSuffix("javadoc.txt"); - - job.setDefinition(asStage(createScanForIssuesStep(new JavaDoc(), "java"), - "publishIssues issues:[java], unstableTotalAll: 6")); - buildWithResult(job, Result.UNSTABLE); - - job.setDefinition(asStage(createScanForIssuesStep(new JavaDoc(), "java"), - "publishIssues issues:[java], failedTotalAll: 6")); - buildWithResult(job, Result.FAILURE); - - job.setDefinition(asStage(createScanForIssuesStep(new JavaDoc(), "java"), - "publishIssues issues:[java], unstableTotalNormal: 6")); - buildWithResult(job, Result.UNSTABLE); - - job.setDefinition(asStage(createScanForIssuesStep(new JavaDoc(), "java"), - "publishIssues issues:[java], failedTotalNormal: 6")); - buildWithResult(job, Result.FAILURE); - } - /** * Runs the all Java parsers on three output files: the build should report issues of all tools. The results should * be aggregated into a new action with the specified ID. Since no name is given the default name is used. @@ -1101,7 +1047,7 @@ void publishIssuesShouldMarkStepWithWarningAction() { assertThat(publishIssuesNode).isNotNull(); WarningAction warningAction = publishIssuesNode.getPersistentAction(WarningAction.class); assertThat(warningAction).isNotNull(); - assertThat(warningAction.getMessage()).isEqualTo( + assertThat(warningAction.getMessage()).endsWith( "Some quality gates have been missed: overall result is UNSTABLE"); } @@ -1123,7 +1069,7 @@ void recordIssuesShouldMarkStepWithWarningAction() { assertThat(publishIssuesNode).isNotNull(); WarningAction warningAction = publishIssuesNode.getPersistentAction(WarningAction.class); assertThat(warningAction).isNotNull(); - assertThat(warningAction.getMessage()).isEqualTo( + assertThat(warningAction.getMessage()).endsWith( "Some quality gates have been missed: overall result is UNSTABLE"); } diff --git a/plugin/src/test/resources/io/jenkins/plugins/analysis/warnings/integrations/job-dsl-warnings-ng.yaml b/plugin/src/test/resources/io/jenkins/plugins/analysis/warnings/integrations/job-dsl-warnings-ng.yaml index bef04ad70f..f32069f8b3 100644 --- a/plugin/src/test/resources/io/jenkins/plugins/analysis/warnings/integrations/job-dsl-warnings-ng.yaml +++ b/plugin/src/test/resources/io/jenkins/plugins/analysis/warnings/integrations/job-dsl-warnings-ng.yaml @@ -6,7 +6,6 @@ jobs: trendChartType('NONE') aggregatingResults(true) blameDisabled(true) - forensicsDisabled(true) enabledForFailure(true) quiet(false) healthy(10) @@ -20,10 +19,10 @@ jobs: unhealthy(50) referenceJobName('test-job') qualityGates { - qualityGate { + warningsQualityGate { threshold(10) type('TOTAL') - unstable(true) + criticality('FAILURE') } } tools { diff --git a/ui-tests/src/main/java/io/jenkins/plugins/analysis/warnings/IssuesRecorder.java b/ui-tests/src/main/java/io/jenkins/plugins/analysis/warnings/IssuesRecorder.java index cb7480f7bb..54820fe133 100644 --- a/ui-tests/src/main/java/io/jenkins/plugins/analysis/warnings/IssuesRecorder.java +++ b/ui-tests/src/main/java/io/jenkins/plugins/analysis/warnings/IssuesRecorder.java @@ -5,7 +5,6 @@ import java.util.stream.Collectors; import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.events.EventFiringWebDriver; import org.jenkinsci.test.acceptance.po.AbstractStep; import org.jenkinsci.test.acceptance.po.Control; @@ -28,8 +27,9 @@ public class IssuesRecorder extends AbstractStep implements PostBuildStep { private final Control filtersRepeatable = findRepeatableAddButtonFor("filters"); private final Control filterRegex = control("/filters/pattern"); private final Control qualityGatesRepeatable = findRepeatableAddButtonFor("qualityGates"); - private final Control qualityGateThreshold = control("/qualityGates/threshold"); + private final Control qualityGateThreshold = control("/qualityGates/integerThreshold"); private final Control qualityGateType = control("/qualityGates/type"); + private final Control qualityGateCriticality = control("/qualityGates/criticality"); private final Control advancedButton = control("advanced-button"); private final Control enabledForFailureCheckBox = control("enabledForFailure"); private final Control ignoreQualityGate = control("ignoreQualityGate"); @@ -50,14 +50,6 @@ public class IssuesRecorder extends AbstractStep implements PostBuildStep { private final Control scm = control("scm"); private final Control quiet = control("quiet"); - /** - * Determines the result of the quality gate. - */ - public enum QualityGateBuildResult { - UNSTABLE, - FAILED - } - /** * Creates a new page object. * @@ -272,14 +264,8 @@ public String getQualityGateType() { return qualityGateType.get(); } - /** - * Gets the quality gate result. - * - * @return the quality gate result - **/ - public QualityGateBuildResult getQualityGateResult() { - return findUnstableRadioButton(self(), true).isSelected() - ? QualityGateBuildResult.UNSTABLE : QualityGateBuildResult.FAILED; + public String getQualityGateCriticality() { + return qualityGateCriticality.get(); } /** @@ -582,18 +568,18 @@ public IssuesRecorder setToolWithPattern(final String toolName, final String pat * the minimum number of issues that fails the quality gate * @param type * the type of the quality gate - * @param result + * @param criticality * determines whether the quality gate sets the build result to Unstable or Failed * * @return this recorder */ public IssuesRecorder addQualityGateConfiguration(final int threshold, final QualityGateType type, - final QualityGateBuildResult result) { + final QualityGateCriticality criticality) { String path = createPageArea("qualityGates", qualityGatesRepeatable::click); QualityGatePanel qualityGate = new QualityGatePanel(this, path); qualityGate.setThreshold(threshold); qualityGate.setType(type); - qualityGate.setUnstable(result == QualityGateBuildResult.UNSTABLE); + qualityGate.setCriticality(criticality); return this; } @@ -659,6 +645,31 @@ public String getDisplayName() { } } + /** + * Available quality gate types. + */ + public enum QualityGateCriticality { + FAILURE("Fail the build"), + UNSTABLE("Mark the build as unstable"), + PIPELINE_FAILURE("Fail the step and the build"), + PIPELINE_UNSTABLE("Mark the step and the build as unstable"); + + private final String displayName; + + QualityGateCriticality(final String displayName) { + this.displayName = displayName; + } + + /** + * Returns the localized human-readable name of this criticality. + * + * @return human-readable name + */ + public String getDisplayName() { + return displayName; + } + } + /** * Page area of a static analysis tool configuration. */ @@ -792,8 +803,9 @@ private void setFilter(final String regex) { * Page area of a quality gate configuration. */ private static class QualityGatePanel extends PageAreaImpl { - private final Control threshold = control("threshold"); + private final Control threshold = control("integerThreshold"); private final Control type = control("type"); + private final Control criticality = control("criticality"); QualityGatePanel(final PageArea area, final String path) { super(area, path); @@ -807,9 +819,8 @@ public void setType(final QualityGateType type) { this.type.select(type.getDisplayName()); } - public void setUnstable(final boolean isUnstable) { - WebElement radioButton = IssuesRecorder.findUnstableRadioButton(self(), isUnstable); - ((EventFiringWebDriver) driver).executeScript("arguments[0].click();", radioButton); + public void setCriticality(final QualityGateCriticality criticality) { + this.criticality.select(criticality.getDisplayName()); } } diff --git a/ui-tests/src/test/java/io/jenkins/plugins/analysis/warnings/FreeStyleConfigurationUiTest.java b/ui-tests/src/test/java/io/jenkins/plugins/analysis/warnings/FreeStyleConfigurationUiTest.java index 08801ae5b5..1ee2131516 100644 --- a/ui-tests/src/test/java/io/jenkins/plugins/analysis/warnings/FreeStyleConfigurationUiTest.java +++ b/ui-tests/src/test/java/io/jenkins/plugins/analysis/warnings/FreeStyleConfigurationUiTest.java @@ -6,7 +6,7 @@ import org.jenkinsci.test.acceptance.junit.WithPlugins; import org.jenkinsci.test.acceptance.po.FreeStyleJob; -import io.jenkins.plugins.analysis.warnings.IssuesRecorder.QualityGateBuildResult; +import io.jenkins.plugins.analysis.warnings.IssuesRecorder.QualityGateCriticality; import io.jenkins.plugins.analysis.warnings.IssuesRecorder.QualityGateType; import io.jenkins.plugins.analysis.warnings.IssuesRecorder.TrendChartType; @@ -52,7 +52,7 @@ public void shouldSetPropertiesInJobConfiguration() { issuesRecorder.setHealthReport(1, 9, SEVERITY); issuesRecorder.setReportFilePattern(PATTERN); issuesRecorder.addIssueFilter("Exclude categories", REGEX); - issuesRecorder.addQualityGateConfiguration(1, QualityGateType.TOTAL_ERROR, QualityGateBuildResult.UNSTABLE); + issuesRecorder.addQualityGateConfiguration(1, QualityGateType.TOTAL_ERROR, QualityGateCriticality.UNSTABLE); job.save(); job.configure(); @@ -79,7 +79,7 @@ public void shouldSetPropertiesInJobConfiguration() { assertThat(issuesRecorder).hasFilterRegex(REGEX); assertThat(issuesRecorder).hasQualityGateThreshold("1"); assertThat(issuesRecorder).hasQualityGateType(QualityGateType.TOTAL_ERROR.toString()); - assertThat(issuesRecorder).hasQualityGateResult(QualityGateBuildResult.UNSTABLE); + assertThat(issuesRecorder).hasQualityGateCriticality(QualityGateCriticality.UNSTABLE.toString()); // Now invert all booleans: issuesRecorder.setAggregatingResults(false); diff --git a/ui-tests/src/test/java/io/jenkins/plugins/analysis/warnings/SnippetGeneratorUiTest.java b/ui-tests/src/test/java/io/jenkins/plugins/analysis/warnings/SnippetGeneratorUiTest.java index e94d56d30c..9c9dfed7e6 100644 --- a/ui-tests/src/test/java/io/jenkins/plugins/analysis/warnings/SnippetGeneratorUiTest.java +++ b/ui-tests/src/test/java/io/jenkins/plugins/analysis/warnings/SnippetGeneratorUiTest.java @@ -5,7 +5,7 @@ import org.jenkinsci.test.acceptance.junit.WithPlugins; import org.jenkinsci.test.acceptance.po.WorkflowJob; -import io.jenkins.plugins.analysis.warnings.IssuesRecorder.QualityGateBuildResult; +import io.jenkins.plugins.analysis.warnings.IssuesRecorder.QualityGateCriticality; import io.jenkins.plugins.analysis.warnings.IssuesRecorder.QualityGateType; import static io.jenkins.plugins.analysis.warnings.Assertions.*; @@ -122,7 +122,7 @@ public void shouldHandleComplexConfiguration() { .setIgnoreQualityGate(true) .setSourceCodeEncoding("otherText") .addIssueFilter("Exclude types", "*toExclude*") - .addQualityGateConfiguration(1, QualityGateType.NEW, QualityGateBuildResult.FAILED) + .addQualityGateConfiguration(1, QualityGateType.NEW, QualityGateCriticality.PIPELINE_FAILURE) .setToolWithPattern(JAVA_COMPILER, "firstText"); String script = snippetGenerator.generateScript(); @@ -135,7 +135,7 @@ public void shouldHandleComplexConfiguration() { assertThat(script).contains("filters: [excludeType('*toExclude*')]"); assertThat(script).contains("ignoreFailedBuilds: false"); assertThat(script).contains("ignoreQualityGate: true"); - assertThat(script).contains("qualityGates: [[threshold: 1, type: 'NEW', unstable: false]]"); + assertThat(script).contains("qualityGates: [[criticality: 'FAILURE', integerThreshold: 1, threshold: 1.0, type: 'NEW']]"); assertThat(script).contains("pattern: 'firstText'"); assertThat(script).contains("sourceCodeEncoding: 'otherText'"); diff --git a/ui-tests/src/test/java/io/jenkins/plugins/analysis/warnings/WarningsPluginUiTest.java b/ui-tests/src/test/java/io/jenkins/plugins/analysis/warnings/WarningsPluginUiTest.java index 2a410a8187..3e87bdbeaf 100644 --- a/ui-tests/src/test/java/io/jenkins/plugins/analysis/warnings/WarningsPluginUiTest.java +++ b/ui-tests/src/test/java/io/jenkins/plugins/analysis/warnings/WarningsPluginUiTest.java @@ -22,7 +22,7 @@ import io.jenkins.plugins.analysis.warnings.AnalysisResult.Tab; import io.jenkins.plugins.analysis.warnings.AnalysisSummary.QualityGateResult; -import io.jenkins.plugins.analysis.warnings.IssuesRecorder.QualityGateBuildResult; +import io.jenkins.plugins.analysis.warnings.IssuesRecorder.QualityGateCriticality; import io.jenkins.plugins.analysis.warnings.IssuesRecorder.QualityGateType; import static io.jenkins.plugins.analysis.warnings.Assertions.*; @@ -102,8 +102,8 @@ public void shouldAggregateToolsIntoSingleResult() { FreeStyleJob job = createFreeStyleJob("build_status_test/build_01"); IssuesRecorder recorder = addAllRecorders(job); recorder.setEnabledForAggregation(true); - recorder.addQualityGateConfiguration(4, QualityGateType.TOTAL, QualityGateBuildResult.UNSTABLE); - recorder.addQualityGateConfiguration(3, QualityGateType.NEW, QualityGateBuildResult.FAILED); + recorder.addQualityGateConfiguration(4, QualityGateType.TOTAL, QualityGateCriticality.UNSTABLE); + recorder.addQualityGateConfiguration(3, QualityGateType.NEW, QualityGateCriticality.FAILURE); recorder.setIgnoreQualityGate(true); job.save();