1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-03-03 15:02:35 +02:00

refactor(checks): use warnings-ng plugin (#2398)

* use recordIssues

* fix c&p issue

* simplify code

* fix

* add quality gates

* change qgates to TOTAL_HIGH

* remove pattern for tasks

* use TOTAL_ERROR for checkstyle

* fix indent

* use deprecated threshold parameters

* debug messages

* transform legacy qgates

* fix

* adjust test cases

* correct qgates

* correct legacy thresholds

* fix typo

* remove deprecated defaults

* add test case

* log use tool

* add notification

* remove deprecated defaults

* remove deprecated parameter

* adjust legacy threshold message

* add q gates on error and high for all check tools

* Apply suggestions from code review

* adjust test cases

* remove duplicate assert

* Fail if aggregation is still defined

* update docs

* fix indent

* Update documentation/docs/steps/checksPublishResults.md

Co-authored-by: Stephan Aßmus <stephan.assmus@sap.com>

Co-authored-by: Stephan Aßmus <stephan.assmus@sap.com>
This commit is contained in:
Christopher Fenner 2020-11-25 15:39:33 +01:00 committed by GitHub
parent 5d1782aa01
commit eff1933a61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 343 additions and 280 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 128 KiB

View File

@ -6,20 +6,13 @@
* **static check result files** - To use this step, there must be static check result files available.
* installed plugins:
* [pmd](https://plugins.jenkins.io/pmd)
* [dry](https://plugins.jenkins.io/dry)
* [findbugs](https://plugins.jenkins.io/findbugs)
* [checkstyle](https://plugins.jenkins.io/checkstyle)
* [warnings](https://plugins.jenkins.io/warnings)
* [core](https://plugins.jenkins.io/core)
* [warnings-ng](https://plugins.jenkins.io/warnings-ng/)
## ${docGenParameters}
### aggregation
| parameter | mandatory | default | possible values |
| ----------|-----------|---------|-----------------|
| thresholds | no | none | see [thresholds](#thresholds) |
deprecated, do not use
### tasks
@ -30,7 +23,7 @@
| high | no | `'FIXME'` | |
| normal | no | `'TODO,REVISE,XXX'` | |
| low | no | | |
| thresholds | no | none | see [thresholds](#thresholds) |
| qualityGates | no | [[threshold: 1, type: 'TOTAL_HIGH', unstable: false], [threshold: 1, type: 'TOTAL_ERROR', unstable: false]] | see [QualityGates](#qualitygates) |
### pmd
@ -38,7 +31,7 @@
| ----------|-----------|---------|-----------------|
| pattern | no | `'**/target/pmd.xml'` | |
| archive | no | `true` | `true`, `false` |
| thresholds | no | none | see [thresholds](#thresholds) |
| qualityGates | no | [[threshold: 1, type: 'TOTAL_HIGH', unstable: false], [threshold: 1, type: 'TOTAL_ERROR', unstable: false]] | see [QualityGates](#qualitygates) |
### cpd
@ -46,7 +39,7 @@
| ----------|-----------|---------|-----------------|
| pattern | no | `'**/target/cpd.xml'` | |
| archive | no | `true` | `true`, `false` |
| thresholds | no | none | see [thresholds](#thresholds) |
| qualityGates | no | [[threshold: 1, type: 'TOTAL_HIGH', unstable: false], [threshold: 1, type: 'TOTAL_ERROR', unstable: false]] | see [QualityGates](#qualitygates) |
### findbugs
@ -54,7 +47,7 @@
| ----------|-----------|---------|-----------------|
| pattern | no | `'**/target/findbugsXml.xml, **/target/findbugs.xml'` | |
| archive | no | `true` | true, false |
| thresholds | no | none | see [thresholds](#thresholds) |
| qualityGates | no | [[threshold: 1, type: 'TOTAL_HIGH', unstable: false], [threshold: 1, type: 'TOTAL_ERROR', unstable: false]] | see [QualityGates](#qualitygates) |
### checkstyle
@ -62,7 +55,7 @@
| ----------|-----------|---------|-----------------|
| pattern | no | `'**/target/checkstyle-result.xml'` | |
| archive | no | `true` | `true`, `false` |
| thresholds | no | none | see [thresholds](#thresholds) |
| qualityGates | no | [[threshold: 1, type: 'TOTAL_HIGH', unstable: false], [threshold: 1, type: 'TOTAL_ERROR', unstable: false]] | see [QualityGates](#qualitygates) |
### eslint
@ -70,7 +63,7 @@
| ----------|-----------|---------|-----------------|
| pattern | no | `'**/eslint.jslint.xml'` | |
| archive | no | `true` | `true`, `false` |
| thresholds | no | none | see [thresholds](#thresholds) |
| qualityGates | no | [[threshold: 1, type: 'TOTAL_HIGH', unstable: false], [threshold: 1, type: 'TOTAL_ERROR', unstable: false]] | see [QualityGates](#qualitygates) |
### pylint
@ -78,39 +71,45 @@
| ----------|-----------|---------|-----------------|
| pattern | no | `'**/pylint.log'` | |
| archive | no | `true` | `true`, `false` |
| thresholds | no | none | see [thresholds](#thresholds) |
| qualityGates | no | [[threshold: 1, type: 'TOTAL_HIGH', unstable: false], [threshold: 1, type: 'TOTAL_ERROR', unstable: false]] | see [QualityGates](#qualitygates) |
## ${docGenConfiguration}
## ${docJenkinsPluginDependencies}
### Thresholds
### QualityGates
It is possible to define thresholds to fail the build on a certain count of findings. To achieve this, just define your thresholds a followed for the specific check tool:
It is possible to define quality gates to set the build result to `FAILURE` (not stop the build) on a certain count of findings. To achieve this, just define your quality gates as followed for the specific check tool:
```groovy
thresholds: [fail: [all: 999, low: 99, normal: 9, high: 0]]
qualityGates: [
[thresholds: 1, type: 'TOTAL_HIGH', unstable: false],
[thresholds: 10, type: 'TOTAL_NORMAL', unstable: false],
[thresholds: 100, type: 'TOTAL_LOW', unstable: false],
[thresholds: 1000, type: 'TOTAL', unstable: false],
]
```
This way, the jenkins will fail the build on 1 high issue, 10 normal issues, 100 low issues or a total issue count of 1000.
This way, the quality gate will fail on 1 high issue, 10 normal issues, 100 low issues or a total issue count of 1000.
The `thresholds` parameter can be set for `aggregation`, `tasks`, `pmd`, `cpd`, `findbugs`, `checkstyle`, `eslint` and `pylint`.
The `qualityGates` parameter can be set for `tasks`, `pmd`, `cpd`, `findbugs`, `checkstyle`, `eslint` and `pylint`.
```groovy
checksPublishResults(
tasks: true,
pmd: [pattern: '**/target/pmd-results.xml', thresholds: [fail: [low: 100]]],
pmd: [pattern: '**/target/pmd-results.xml', qualityGates: [[threshold: 101, type: 'TOTAL_LOW', unstable: true]]],
cpd: [archive: false],
aggregation: [thresholds: [fail: [high: 0]]],
archive: true
)
```
See also the [official plugin documentation](https://github.com/jenkinsci/warnings-ng-plugin/blob/master/doc/Documentation.md#quality-gate-configuration) for further information.
![StaticChecks Thresholds](../images/StaticChecks_Threshold.png)
## Side effects
If both ESLint and PyLint results are published, they are not correctly aggregated in the aggregator plugin.
none
## Exceptions
@ -120,12 +119,12 @@ none
```groovy
// publish java results from pmd, cpd, checkstyle & findbugs
checksPublishResults archive: true, pmd: true, cpd: true, findbugs: true, checkstyle: true, aggregation: [thresholds: [fail: [high: 0]]]
checksPublishResults archive: true, pmd: true, cpd: true, findbugs: true, checkstyle: true
```
```groovy
// publish javascript results from ESLint
checksPublishResults archive: true, eslint: [pattern: '**/result-file-with-fancy-name.xml'], aggregation: [thresholds: [fail: [high: 0, normal: 10]]]
checksPublishResults archive: true, eslint: [pattern: '**/result-file-with-fancy-name.xml']
```
```groovy

View File

@ -110,11 +110,6 @@ steps:
- 'tests'
testPackage: 'piper-bats'
checksPublishResults:
aggregation:
active: true
thresholds:
fail:
high: '0'
tasks:
pattern: '**/*.java'
low: ''
@ -122,51 +117,79 @@ steps:
high: 'FIXME'
archive: true
active: false
thresholds:
fail:
high: '0'
qualityGates:
- threshold: 1
type: 'TOTAL_HIGH'
unstable: false
- threshold: 1
type: 'TOTAL_ERROR'
unstable: false
pmd:
pattern: '**/target/pmd.xml'
archive: true
active: false
thresholds:
fail:
high: '0'
qualityGates:
- threshold: 1
type: 'TOTAL_HIGH'
unstable: false
- threshold: 1
type: 'TOTAL_ERROR'
unstable: false
cpd:
pattern: '**/target/cpd.xml'
archive: true
active: false
thresholds:
fail:
high: '0'
qualityGates:
- threshold: 1
type: 'TOTAL_HIGH'
unstable: false
- threshold: 1
type: 'TOTAL_ERROR'
unstable: false
findbugs:
pattern: '**/target/findbugsXml.xml, **/target/findbugs.xml'
archive: true
active: false
thresholds:
fail:
high: '0'
qualityGates:
- threshold: 1
type: 'TOTAL_HIGH'
unstable: false
- threshold: 1
type: 'TOTAL_ERROR'
unstable: false
checkstyle:
pattern: '**/target/checkstyle-result.xml'
archive: true
active: false
thresholds:
fail:
high: '0'
qualityGates:
- threshold: 1
type: 'TOTAL_HIGH'
unstable: false
- threshold: 1
type: 'TOTAL_ERROR'
unstable: false
eslint:
pattern: '**/eslint.xml'
archive: true
active: false
thresholds:
fail:
high: '0'
qualityGates:
- threshold: 1
type: 'TOTAL_HIGH'
unstable: false
- threshold: 1
type: 'TOTAL_ERROR'
unstable: false
pylint:
pattern: '**/pylint.log'
archive: true
active: false
thresholds:
fail:
high: '0'
qualityGates:
- threshold: 1
type: 'TOTAL_HIGH'
unstable: false
- threshold: 1
type: 'TOTAL_ERROR'
unstable: false
archive: false
cloudFoundryDeploy:
cloudFoundry:

View File

@ -9,9 +9,15 @@ import com.sap.piper.Utils
import util.BasePiperTest
import static org.junit.Assert.assertEquals
import static org.junit.Assert.assertTrue
import static org.hamcrest.Matchers.hasItem
import static org.hamcrest.Matchers.containsInAnyOrder
import static org.hamcrest.Matchers.not
import static org.hamcrest.Matchers.allOf
import static org.hamcrest.Matchers.is
import static org.hamcrest.Matchers.hasKey
import static org.hamcrest.Matchers.hasSize
import static org.hamcrest.Matchers.hasEntry
import static org.junit.Assert.assertThat
import util.Rules
import util.JenkinsReadYamlRule
@ -35,8 +41,29 @@ class ChecksPublishResultsTest extends BasePiperTest {
publisherStepOptions = [:]
archiveStepPatterns = []
// add handler for generic step call
helper.registerAllowedMethod("step", [Map.class], {
parameters -> publisherStepOptions[parameters.$class] = parameters
helper.registerAllowedMethod("recordIssues", [Map.class], {
parameters -> publisherStepOptions[parameters.tools[0].publisher] = parameters
})
helper.registerAllowedMethod("pmdParser", [Map.class], {
parameters -> return parameters.plus([publisher: "PmdPublisher"])
})
helper.registerAllowedMethod("cpd", [Map.class], {
parameters -> return parameters.plus([publisher: "DryPublisher"])
})
helper.registerAllowedMethod("findBugs", [Map.class], {
parameters -> return parameters.plus([publisher: "FindBugsPublisher"])
})
helper.registerAllowedMethod("checkStyle", [Map.class], {
parameters -> return parameters.plus([publisher: "CheckStylePublisher"])
})
helper.registerAllowedMethod("esLint", [Map.class], {
parameters -> return parameters.plus([publisher: "ESLintPublisher"])
})
helper.registerAllowedMethod("pyLint", [Map.class], {
parameters -> return parameters.plus([publisher: "PyLintPublisher"])
})
helper.registerAllowedMethod("taskScanner", [Map.class], {
parameters -> return parameters.plus([publisher: "TaskPublisher"])
})
helper.registerAllowedMethod("archiveArtifacts", [Map.class], {
parameters -> archiveStepPatterns.push(parameters.artifacts)
@ -51,233 +78,243 @@ class ChecksPublishResultsTest extends BasePiperTest {
@Test
void testPublishWithDefaultSettings() throws Exception {
// test
stepRule.step.checksPublishResults(script: nullScript)
assertTrue("AnalysisPublisher options not set", publisherStepOptions['AnalysisPublisher'] != null)
// ensure nothing else is published
assertTrue("WarningsPublisher options not empty", publisherStepOptions['WarningsPublisher'] == null)
assertTrue("PmdPublisher options not empty", publisherStepOptions['PmdPublisher'] == null)
assertTrue("DryPublisher options not empty", publisherStepOptions['DryPublisher'] == null)
assertTrue("FindBugsPublisher options not empty", publisherStepOptions['FindBugsPublisher'] == null)
assertTrue("CheckStylePublisher options not empty", publisherStepOptions['CheckStylePublisher'] == null)
// assert
// ensure nothing is published
assertThat(publisherStepOptions, not(hasKey('PmdPublisher')))
assertThat(publisherStepOptions, not(hasKey('DryPublisher')))
assertThat(publisherStepOptions, not(hasKey('FindBugsPublisher')))
assertThat(publisherStepOptions, not(hasKey('CheckStylePublisher')))
assertThat(publisherStepOptions, not(hasKey('ESLintPublisher')))
assertThat(publisherStepOptions, not(hasKey('PyLintPublisher')))
assertThat(publisherStepOptions, not(hasKey('TaskPublisher')))
}
@Test
void testPublishForJavaWithDefaultSettings() throws Exception {
// test
stepRule.step.checksPublishResults(script: nullScript, pmd: true, cpd: true, findbugs: true, checkstyle: true)
assertTrue("AnalysisPublisher options not set", publisherStepOptions['AnalysisPublisher'] != null)
assertTrue("PmdPublisher options not set", publisherStepOptions['PmdPublisher'] != null)
assertTrue("DryPublisher options not set", publisherStepOptions['DryPublisher'] != null)
assertTrue("FindBugsPublisher options not set", publisherStepOptions['FindBugsPublisher'] != null)
assertTrue("CheckStylePublisher options not set", publisherStepOptions['CheckStylePublisher'] != null)
// assert
assertThat(publisherStepOptions, hasKey('PmdPublisher'))
assertThat(publisherStepOptions, hasKey('DryPublisher'))
assertThat(publisherStepOptions, hasKey('FindBugsPublisher'))
assertThat(publisherStepOptions, hasKey('CheckStylePublisher'))
// ensure default patterns are set
assertEquals("PmdPublisher default pattern not set", '**/target/pmd.xml', publisherStepOptions['PmdPublisher']['pattern'])
assertEquals("DryPublisher default pattern not set", '**/target/cpd.xml', publisherStepOptions['DryPublisher']['pattern'])
assertEquals("FindBugsPublisher default pattern not set", '**/target/findbugsXml.xml, **/target/findbugs.xml', publisherStepOptions['FindBugsPublisher']['pattern'])
assertEquals("CheckStylePublisher default pattern not set", '**/target/checkstyle-result.xml', publisherStepOptions['CheckStylePublisher']['pattern'])
assertThat(publisherStepOptions['PmdPublisher'], hasKey('tools'))
assertThat(publisherStepOptions['PmdPublisher']['tools'], hasItem(hasEntry('pattern', '**/target/pmd.xml')))
assertThat(publisherStepOptions['DryPublisher'], hasKey('tools'))
assertThat(publisherStepOptions['DryPublisher']['tools'], hasItem(hasEntry('pattern', '**/target/cpd.xml')))
assertThat(publisherStepOptions['FindBugsPublisher'], hasKey('tools'))
assertThat(publisherStepOptions['FindBugsPublisher']['tools'], hasItem(hasEntry('pattern', '**/target/findbugsXml.xml, **/target/findbugs.xml')))
assertThat(publisherStepOptions['CheckStylePublisher'], hasKey('tools'))
assertThat(publisherStepOptions['CheckStylePublisher']['tools'], hasItem(hasEntry('pattern', '**/target/checkstyle-result.xml')))
// ensure nothing else is published
assertTrue("WarningsPublisher options not empty", publisherStepOptions['WarningsPublisher'] == null)
assertThat(publisherStepOptions, not(hasKey('ESLintPublisher')))
assertThat(publisherStepOptions, not(hasKey('PyLintPublisher')))
assertThat(publisherStepOptions, not(hasKey('TaskPublisher')))
}
@Test
void testPublishForJavaScriptWithDefaultSettings() throws Exception {
// test
stepRule.step.checksPublishResults(script: nullScript, eslint: true)
assertTrue("AnalysisPublisher options not set", publisherStepOptions['AnalysisPublisher'] != null)
assertTrue("WarningsPublisher options not set", publisherStepOptions['WarningsPublisher'] != null)
assertTrue("WarningsPublisher parser configuration number not correct", publisherStepOptions['WarningsPublisher']['parserConfigurations'].size() == 1)
// assert
assertThat(publisherStepOptions, hasKey('ESLintPublisher'))
// ensure correct parser is set set
assertEquals("ESLint parser not correct", 'JSLint', publisherStepOptions['WarningsPublisher']['parserConfigurations'][0]['parserName'])
// ensure default patterns are set
assertEquals("ESLint default pattern not set", '**/eslint.xml', publisherStepOptions['WarningsPublisher']['parserConfigurations'][0]['pattern'])
assertThat(publisherStepOptions['ESLintPublisher'], hasKey('tools'))
assertThat(publisherStepOptions['ESLintPublisher']['tools'], hasItem(hasEntry('pattern', '**/eslint.xml')))
// ensure nothing else is published
assertTrue("PmdPublisher options not empty", publisherStepOptions['PmdPublisher'] == null)
assertTrue("DryPublisher options not empty", publisherStepOptions['DryPublisher'] == null)
assertTrue("FindBugsPublisher options not empty", publisherStepOptions['FindBugsPublisher'] == null)
assertTrue("CheckStylePublisher options not empty", publisherStepOptions['CheckStylePublisher'] == null)
assertThat(publisherStepOptions, not(hasKey('PmdPublisher')))
assertThat(publisherStepOptions, not(hasKey('DryPublisher')))
assertThat(publisherStepOptions, not(hasKey('FindBugsPublisher')))
assertThat(publisherStepOptions, not(hasKey('CheckStylePublisher')))
assertThat(publisherStepOptions, not(hasKey('PyLintPublisher')))
assertThat(publisherStepOptions, not(hasKey('TaskPublisher')))
}
@Test
void testPublishForPythonWithDefaultSettings() throws Exception {
// test
stepRule.step.checksPublishResults(script: nullScript, pylint: true)
assertTrue("AnalysisPublisher options not set", publisherStepOptions['AnalysisPublisher'] != null)
assertTrue("WarningsPublisher options not set", publisherStepOptions['WarningsPublisher'] != null)
assertTrue("WarningsPublisher parser configuration number not correct", publisherStepOptions['WarningsPublisher']['parserConfigurations'].size() == 1)
assertEquals('PyLint', publisherStepOptions['WarningsPublisher']['parserConfigurations'][0]['parserName'])
// assert
assertThat(publisherStepOptions, hasKey('PyLintPublisher'))
// ensure correct parser is set set
assertEquals("PyLint parser not correct", 'PyLint', publisherStepOptions['WarningsPublisher']['parserConfigurations'][0]['parserName'])
// ensure default patterns are set
assertEquals("PyLint default pattern not set", '**/pylint.log', publisherStepOptions['WarningsPublisher']['parserConfigurations'][0]['pattern'])
assertThat(publisherStepOptions['PyLintPublisher'], hasKey('tools'))
assertThat(publisherStepOptions['PyLintPublisher']['tools'], hasItem(hasEntry('pattern', '**/pylint.log')))
// ensure nothing else is published
assertTrue("PmdPublisher options not empty", publisherStepOptions['PmdPublisher'] == null)
assertTrue("DryPublisher options not empty", publisherStepOptions['DryPublisher'] == null)
assertTrue("FindBugsPublisher options not empty", publisherStepOptions['FindBugsPublisher'] == null)
assertTrue("CheckStylePublisher options not empty", publisherStepOptions['CheckStylePublisher'] == null)
}
@Test
void testPublishNothing() throws Exception {
stepRule.step.checksPublishResults(script: nullScript, aggregation: false)
// ensure nothing is published
assertTrue("AnalysisPublisher options not empty", publisherStepOptions['AnalysisPublisher'] == null)
assertTrue("WarningsPublisher options not empty", publisherStepOptions['WarningsPublisher'] == null)
assertTrue("PmdPublisher options not empty", publisherStepOptions['PmdPublisher'] == null)
assertTrue("DryPublisher options not empty", publisherStepOptions['DryPublisher'] == null)
assertTrue("FindBugsPublisher options not empty", publisherStepOptions['FindBugsPublisher'] == null)
assertTrue("CheckStylePublisher options not empty", publisherStepOptions['CheckStylePublisher'] == null)
assertThat(publisherStepOptions, not(hasKey('PmdPublisher')))
assertThat(publisherStepOptions, not(hasKey('DryPublisher')))
assertThat(publisherStepOptions, not(hasKey('FindBugsPublisher')))
assertThat(publisherStepOptions, not(hasKey('CheckStylePublisher')))
assertThat(publisherStepOptions, not(hasKey('ESLintPublisher')))
assertThat(publisherStepOptions, not(hasKey('TaskPublisher')))
}
@Test
void testPublishNothingExplicitFalse() throws Exception {
// test
stepRule.step.checksPublishResults(script: nullScript, pmd: false)
assertTrue("AnalysisPublisher options not set", publisherStepOptions['AnalysisPublisher'] != null)
// ensure nothing else is published
assertTrue("PmdPublisher options not empty", publisherStepOptions['PmdPublisher'] == null)
assertTrue("DryPublisher options not empty", publisherStepOptions['DryPublisher'] == null)
assertTrue("FindBugsPublisher options not empty", publisherStepOptions['FindBugsPublisher'] == null)
assertTrue("CheckStylePublisher options not empty", publisherStepOptions['CheckStylePublisher'] == null)
assertTrue("WarningsPublisher options not empty", publisherStepOptions['WarningsPublisher'] == null)
// assert
// ensure pmd is not published
assertThat(publisherStepOptions, not(hasKey('PmdPublisher')))
}
@Test
void testPublishNothingImplicitTrue() throws Exception {
// test
stepRule.step.checksPublishResults(script: nullScript, pmd: [:])
// ensure pmd is not published
assertTrue("PmdPublisher options not set", publisherStepOptions['PmdPublisher'] != null)
// assert
// ensure pmd is published
assertThat(publisherStepOptions, hasKey('PmdPublisher'))
}
@Test
void testPublishNothingExplicitActiveFalse() throws Exception {
// test
stepRule.step.checksPublishResults(script: nullScript, pmd: [active: false])
// assert
// ensure pmd is not published
assertTrue("PmdPublisher options not empty", publisherStepOptions['PmdPublisher'] == null)
assertThat(publisherStepOptions, not(hasKey('PmdPublisher')))
}
@Test
void testPublishWithChangedStepDefaultSettings() throws Exception {
// init
// pmd has been set to active: true in step configuration
stepRule.step.checksPublishResults(script: [commonPipelineEnvironment: [
configuration: [steps: [checksPublishResults: [pmd: [active: true]]]]
]])
assertTrue("AnalysisPublisher options not set", publisherStepOptions['AnalysisPublisher'] != null)
assertTrue("PmdPublisher options not set", publisherStepOptions['PmdPublisher'] != null)
def cpe = [configuration: [steps: [checksPublishResults: [pmd: [active: true]]]]]
// test
stepRule.step.checksPublishResults(script: [commonPipelineEnvironment: cpe])
// assert
assertThat(publisherStepOptions, hasKey('PmdPublisher'))
// ensure nothing else is published
assertTrue("DryPublisher options not empty", publisherStepOptions['DryPublisher'] == null)
assertTrue("FindBugsPublisher options not empty", publisherStepOptions['FindBugsPublisher'] == null)
assertTrue("CheckStylePublisher options not empty", publisherStepOptions['CheckStylePublisher'] == null)
assertTrue("WarningsPublisher options not empty", publisherStepOptions['WarningsPublisher'] == null)
assertThat(publisherStepOptions, not(hasKey('DryPublisher')))
assertThat(publisherStepOptions, not(hasKey('FindBugsPublisher')))
assertThat(publisherStepOptions, not(hasKey('CheckStylePublisher')))
assertThat(publisherStepOptions, not(hasKey('ESLintPublisher')))
assertThat(publisherStepOptions, not(hasKey('PyLintPublisher')))
assertThat(publisherStepOptions, not(hasKey('TaskPublisher')))
}
@Test
void testPublishWithCustomPattern() throws Exception {
// test
stepRule.step.checksPublishResults(script: nullScript, eslint: [pattern: 'my-fancy-file.ext'], pmd: [pattern: 'this-is-not-a-patter.xml'])
assertTrue("AnalysisPublisher options not set", publisherStepOptions['AnalysisPublisher'] != null)
assertTrue("PmdPublisher options not set", publisherStepOptions['PmdPublisher'] != null)
assertTrue("WarningsPublisher options not set", publisherStepOptions['WarningsPublisher'] != null)
assertTrue("WarningsPublisher parser configuration number not correct", publisherStepOptions['WarningsPublisher']['parserConfigurations'].size() == 1)
// assert
assertThat(publisherStepOptions, hasKey('PmdPublisher'))
assertThat(publisherStepOptions, hasKey('ESLintPublisher'))
// ensure custom patterns are set
assertEquals("PmdPublisher custom pattern not set", 'this-is-not-a-patter.xml', publisherStepOptions['PmdPublisher']['pattern'])
assertEquals("ESLint custom pattern not set", 'my-fancy-file.ext', publisherStepOptions['WarningsPublisher']['parserConfigurations'][0]['pattern'])
assertThat(publisherStepOptions['PmdPublisher'], hasKey('tools'))
assertThat(publisherStepOptions['PmdPublisher']['tools'], hasItem(hasEntry('pattern', 'this-is-not-a-patter.xml')))
assertThat(publisherStepOptions['ESLintPublisher'], hasKey('tools'))
assertThat(publisherStepOptions['ESLintPublisher']['tools'], hasItem(hasEntry('pattern', 'my-fancy-file.ext')))
// ensure nothing else is published
assertTrue("DryPublisher options not empty", publisherStepOptions['DryPublisher'] == null)
assertTrue("FindBugsPublisher options not empty", publisherStepOptions['FindBugsPublisher'] == null)
assertTrue("CheckStylePublisher options not empty", publisherStepOptions['CheckStylePublisher'] == null)
assertThat(publisherStepOptions, not(hasKey('DryPublisher')))
assertThat(publisherStepOptions, not(hasKey('FindBugsPublisher')))
assertThat(publisherStepOptions, not(hasKey('CheckStylePublisher')))
assertThat(publisherStepOptions, not(hasKey('PyLintPublisher')))
assertThat(publisherStepOptions, not(hasKey('TaskPublisher')))
}
@Test
void testPublishWithArchive() throws Exception {
// test
stepRule.step.checksPublishResults(script: nullScript, archive: true, eslint: true, pmd: true, cpd: true, findbugs: true, checkstyle: true)
assertTrue("ArchivePatterns number not correct", archiveStepPatterns.size() == 5)
assertTrue("ArchivePatterns contains no PMD pattern", archiveStepPatterns.contains('**/target/pmd.xml'))
assertTrue("ArchivePatterns contains no CPD pattern", archiveStepPatterns.contains('**/target/cpd.xml'))
assertTrue("ArchivePatterns contains no FindBugs pattern", archiveStepPatterns.contains('**/target/findbugsXml.xml, **/target/findbugs.xml'))
assertTrue("ArchivePatterns contains no CheckStyle pattern", archiveStepPatterns.contains('**/target/checkstyle-result.xml'))
assertTrue("ArchivePatterns contains no ESLint pattern", archiveStepPatterns.contains('**/eslint.xml'))
// assert
assertThat(archiveStepPatterns, hasSize(5))
assertThat(archiveStepPatterns, allOf(
hasItem('**/target/pmd.xml'),
hasItem('**/target/cpd.xml'),
hasItem('**/target/findbugsXml.xml, **/target/findbugs.xml'),
hasItem('**/target/checkstyle-result.xml'),
hasItem('**/eslint.xml'),
))
}
@Test
void testPublishWithPartialArchive() throws Exception {
// test
stepRule.step.checksPublishResults(script: nullScript, archive: true, eslint: [archive: false], pmd: true, cpd: true, findbugs: true, checkstyle: true)
assertTrue("ArchivePatterns number not correct", archiveStepPatterns.size() == 4)
assertTrue("ArchivePatterns contains no PMD pattern", archiveStepPatterns.contains('**/target/pmd.xml'))
assertTrue("ArchivePatterns contains no CPD pattern", archiveStepPatterns.contains('**/target/cpd.xml'))
assertTrue("ArchivePatterns contains no FindBugs pattern", archiveStepPatterns.contains('**/target/findbugsXml.xml, **/target/findbugs.xml'))
assertTrue("ArchivePatterns contains no CheckStyle pattern", archiveStepPatterns.contains('**/target/checkstyle-result.xml'))
// ensure no ESLint pattern is contained
assertTrue("ArchivePatterns contains ESLint pattern", !archiveStepPatterns.contains('**/eslint.xml'))
// assert
assertThat(archiveStepPatterns, hasSize(4))
assertThat(archiveStepPatterns, allOf(
hasItem('**/target/pmd.xml'),
hasItem('**/target/cpd.xml'),
hasItem('**/target/findbugsXml.xml, **/target/findbugs.xml'),
hasItem('**/target/checkstyle-result.xml'),
not(hasItem('**/eslint.xml')),
))
}
@Test
void testPublishWithDefaultThresholds() throws Exception {
// test
stepRule.step.checksPublishResults(script: nullScript, pmd: true)
assertTrue("AnalysisPublisher options not set",
publisherStepOptions['AnalysisPublisher'] != null)
assertTrue("PmdPublisher options not set",
publisherStepOptions['PmdPublisher'] != null)
assertEquals("AnalysisPublisher thresholds configuration for failedTotalHigh not correct",
'0', publisherStepOptions['AnalysisPublisher']['failedTotalHigh'])
assertEquals("PmdPublisher thresholds configuration for failedTotalHigh not correct",
'0', publisherStepOptions['PmdPublisher']['failedTotalHigh'])
// ensure other values are empty
assertEquals("AnalysisPublisher thresholds configuration for failedTotalNormal is set",
null, publisherStepOptions['AnalysisPublisher']['failedTotalNormal'])
assertEquals("AnalysisPublisher thresholds configuration for failedTotalLow is set",
null, publisherStepOptions['AnalysisPublisher']['failedTotalLow'])
assertEquals("AnalysisPublisher thresholds configuration for failedTotalAll is set",
null, publisherStepOptions['AnalysisPublisher']['failedTotalAll'])
assertEquals("AnalysisPublisher thresholds configuration for unstableTotalHigh not correct",
null, publisherStepOptions['AnalysisPublisher']['unstableTotalHigh'])
assertEquals("AnalysisPublisher thresholds configuration for unstableTotalNormal is set",
null, publisherStepOptions['AnalysisPublisher']['unstableTotalNormal'])
assertEquals("AnalysisPublisher thresholds configuration for unstableTotalLow is set",
null, publisherStepOptions['AnalysisPublisher']['unstableTotalLow'])
assertEquals("AnalysisPublisher thresholds configuration for unstableTotalAll is set",
null, publisherStepOptions['AnalysisPublisher']['unstableTotalAll'])
// ensure nothing else is published
assertTrue("DryPublisher options not empty", publisherStepOptions['DryPublisher'] == null)
assertTrue("FindBugsPublisher options not empty", publisherStepOptions['FindBugsPublisher'] == null)
assertTrue("CheckStylePublisher options not empty", publisherStepOptions['CheckStylePublisher'] == null)
assertTrue("WarningsPublisher options not empty", publisherStepOptions['WarningsPublisher'] == null)
// assert
assertThat(publisherStepOptions, hasKey('PmdPublisher'))
assertThat(publisherStepOptions['PmdPublisher'], hasKey('qualityGates'))
assertThat(publisherStepOptions['PmdPublisher']['qualityGates'], allOf(
hasSize(2),
hasItem(allOf(
hasEntry('threshold', 1),
hasEntry('type', 'TOTAL_ERROR'),
hasEntry('unstable', false),
)),
hasItem(allOf(
hasEntry('threshold', 1),
hasEntry('type', 'TOTAL_HIGH'),
hasEntry('unstable', false),
)),
))
}
@Test
void testPublishWithThresholds() throws Exception {
stepRule.step.checksPublishResults(script: nullScript, aggregation: [thresholds: [fail: [high: '10']]], pmd: true)
void testPublishWithLegacyThresholds() throws Exception {
// test
stepRule.step.checksPublishResults(script: nullScript, pmd: [thresholds: [fail: [high: '10']]])
// assert
assertThat(publisherStepOptions, hasKey('PmdPublisher'))
assertThat(publisherStepOptions['PmdPublisher'], hasKey('qualityGates'))
assertThat(publisherStepOptions['PmdPublisher']['qualityGates'], allOf(
//TODO: thresholds are added to existing qualityGates, thus we have 2 defined in the end
hasSize(3),
hasItem(allOf(
hasEntry('threshold', 1),
hasEntry('type', 'TOTAL_ERROR'),
hasEntry('unstable', false),
)),
hasItem(allOf(
hasEntry('threshold', 1),
hasEntry('type', 'TOTAL_HIGH'),
hasEntry('unstable', false),
)),
hasItem(allOf(
hasEntry('threshold', 11),
hasEntry('type', 'TOTAL_HIGH'),
hasEntry('unstable', false),
)),
))
}
assertTrue("AnalysisPublisher options not set", publisherStepOptions['AnalysisPublisher'] != null)
assertTrue("PmdPublisher options not set", publisherStepOptions['PmdPublisher'] != null)
assertEquals("AnalysisPublisher thresholds configuration for failedTotalHigh not correct",
'10', publisherStepOptions['AnalysisPublisher']['failedTotalHigh'])
// ensure other values are empty
assertEquals("AnalysisPublisher thresholds configuration for failedTotalNormal is set",
null, publisherStepOptions['AnalysisPublisher']['failedTotalNormal'])
assertEquals("AnalysisPublisher thresholds configuration for failedTotalLow is set",
null, publisherStepOptions['AnalysisPublisher']['failedTotalLow'])
assertEquals("AnalysisPublisher thresholds configuration for failedTotalAll is set",
null, publisherStepOptions['AnalysisPublisher']['failedTotalAll'])
assertEquals("AnalysisPublisher thresholds configuration for unstableTotalHigh not correct",
null, publisherStepOptions['AnalysisPublisher']['unstableTotalHigh'])
assertEquals("AnalysisPublisher thresholds configuration for unstableTotalNormal is set",
null, publisherStepOptions['AnalysisPublisher']['unstableTotalNormal'])
assertEquals("AnalysisPublisher thresholds configuration for unstableTotalLow is set",
null, publisherStepOptions['AnalysisPublisher']['unstableTotalLow'])
assertEquals("AnalysisPublisher thresholds configuration for unstableTotalAll is set",
null, publisherStepOptions['AnalysisPublisher']['unstableTotalAll'])
// ensure nothing else is published
assertTrue("DryPublisher options not empty", publisherStepOptions['DryPublisher'] == null)
assertTrue("FindBugsPublisher options not empty", publisherStepOptions['FindBugsPublisher'] == null)
assertTrue("CheckStylePublisher options not empty", publisherStepOptions['CheckStylePublisher'] == null)
assertTrue("WarningsPublisher options not empty", publisherStepOptions['WarningsPublisher'] == null)
@Test
void testPublishWithCustomThresholds() throws Exception {
// test
stepRule.step.checksPublishResults(script: nullScript, pmd: [qualityGates: [[threshold: 20, type: 'TOTAL_LOW', unstable: false],[threshold: 10, type: 'TOTAL_NORMAL', unstable: false]]])
// assert
assertThat(publisherStepOptions, hasKey('PmdPublisher'))
assertThat(publisherStepOptions['PmdPublisher'], hasKey('qualityGates'))
assertThat(publisherStepOptions['PmdPublisher']['qualityGates'], allOf(
hasSize(2),
hasItem(allOf(
hasEntry('threshold', 10),
hasEntry('type', 'TOTAL_NORMAL'),
hasEntry('unstable', false),
)),
hasItem(allOf(
hasEntry('threshold', 20),
hasEntry('type', 'TOTAL_LOW'),
hasEntry('unstable', false),
)),
))
}
}

View File

@ -78,6 +78,10 @@ void call(Map parameters = [:]) {
.mixin(parameters, PARAMETER_KEYS)
.use()
if (configuration.aggregation && configuration.aggregation.active != false){
error "[ERROR] Configuration of the aggregation view is no longer possible. Migrate any thresholds defined here to tool specific quality gates. (piper-lib/${STEP_NAME})"
}
new Utils().pushToSWA([
step: STEP_NAME,
stepParamKey1: 'scriptMissing',
@ -85,64 +89,32 @@ void call(Map parameters = [:]) {
], configuration)
// JAVA
report('PmdPublisher', configuration.pmd, configuration.archive)
report('DryPublisher', configuration.cpd, configuration.archive)
report('FindBugsPublisher', configuration.findbugs, configuration.archive)
report('CheckStylePublisher', configuration.checkstyle, configuration.archive)
report(pmdParser(createToolOptions(configuration.pmd)), configuration.pmd, configuration.archive)
report(cpd(createToolOptions(configuration.cpd)), configuration.cpd, configuration.archive)
report(findBugs(createToolOptions(configuration.findbugs, [useRankAsPriority: true])), configuration.findbugs, configuration.archive)
report(checkStyle(createToolOptions(configuration.checkstyle)), configuration.checkstyle, configuration.archive)
// JAVA SCRIPT
reportWarnings('JSLint', configuration.eslint, configuration.archive)
report(esLint(createToolOptions(configuration.eslint)), configuration.eslint, configuration.archive)
// PYTHON
reportWarnings('PyLint', configuration.pylint, configuration.archive)
report(pyLint(createToolOptions(configuration.pylint)), configuration.pylint, configuration.archive)
// GENERAL
reportTasks(configuration.tasks)
aggregateReports(configuration.aggregation)
report(taskScanner(createToolOptions(configuration.tasks, [
includePattern: configuration.tasks.get('pattern'),
highTags: configuration.tasks.get('high'),
normalTags: configuration.tasks.get('normal'),
lowTags: configuration.tasks.get('low'),
]).minus([pattern: configuration.tasks.get('pattern')])), configuration.tasks, configuration.archive)
}
}
def aggregateReports(settings){
def report(tool, settings, doArchive){
if (settings.active) {
def options = createCommonOptionsMap('AnalysisPublisher', settings)
def options = createOptions(settings).plus([tools: [tool]])
echo "recordIssues OPTIONS: ${options}"
// publish
step(options)
}
}
def reportTasks(settings){
if (settings.active) {
def options = createCommonOptionsMap('TasksPublisher', settings)
options.put('pattern', settings.get('pattern'))
options.put('high', settings.get('high'))
options.put('normal', settings.get('normal'))
options.put('low', settings.get('low'))
// publish
step(options)
}
}
def report(publisherName, settings, doArchive){
if (settings.active) {
def pattern = settings.get('pattern')
def options = createCommonOptionsMap(publisherName, settings)
options.put('pattern', pattern)
// publish
step(options)
recordIssues(options)
// archive check results
archiveResults(doArchive && settings.get('archive'), pattern, true)
}
}
def reportWarnings(parserName, settings, doArchive){
if (settings.active) {
def pattern = settings.get('pattern')
def options = createCommonOptionsMap('WarningsPublisher', settings)
options.put('parserConfigurations', [[
parserName: parserName,
pattern: pattern
]])
// publish
step(options)
// archive check results
archiveResults(doArchive && settings.get('archive'), pattern, true)
archiveResults(doArchive && settings.get('archive'), settings.get('pattern'), true)
}
}
@ -154,24 +126,56 @@ def archiveResults(archive, pattern, allowEmpty){
}
@NonCPS
def createCommonOptionsMap(publisherName, settings){
def createOptions(settings){
Map result = [:]
def thresholds = settings.get('thresholds', [:])
def fail = thresholds.get('fail', [:])
def unstable = thresholds.get('unstable', [:])
result.put('blameDisabled', true)
result.put('enabledForFailure', true)
result.put('aggregatingResults', false)
result.put('$class', publisherName)
result.put('healthy', settings.get('healthy'))
result.put('unHealthy', settings.get('unHealthy'))
result.put('canRunOnFailed', true)
result.put('failedTotalAll', fail.get('all'))
result.put('failedTotalHigh', fail.get('high'))
result.put('failedTotalNormal', fail.get('normal'))
result.put('failedTotalLow', fail.get('low'))
result.put('unstableTotalAll', unstable.get('all'))
result.put('unstableTotalHigh', unstable.get('high'))
result.put('unstableTotalNormal', unstable.get('normal'))
result.put('unstableTotalLow', unstable.get('low'))
def qualityGates = []
if (settings.qualityGates)
qualityGates = qualityGates.plus(settings.qualityGates)
// handle legacy thresholds
// https://github.com/jenkinsci/warnings-ng-plugin/blob/6602c3a999b971405adda15be03979ce21cb3cbf/plugin/src/main/java/io/jenkins/plugins/analysis/core/util/QualityGate.java#L186
def thresholdsList = settings.get('thresholds', [:])
if (thresholdsList) {
for (String status : ['fail', 'unstable']) {
def thresholdsListPerStatus = thresholdsList.get(status, [:])
if (thresholdsListPerStatus) {
for (String severity : ['all', 'high', 'normal', 'low']) {
def threshold = thresholdsListPerStatus.get(severity)
if (threshold == null)
continue
threshold = threshold.toInteger() + 1
def type = "TOTAL"
if(severity != 'all')
type += "_" + severity.toUpperCase()
def gate = [threshold: threshold, type: type, unstable: status == 'unstable']
echo "[WARNING] legacy threshold found, please migrate to quality gate (piper-lib/checksPublishResults)"
echo "legacy threshold transformed to quality gate: ${gate}"
qualityGates = qualityGates.plus([gate])
}
}
}
}
result.put('qualityGates', qualityGates)
// filter empty values
result = result.findAll {
return it.value != null && it.value != ''
}
return result
}
@NonCPS
def createToolOptions(settings, additionalOptions = [:]){
Map result = [pattern: settings.get('pattern')]
if (settings.id)
result.put('id ', settings.id)
if (settings.name)
result.put('name', settings.name)
result = result.plus(additionalOptions)
// filter empty values
result = result.findAll {
return it.value != null && it.value != ''