├── .github ├── CODEOWNERS ├── dependabot.yml └── workflows │ ├── jenkins-security-scan.yml │ └── cd.yaml ├── .mvn ├── maven.config └── extensions.xml ├── src ├── main │ ├── resources │ │ ├── com │ │ │ └── sonyericsson │ │ │ │ └── jenkins │ │ │ │ └── plugins │ │ │ │ └── bfa │ │ │ │ ├── model │ │ │ │ ├── FailureCause │ │ │ │ │ ├── index.properties │ │ │ │ │ └── index.groovy │ │ │ │ ├── ScannerJobProperty │ │ │ │ │ ├── help-doNotScan.html │ │ │ │ │ └── config.jelly │ │ │ │ ├── indication │ │ │ │ │ ├── BuildLogIndication │ │ │ │ │ │ ├── help-testText.html │ │ │ │ │ │ ├── help-textSource.html │ │ │ │ │ │ ├── help-userProvidedExpression.html │ │ │ │ │ │ └── config.jelly │ │ │ │ │ └── MultilineBuildLogIndication │ │ │ │ │ │ ├── help-testText.html │ │ │ │ │ │ ├── help-textSource.html │ │ │ │ │ │ ├── help-userProvidedExpression.html │ │ │ │ │ │ └── config.jelly │ │ │ │ ├── FailureCauseColumn │ │ │ │ │ ├── columnHeader.jelly │ │ │ │ │ ├── config.jelly │ │ │ │ │ └── column.jelly │ │ │ │ ├── FailureCauseProjectAction │ │ │ │ │ └── jobMain.groovy │ │ │ │ ├── FailureCauseMatrixBuildAction │ │ │ │ │ └── badge.jelly │ │ │ │ └── FailureCauseBuildAction │ │ │ │ │ └── badge.jelly │ │ │ │ ├── CauseManagement │ │ │ │ ├── index.properties │ │ │ │ ├── remove.properties │ │ │ │ ├── resource.js │ │ │ │ ├── help-causes.html │ │ │ │ └── remove.groovy │ │ │ │ ├── db │ │ │ │ ├── MongoDBKnowledgeBase │ │ │ │ │ ├── config.properties │ │ │ │ │ └── config.jelly │ │ │ │ └── LocalFileKnowledgeBase │ │ │ │ │ └── config.jelly │ │ │ │ ├── ScanLogAction │ │ │ │ └── index.jelly │ │ │ │ ├── sod │ │ │ │ ├── ScanOnDemandBaseAction │ │ │ │ │ ├── ScanMode │ │ │ │ │ │ ├── resource.js │ │ │ │ │ │ └── index.groovy │ │ │ │ │ └── index.jelly │ │ │ │ └── ScanOnDemandVariables │ │ │ │ │ └── config.jelly │ │ │ │ ├── tokens │ │ │ │ └── Token │ │ │ │ │ └── help.groovy │ │ │ │ ├── PluginImpl │ │ │ │ └── config.properties │ │ │ │ └── Messages.properties │ │ ├── META-INF │ │ │ └── hudson.remoting.ClassFilter │ │ └── index.jelly │ ├── webapp │ │ └── help │ │ │ ├── help-SearchOption.html │ │ │ ├── help-doNotAnalyzeAbortedJobs.html │ │ │ ├── help-metricSquashingEnabled.html │ │ │ └── sod │ │ │ ├── nonscanned.html │ │ │ └── all.html │ └── java │ │ └── com │ │ └── sonyericsson │ │ └── jenkins │ │ └── plugins │ │ └── bfa │ │ ├── model │ │ ├── IFailureCauseMetricData.java │ │ ├── dbf │ │ │ ├── BuildCacheDBF.java │ │ │ ├── CoreDBF.java │ │ │ ├── DownstreamBuildFinder.java │ │ │ └── ParameterizedTriggerDBF.java │ │ ├── FailureCauseProjectAction.java │ │ ├── ScannerOffJobProperty.java │ │ ├── FailureCauseModification.java │ │ ├── indication │ │ │ └── MultilineBuildLogIndication.java │ │ ├── ScannerJobProperty.java │ │ ├── BuildLogFailureReader.java │ │ └── FailureCauseColumn.java │ │ ├── TransientActionProvider.java │ │ ├── TransientCauseManagement.java │ │ ├── sod │ │ └── ScanOnDemandTransientActionProvider.java │ │ ├── utils │ │ ├── BfaUtils.java │ │ └── ObjectCountPair.java │ │ ├── db │ │ └── Semaphore.java │ │ ├── MetricsManager.java │ │ ├── IndicationAnnotatorFactory.java │ │ ├── tokens │ │ └── TokenUtils.java │ │ ├── FailureCauseMatrixAggregator.java │ │ ├── statistics │ │ └── FailureCauseStatistics.java │ │ ├── AnnotationHelper.java │ │ ├── ScanLogAction.java │ │ ├── IndicationAnnotator.java │ │ ├── providers │ │ └── FailureCauseProvider.java │ │ └── GerritMessageProviderExtension.java ├── spotbugs │ └── excludesFilter.xml └── test │ ├── resources │ └── com │ │ └── sonyericsson │ │ └── jenkins │ │ └── plugins │ │ └── bfa │ │ ├── model │ │ ├── FailureReaderTest.zip │ │ └── FailureCauseColumnTest │ │ │ ├── build-failure-analyzer.xml │ │ │ └── config.xml │ │ ├── BackwardsCompatibilityTest │ │ ├── testMatrix120.zip │ │ ├── testLoadVersion1ConfigXml.zip │ │ ├── testReadResolveFromVersion1.zip │ │ └── testLoadOldFailureCauseWithOnlyLineNumbers.zip │ │ ├── junit.xml │ │ ├── jcasc │ │ ├── jcasc-local-expected.yml │ │ ├── jcasc-local.yml │ │ ├── jcasc-mongo-expected.yml │ │ └── jcasc-mongo.yml │ │ └── test │ │ └── utils │ │ └── DifferentKnowledgeBase │ │ └── config.jelly │ └── java │ └── com │ └── sonyericsson │ └── jenkins │ └── plugins │ └── bfa │ ├── test │ └── utils │ │ ├── MatrixSupport.java │ │ ├── PrintToLogBuilder.java │ │ └── DifferentKnowledgeBase.java │ ├── IndicationAnnotatorTest.java │ ├── tokens │ ├── TokenUtilsTest.java │ └── PipelineTokenTest.java │ ├── db │ ├── SemaphoreTest.java │ └── EmbeddedMongoTest.java │ ├── model │ ├── FailureCauseProjectActionHudsonTest.java │ └── FailureCauseColumnTest.java │ ├── PluginImplTest.java │ ├── FailureCauseWorkFlowTest.java │ ├── MetricsManagerTest.java │ └── jcasc │ ├── ConfigurationAsCodeLocalTest.java │ └── ConfigurationAsCodeMongoTest.java ├── docs ├── images │ ├── bfa-buildlog.png │ ├── bfa-buildpage.png │ ├── bfa-newfailurecause.png │ ├── cosmos-configuration.png │ └── aws-documentdb-configuration.png ├── metrics.md ├── azure.md └── documentDB.md ├── Jenkinsfile ├── .gitignore ├── checkstyle-suppressions.xml ├── README.md └── LICENSE /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @jenkinsci/build-failure-analyzer-plugin-developers 2 | -------------------------------------------------------------------------------- /.mvn/maven.config: -------------------------------------------------------------------------------- 1 | -Pconsume-incrementals 2 | -Pmight-produce-incrementals 3 | -Dchangelist.format=%d.v%s 4 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/model/FailureCause/index.properties: -------------------------------------------------------------------------------- 1 | ModifiedBy={0} by {1} 2 | -------------------------------------------------------------------------------- /docs/images/bfa-buildlog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-failure-analyzer-plugin/HEAD/docs/images/bfa-buildlog.png -------------------------------------------------------------------------------- /docs/images/bfa-buildpage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-failure-analyzer-plugin/HEAD/docs/images/bfa-buildpage.png -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/CauseManagement/index.properties: -------------------------------------------------------------------------------- 1 | Removed=Removed {0} 2 | ModifiedBy={0} by {1} 3 | -------------------------------------------------------------------------------- /docs/images/bfa-newfailurecause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-failure-analyzer-plugin/HEAD/docs/images/bfa-newfailurecause.png -------------------------------------------------------------------------------- /docs/images/cosmos-configuration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-failure-analyzer-plugin/HEAD/docs/images/cosmos-configuration.png -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | buildPlugin(useContainerAgent: true, configurations: [ 2 | [platform: 'linux', jdk: 21], 3 | [platform: 'windows', jdk: 17], 4 | ]) 5 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/hudson.remoting.ClassFilter: -------------------------------------------------------------------------------- 1 | java.util.Collections$SynchronizedList 2 | java.util.Collections$SynchronizedRandomAccessList 3 | -------------------------------------------------------------------------------- /src/spotbugs/excludesFilter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/images/aws-documentdb-configuration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-failure-analyzer-plugin/HEAD/docs/images/aws-documentdb-configuration.png -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/CauseManagement/remove.properties: -------------------------------------------------------------------------------- 1 | removeQuestion=Are you sure you want to remove the cause: [{0}] ? 2 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/model/ScannerJobProperty/help-doNotScan.html: -------------------------------------------------------------------------------- 1 | Tick this setting if you don't want the Build Failure Analyzer to scan builds of this project. 2 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/model/indication/BuildLogIndication/help-testText.html: -------------------------------------------------------------------------------- 1 | A text to match against the pattern or a URL to a build whose log should be matched against the pattern. -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | 3 | # mvn hpi:run 4 | work 5 | 6 | # IntelliJ IDEA project files 7 | *.iml 8 | *.iws 9 | *.ipr 10 | .idea 11 | 12 | # Eclipse project files 13 | .settings 14 | .classpath 15 | .project 16 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/model/indication/MultilineBuildLogIndication/help-testText.html: -------------------------------------------------------------------------------- 1 | A text to match against the pattern or a URL to a build whose log should be matched against the pattern. -------------------------------------------------------------------------------- /src/main/webapp/help/help-SearchOption.html: -------------------------------------------------------------------------------- 1 |
2 | "Scan non-scanned builds" option scans only non-scanned builds. 3 | "Scan/Rescan all the builds" option scans all the builds including scanned and non-scanned builds. 4 |
5 | -------------------------------------------------------------------------------- /src/test/resources/com/sonyericsson/jenkins/plugins/bfa/model/FailureReaderTest.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-failure-analyzer-plugin/HEAD/src/test/resources/com/sonyericsson/jenkins/plugins/bfa/model/FailureReaderTest.zip -------------------------------------------------------------------------------- /src/test/resources/com/sonyericsson/jenkins/plugins/bfa/BackwardsCompatibilityTest/testMatrix120.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-failure-analyzer-plugin/HEAD/src/test/resources/com/sonyericsson/jenkins/plugins/bfa/BackwardsCompatibilityTest/testMatrix120.zip -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/CauseManagement/resource.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", () => { 2 | document.querySelector(".bfa-cause-management-back-button").addEventListener("click", () => { 3 | history.back(1); 4 | }); 5 | }); 6 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/model/indication/BuildLogIndication/help-textSource.html: -------------------------------------------------------------------------------- 1 | A value indicating whether the text in the text field below should be matched against the pattern or 2 | be considered a URL to a build whose log should be matched against the pattern. -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/CauseManagement/help-causes.html: -------------------------------------------------------------------------------- 1 | The Cause is the description you see when an issue is found. 2 | The cause has one or more indications, if one of those indications are found in the build 3 | then the cause will be shown on the build page. 4 | -------------------------------------------------------------------------------- /src/test/resources/com/sonyericsson/jenkins/plugins/bfa/BackwardsCompatibilityTest/testLoadVersion1ConfigXml.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-failure-analyzer-plugin/HEAD/src/test/resources/com/sonyericsson/jenkins/plugins/bfa/BackwardsCompatibilityTest/testLoadVersion1ConfigXml.zip -------------------------------------------------------------------------------- /src/test/resources/com/sonyericsson/jenkins/plugins/bfa/BackwardsCompatibilityTest/testReadResolveFromVersion1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-failure-analyzer-plugin/HEAD/src/test/resources/com/sonyericsson/jenkins/plugins/bfa/BackwardsCompatibilityTest/testReadResolveFromVersion1.zip -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/db/MongoDBKnowledgeBase/config.properties: -------------------------------------------------------------------------------- 1 | MongoDBKnowledgeBase_UserNameDesc=User name for the database, leave blank if no authentication used 2 | MongoDBKnowledgeBase_PasswordDesc=Password for the database, leave blank if no authentication used 3 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/model/indication/MultilineBuildLogIndication/help-textSource.html: -------------------------------------------------------------------------------- 1 | A value indicating whether the text in the text field below should be matched against the pattern or 2 | be considered a URL to a build whose log should be matched against the pattern. -------------------------------------------------------------------------------- /src/test/resources/com/sonyericsson/jenkins/plugins/bfa/BackwardsCompatibilityTest/testLoadOldFailureCauseWithOnlyLineNumbers.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/build-failure-analyzer-plugin/HEAD/src/test/resources/com/sonyericsson/jenkins/plugins/bfa/BackwardsCompatibilityTest/testLoadOldFailureCauseWithOnlyLineNumbers.zip -------------------------------------------------------------------------------- /src/main/webapp/help/help-doNotAnalyzeAbortedJobs.html: -------------------------------------------------------------------------------- 1 |
2 | "Do not analyze aborted jobs" option forces BFA plugin to ignore all aborted jobs. It doesn't check reason why job was aborted. 3 | So, if you want to scan jobs aborted due timeout, you need to specify "Fail the build" in "Time-out actions" in job config. 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 2 |
3 | Jenkins Build Failure Analyzer. 4 | This plugin scans build logs and other files in the workspace for recognised patterns 5 | of known causes to build failures, and displays them on the build page for quicker 6 | recognition of why the build failed. 7 |
8 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 2 | --- 3 | version: 2 4 | updates: 5 | - package-ecosystem: "maven" 6 | directory: "/" 7 | schedule: 8 | interval: "weekly" 9 | - package-ecosystem: github-actions 10 | directory: / 11 | schedule: 12 | interval: monthly 13 | -------------------------------------------------------------------------------- /.mvn/extensions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | io.jenkins.tools.incrementals 4 | git-changelist-maven-extension 5 | 1.13 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/model/IFailureCauseMetricData.java: -------------------------------------------------------------------------------- 1 | package com.sonyericsson.jenkins.plugins.bfa.model; 2 | 3 | import java.util.List; 4 | 5 | public interface IFailureCauseMetricData { 6 | /** 7 | * Getter for the name. 8 | * @return the name 9 | */ 10 | String getName(); 11 | 12 | /** 13 | * Getter for the categories. 14 | * @return the categories 15 | */ 16 | List getCategories(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/webapp/help/help-metricSquashingEnabled.html: -------------------------------------------------------------------------------- 1 |
2 | "Squash failure metrics to unique categories for each build" option can be useful when a single failed build should 3 | count towards each cause category exactly once. This is particularly useful when combined with the "Treat failed 4 | test cases as failure causes." If numerous tests fail, "squash failure metrics" will prevent those categories 5 | from being incremented for every single failed test, which can skew metrics significantly. 6 |
7 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/ScanLogAction/index.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |

7 | ${%Failure Cause Scan Log} 8 |

9 |
${it.getLogText()}
10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/sod/ScanOnDemandBaseAction/ScanMode/resource.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", () => { 2 | document.querySelectorAll(".bfa-scan-mode-build-type-radio-entry").forEach((entry) => { 3 | const { rootUrl, optionFullUrl } = entry.querySelector(".bfa-entry-data-holder").dataset; 4 | 5 | entry.querySelector(".jenkins-radio").addEventListener("click", () => { 6 | document.location = `${rootURL}/${optionFullUrl}`; 7 | }); 8 | }) 9 | }); 10 | -------------------------------------------------------------------------------- /src/test/resources/com/sonyericsson/jenkins/plugins/bfa/junit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Here are details of the failure... 6 | 7 | 8 | More details 9 | 10 | 11 | -------------------------------------------------------------------------------- /checkstyle-suppressions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 10 | 12 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/test/resources/com/sonyericsson/jenkins/plugins/bfa/jcasc/jcasc-local-expected.yml: -------------------------------------------------------------------------------- 1 | doNotAnalyzeAbortedJob: true 2 | gerritTriggerEnabled: true 3 | globalEnabled: true 4 | graphsEnabled: false 5 | knowledgeBase: "localFile" 6 | maxLogSize: 10 7 | metricSquashingEnabled: false 8 | noCausesEnabled: true 9 | noCausesMessage: "No problems were identified. Please contribute causes to help others" 10 | nrOfScanThreads: 6 11 | slackFailureCategories: "ALL" 12 | slackNotifEnabled: false 13 | sodVariables: 14 | maximumSodWorkerThreads: 7 15 | minimumSodWorkerThreads: 2 16 | sodCorePoolNumberOfThreads: 6 17 | sodThreadKeepAliveTime: 17 18 | sodWaitForJobShutdownTimeout: 32 19 | testResultCategories: "hgjghhlllllaa" 20 | testResultParsingEnabled: true 21 | -------------------------------------------------------------------------------- /src/test/resources/com/sonyericsson/jenkins/plugins/bfa/jcasc/jcasc-local.yml: -------------------------------------------------------------------------------- 1 | unclassified: 2 | buildFailureAnalyzer: 3 | doNotAnalyzeAbortedJob: true 4 | gerritTriggerEnabled: true 5 | globalEnabled: true 6 | graphsEnabled: false 7 | knowledgeBase: "localFile" 8 | maxLogSize: 10 9 | metricSquashingEnabled: false 10 | noCausesEnabled: true 11 | noCausesMessage: "No problems were identified. Please contribute causes to help others" 12 | nrOfScanThreads: 6 13 | slackNotifEnabled: false 14 | sodVariables: 15 | maximumSodWorkerThreads: 7 16 | minimumSodWorkerThreads: 2 17 | sodCorePoolNumberOfThreads: 6 18 | sodThreadKeepAliveTime: 17 19 | sodWaitForJobShutdownTimeout: 32 20 | testResultCategories: "hgjghhlllllaa" 21 | testResultParsingEnabled: true 22 | -------------------------------------------------------------------------------- /.github/workflows/jenkins-security-scan.yml: -------------------------------------------------------------------------------- 1 | # Jenkins Security Scan 2 | # For more information, see: https://www.jenkins.io/doc/developer/security/scan/ 3 | --- 4 | name: Jenkins Security Scan 5 | 6 | on: 7 | push: 8 | branches: 9 | - master 10 | pull_request: 11 | types: [ opened, synchronize, reopened ] 12 | workflow_dispatch: 13 | 14 | permissions: 15 | security-events: write 16 | contents: read 17 | actions: read 18 | 19 | jobs: 20 | security-scan: 21 | uses: jenkins-infra/jenkins-security-scan/.github/workflows/jenkins-security-scan.yaml@v2 22 | with: 23 | java-cache: 'maven' # Optionally enable use of a build dependency cache. Specify 'maven' or 'gradle' as appropriate. 24 | # java-version: 21 # Optionally specify what version of Java to set up for the build, or remove to use a recent default. 25 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/model/dbf/BuildCacheDBF.java: -------------------------------------------------------------------------------- 1 | package com.sonyericsson.jenkins.plugins.bfa.model.dbf; 2 | 3 | import com.axis.system.jenkins.plugins.downstream.cache.BuildCache; 4 | import hudson.Extension; 5 | import hudson.model.Run; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | /** 11 | * Gets downstream builds using the build-cache plugin. This should cover most scenarios. 12 | * 13 | * @author Stephan Pauxberger 14 | */ 15 | @Extension(optional = true) 16 | public class BuildCacheDBF extends DownstreamBuildFinder { 17 | static { 18 | BuildCache.getCache(); 19 | } 20 | @Override 21 | public List> getDownstreamBuilds(Run build) { 22 | //noinspection unchecked 23 | return new ArrayList(BuildCache.getCache().getDownstreamBuilds(build)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Build Failure Analyzer Plugin 2 | 3 | This plugin scans build logs and other files in the workspace for recognised patterns 4 | of known causes to build failures and displays them on the build page for quicker 5 | recognition of why the build failed. 6 | 7 | ## Maintainers 8 | 9 | * Robert Sandell 10 | - robert.sandell@cloudbees.com 11 | - sandell.robert@gmail.com 12 | 13 | * Tomas Westling 14 | - tomas.westling@axis.com 15 | 16 | ## Guides 17 | 18 | * [Azure Cosmos DB](docs/azure.md) 19 | * [Metrics Integration](docs/metrics.md) 20 | 21 | ## Community Resources 22 | * [Changelog](https://github.com/jenkinsci/build-failure-analyzer-plugin/releases) 23 | * [User Guide](https://plugins.jenkins.io/build-failure-analyzer/) 24 | 25 | # License 26 | MIT License 27 | 28 | 29 | Icon from Tango Icon Library 0.8.90 http://tango.freedesktop.org/Tango_Icon_Library 30 | -------------------------------------------------------------------------------- /src/test/resources/com/sonyericsson/jenkins/plugins/bfa/jcasc/jcasc-mongo-expected.yml: -------------------------------------------------------------------------------- 1 | doNotAnalyzeAbortedJob: true 2 | gerritTriggerEnabled: true 3 | globalEnabled: true 4 | graphsEnabled: false 5 | knowledgeBase: 6 | mongoDB: 7 | dbName: "bfa" 8 | enableStatistics: true 9 | host: "localhost" 10 | 11 | port: 27017 12 | successfulLogging: false 13 | userName: "bfa" 14 | maxLogSize: 10 15 | metricSquashingEnabled: false 16 | noCausesEnabled: true 17 | noCausesMessage: "No problems were identified. Please contribute causes to help others" 18 | nrOfScanThreads: 6 19 | slackFailureCategories: "ALL" 20 | slackNotifEnabled: false 21 | sodVariables: 22 | maximumSodWorkerThreads: 7 23 | minimumSodWorkerThreads: 2 24 | sodCorePoolNumberOfThreads: 6 25 | sodThreadKeepAliveTime: 17 26 | sodWaitForJobShutdownTimeout: 32 27 | testResultCategories: "hgjghhlllllaa" 28 | testResultParsingEnabled: true 29 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/model/indication/BuildLogIndication/help-userProvidedExpression.html: -------------------------------------------------------------------------------- 1 |
2 |

A regular 3 | expression to find in the build log.

4 |

The regular expression should match the entire line, so if you are looking for FATAL first in the line 5 | but don't know what comes after it, your expression should be ^FATAL.*

6 |

Substitutions may be made within the description with placeholders of the form ${I,G}, where 7 | I is the indication number and G is the captured group within the indication 8 | expression. e.g., ${1,1} would be replaced with the first indication's first captured group 9 | and ${1,2} would be replaced with the first indication's second captured group.

10 |
11 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/model/indication/MultilineBuildLogIndication/help-userProvidedExpression.html: -------------------------------------------------------------------------------- 1 |
2 |

A regular 3 | expression to find in the build log.

4 |

Note that you should not specify ".*" within your multi-line pattern unless you actually want to match every 5 | character. ".*FOO.*" will match the entire build log, assuming it contains "FOO" somewhere.

6 |

Substitutions may be made within the description with placeholders of the form ${I,G}, where 7 | I is the indication number and G is the captured group within the indication 8 | expression. e.g., ${1,1} would be replaced with the first indication's first captured group 9 | and ${1,2} would be replaced with the first indication's second captured group.

10 |
11 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/tokens/Token/help.groovy: -------------------------------------------------------------------------------- 1 | dt("\${BUILD_FAILURE_ANALYZER}") 2 | dd() { 3 | span("Displays found causes by the Build Failure Analyzer.") 4 | dl() { 5 | dt("includeIndications") 6 | dd("When true, the indication numbers and links into the console log are included in the token replacement text.") 7 | 8 | dt("useHtmlFormat") 9 | dd("When true, the replacement text will be an HTML snippet.") 10 | 11 | dt("includeTitle") 12 | dd("When true, the title will appear in the token replacement text.") 13 | 14 | dt("wrapWidth") 15 | dd("Wrap long lines at this width. If wrapWidth is 0, the text isn't wrapped. Only applies if useHtmlFormat == false.") 16 | 17 | dt("noFailureText") 18 | dd("Text to return when no failure cause is present.") 19 | 20 | dt("escapeHtml") 21 | dd("If true, any HTML specific code will be escaped. Only applies if useHtmlFormat == false. Defaults to false.") 22 | } 23 | } -------------------------------------------------------------------------------- /src/test/resources/com/sonyericsson/jenkins/plugins/bfa/jcasc/jcasc-mongo.yml: -------------------------------------------------------------------------------- 1 | unclassified: 2 | buildFailureAnalyzer: 3 | doNotAnalyzeAbortedJob: true 4 | gerritTriggerEnabled: true 5 | globalEnabled: true 6 | graphsEnabled: false 7 | knowledgeBase: 8 | mongoDB: 9 | dbName: "bfa" 10 | enableStatistics: true 11 | host: "localhost" 12 | userName: bfa 13 | password: changeme 14 | port: 27017 15 | successfulLogging: false 16 | maxLogSize: 10 17 | metricSquashingEnabled: false 18 | noCausesEnabled: true 19 | noCausesMessage: "No problems were identified. Please contribute causes to help others" 20 | nrOfScanThreads: 6 21 | slackNotifEnabled: false 22 | sodVariables: 23 | maximumSodWorkerThreads: 7 24 | minimumSodWorkerThreads: 2 25 | sodCorePoolNumberOfThreads: 6 26 | sodThreadKeepAliveTime: 17 27 | sodWaitForJobShutdownTimeout: 32 28 | testResultCategories: "hgjghhlllllaa" 29 | testResultParsingEnabled: true 30 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/PluginImpl/config.properties: -------------------------------------------------------------------------------- 1 | enableGerritTriggerDescription=This option allows BFA to forward the description of the found causes to the Gerrit-Trigger-plugin, ultimately allowing users to see their build issues directly inside Gerrit. 2 | nrOfScanThreadsDescription=Number of threads per build to use when scanning the failed builds. 3 | testResultParsingEnabledDescription=Treat failed test cases (as indicated by JUnit/xUnit/... publishers) as failure causes. 4 | testResultCategoriesDescription=A space-separated list of categories to use for failure causes representing failed test cases. 5 | maxLogSize=Log file with size that exceeds limit (in MB) would not be scanned, 0 - disables this check 6 | fallbackCategoriesDescription=Space separated list of category names that marks fallback causes. Fallback causes will only be applied if there are no non-fallback causes found. 7 | metricSquashingEnabledDescription=Prevents a single failed build from counting categories multiple times if multiple failures causes are identified with the same categories. 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright 2012 Sony Ericsson Mobile Communications. All rights reserved. 4 | Copyright 2012 Sony Mobile Communications AB. All rights reserved. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/Messages.properties: -------------------------------------------------------------------------------- 1 | #I18n messages. 2 | PermissionGroup_Title=Build Failure Analyzer 3 | PermissionView_Description=View Failure causes. 4 | PermissionUpdate_Description=Add and Update Failure causes. 5 | PermissionRemove_Description=Remove Failure causes. 6 | BuildLogIndication_DisplayName=Build Log Indication 7 | MultilineBuildLogIndication_DisplayName=Multi-Line Build Log Indication 8 | CauseManagement_DisplayName=Failure Cause Management 9 | ScanLogAction_DisplayName=Failure Scan Log 10 | CauseList_DisplayName=Failure Causes 11 | ScannerJobProperty_DisplayName=Do not Scan failed builds 12 | LocalFileKnowledgeBase_DisplayName=Jenkins Local 13 | MongoDBKnowledgeBase_DisplayName=Mongo DB 14 | MongoDBKnowledgeBase_ConnectionError=Could not connect 15 | MongoDBKnowledgeBase_ConnectionOK=Connection OK! 16 | StringMatchesPattern=String matches pattern 17 | StringDoesNotMatchPattern=String does not match pattern 18 | InvalidPattern_Error=Invalid pattern 19 | InvalidURL_Error=Invalid URL 20 | FailedToScanFile_Error=Failed to scan file 21 | FailureScan_DisplayName=Failure Scan Options 22 | SodAccessDeniedException={0} is missing the {1} or {2} permission 23 | ScanOnDemandBaseAction_NonScanned_DisplayName=Only non-scanned builds 24 | ScanOnDemandBaseAction_AllBuilds_DisplayName=All builds 25 | -------------------------------------------------------------------------------- /src/test/java/com/sonyericsson/jenkins/plugins/bfa/test/utils/MatrixSupport.java: -------------------------------------------------------------------------------- 1 | package com.sonyericsson.jenkins.plugins.bfa.test.utils; 2 | 3 | import hudson.matrix.MatrixProject; 4 | import org.jvnet.hudson.test.JenkinsRule; 5 | 6 | import java.io.IOException; 7 | 8 | /** 9 | * Jenkins Rule with extra methods for {@link MatrixProject}s. 10 | */ 11 | public final class MatrixSupport { 12 | 13 | private MatrixSupport() { 14 | // hidden 15 | } 16 | 17 | /** 18 | * Create matrix project. 19 | * 20 | * @param jenkins 21 | * 22 | * @return Project 23 | * 24 | * @throws IOException Failed to save the project 25 | */ 26 | public static MatrixProject createMatrixProject(JenkinsRule jenkins) throws IOException { 27 | return jenkins.createProject(MatrixProject.class, "test" + jenkins.jenkins.getItems().size()); 28 | } 29 | 30 | /** 31 | * Create matrix project. 32 | * 33 | * @param jenkins 34 | * @param name Project name 35 | * 36 | * @return Project 37 | * 38 | * @throws IOException Failed to save the project 39 | */ 40 | public static MatrixProject createMatrixProject(JenkinsRule jenkins, String name) throws IOException { 41 | return jenkins.createProject(MatrixProject.class, name); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/sod/ScanOnDemandVariables/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 9 | 10 | 11 | 13 | 14 | 15 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/main/webapp/help/sod/nonscanned.html: -------------------------------------------------------------------------------- 1 | 24 | 25 |

26 | Scan only builds that have not already been scanned. 27 |

-------------------------------------------------------------------------------- /src/main/webapp/help/sod/all.html: -------------------------------------------------------------------------------- 1 | 24 | 25 |

26 | Scan all the builds including already scanned and non-scanned builds. 27 |

-------------------------------------------------------------------------------- /docs/metrics.md: -------------------------------------------------------------------------------- 1 | # Metrics Integration 2 | 3 | This is a guide for the integration with the [Metrics plugin](https://plugins.jenkins.io/metrics/). 4 | 5 | ## Metrics 6 | 7 | The integration provides counters for each individual cause and category that you create. These counters will reset to zero when jenkins is restarted. The format for the metrics created is `jenkins_bfa_category_` for each category and `jenkins_bfa_cause_` for each cause. The category and cause names will be escaped by the metrics api to replace any spaces with underscores. 8 | 9 | ## Exporting 10 | 11 | To export the BFA metrics you can use any plugin that integrates with the Metrics plugin. 12 | 13 | ### Prometheus 14 | The [prometheus plugin](https://plugins.jenkins.io/prometheus/) 15 | To restructure the metrics into the form that prometheus expects you can add the following into your scrape config: 16 | 17 | ```yaml 18 | metric_relabel_configs: 19 | - source_labels: [__name__] 20 | regex: 'jenkins_bfa_category_(.*)' 21 | target_label: 'category' 22 | - source_labels: [__name__] 23 | regex: 'jenkins_bfa_cause_(.*)' 24 | target_label: 'cause' 25 | - source_labels: [__name__] 26 | regex: 'jenkins_bfa_(.*)_(.*)' 27 | replacement: 'jenkins_bfa' 28 | target_label: __name__ 29 | ``` 30 | 31 | This will provide a metric called `jenkins_bfa` with labels for the category and specific cause. 32 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/db/LocalFileKnowledgeBase/config.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/model/FailureCauseColumn/columnHeader.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/model/FailureCauseColumn/config.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/sod/ScanOnDemandBaseAction/index.jelly: -------------------------------------------------------------------------------- 1 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/model/FailureCauseProjectAction/jobMain.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2014 Red Hat, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.sonyericsson.jenkins.plugins.bfa.model.FailureCauseProjectAction; 26 | 27 | st = namespace("jelly:stapler"); 28 | 29 | action = it.action; 30 | if (action != null) { 31 | table(style: "margin-left: 1em;") { 32 | st.include(it: action, page: "summary") 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/resources/com/sonyericsson/jenkins/plugins/bfa/model/FailureCauseColumnTest/build-failure-analyzer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | No problems were identified. If you know why this problem occurred, please add a suitable Cause for it. 4 | 5 | 6 | 7 | fa3ad321-4f70-46da-af45-1304dca50146 8 | 9 | fa3ad321-4f70-46da-af45-1304dca50146 10 | Failure Builder 11 | Simulating a failure 12 | 13 | 14 | .*Simulating a specific result code.*FAILURE.* 15 | 16 | 17 | 18 | 19 | 20 | 21 | 3 22 | 23 | 1 24 | 1 25 | 15 26 | 30 27 | 5 28 | 29 | -------------------------------------------------------------------------------- /src/test/resources/com/sonyericsson/jenkins/plugins/bfa/test/utils/DifferentKnowledgeBase/config.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/model/ScannerJobProperty/config.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | The Build Failure Analyzer will not scan builds of this project. 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/model/FailureCauseMatrixBuildAction/badge.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/test/java/com/sonyericsson/jenkins/plugins/bfa/IndicationAnnotatorTest.java: -------------------------------------------------------------------------------- 1 | package com.sonyericsson.jenkins.plugins.bfa; 2 | 3 | import com.sonyericsson.jenkins.plugins.bfa.model.FailureCause; 4 | import com.sonyericsson.jenkins.plugins.bfa.model.FoundFailureCause; 5 | import com.sonyericsson.jenkins.plugins.bfa.model.indication.FoundIndication; 6 | import hudson.MarkupText; 7 | import org.junit.jupiter.api.Test; 8 | import org.jvnet.hudson.test.Issue; 9 | import java.util.ArrayList; 10 | 11 | import static org.junit.jupiter.api.Assertions.assertTrue; 12 | import java.util.List; 13 | 14 | /** 15 | * Tests for the IndicationAnnotator. 16 | * 17 | * @author Tomas Westling <tomas.westling@axis.com> 18 | */ 19 | class IndicationAnnotatorTest { 20 | 21 | private static final String EXPECTED_ANNOTATED_TEXT = "tilt" onmouseover=alert(1) foo="bar"; 22 | 23 | /** 24 | * Tests that html is escaped correctly when annotating text. 25 | */ 26 | @Issue("SECURITY-3244") 27 | @Test 28 | void testAnnotate() { 29 | MarkupText text = new MarkupText("matchingString"); 30 | FoundIndication fi = new FoundIndication( 31 | "pattern", "matchingFile", "matchingString"); 32 | List fis = new ArrayList<>(); 33 | fis.add(fi); 34 | FoundFailureCause ffc = new FoundFailureCause( 35 | new FailureCause("tilt\" onmouseover=alert(1) foo=\"bar", "description"), fis); 36 | List foundFailureCauses = new ArrayList<>(); 37 | foundFailureCauses.add(ffc); 38 | IndicationAnnotator ia = new IndicationAnnotator(foundFailureCauses); 39 | ia.annotate(null, text); 40 | assertTrue(text.toString(false).contains(EXPECTED_ANNOTATED_TEXT)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/model/FailureCauseBuildAction/badge.jelly: -------------------------------------------------------------------------------- 1 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/model/FailureCauseColumn/column.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | ${firstCause.name} 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /.github/workflows/cd.yaml: -------------------------------------------------------------------------------- 1 | # Note: additional setup is required, see https://www.jenkins.io/redirect/continuous-delivery-of-plugins 2 | # 3 | # Please find additional hints for individual trigger use case 4 | # configuration options inline this script below. 5 | # 6 | --- 7 | name: cd 8 | on: 9 | workflow_dispatch: 10 | inputs: 11 | validate_only: 12 | required: false 13 | type: boolean 14 | description: | 15 | Run validation with release drafter only 16 | → Skip the release job 17 | # Note: Change this default to true, 18 | # if the checkbox should be checked by default. 19 | default: false 20 | # If you don't want any automatic trigger in general, then 21 | # the following check_run trigger lines should all be commented. 22 | # Note: Consider the use case #2 config for 'validate_only' below 23 | # as an alternative option! 24 | check_run: 25 | types: 26 | - completed 27 | 28 | permissions: 29 | checks: read 30 | contents: write 31 | 32 | jobs: 33 | maven-cd: 34 | uses: jenkins-infra/github-reusable-workflows/.github/workflows/maven-cd.yml@v1 35 | with: 36 | # Comment / uncomment the validate_only config appropriate to your preference: 37 | # 38 | # Use case #1 (automatic release): 39 | # - Let any successful Jenkins build trigger another release, 40 | # if there are merged pull requests of interest 41 | # - Perform a validation only run with drafting a release note, 42 | # if manually triggered AND inputs.validate_only has been checked. 43 | # 44 | validate_only: ${{ inputs.validate_only == true }} 45 | # 46 | # Alternative use case #2 (no automatic release): 47 | # - Same as use case #1 - but: 48 | # - Let any check_run trigger a validate_only run. 49 | # => enforce the release job to be skipped. 50 | # 51 | #validate_only: ${{ inputs.validate_only == true || github.event_name == 'check_run' }} 52 | secrets: 53 | MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} 54 | MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }} 55 | -------------------------------------------------------------------------------- /src/test/java/com/sonyericsson/jenkins/plugins/bfa/tokens/TokenUtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.sonyericsson.jenkins.plugins.bfa.tokens; 2 | import org.junit.jupiter.api.Test; 3 | import java.util.List; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | 7 | /** 8 | * Tests that the plugin can wrap token macro output. 9 | */ 10 | class TokenUtilsTest { 11 | private static final String TEST_TEXT = """ 12 | Lorem ipsum dolor sit amet, 13 | consectetur adipiscing elit. Nulla euismod sapien ligula, 14 | 15 | ac euismod quam aliquet vel. 16 | Duis quam augue, tristique in mi ac, scelerisque 17 | euismod nibh. 18 | 19 | Nulla accumsan velit nec neque sollicitudin, 20 | eget sagittis purus vestibulum. Nunc cursus ornare sapien 21 | sit amet hendrerit. Proin non nisi sapien."""; 22 | 23 | /** 24 | * Test that wrap() with no additional wrapping works appropriately. 25 | * 26 | */ 27 | @Test 28 | void testNoAdditionalWrap() { 29 | final int noWrapping = 0; 30 | final List unwrappedLines = TokenUtils.wrap(TEST_TEXT, noWrapping); 31 | System.out.println("Unwrapped lines:"); 32 | for (final String line : unwrappedLines) { 33 | System.out.println(line); 34 | } 35 | final int expectedNoWrappingLineCount = 10; 36 | assertEquals(expectedNoWrappingLineCount, unwrappedLines.size()); 37 | } 38 | 39 | /** 40 | * Test that wrap() works appropriately. 41 | * 42 | */ 43 | @Test 44 | void testWrap() { 45 | final int wrapAt35 = 35; 46 | final List wrappedAt35 = TokenUtils.wrap(TEST_TEXT, wrapAt35); 47 | System.out.println("Wrapped at 35:"); 48 | for (final String line : wrappedAt35) { 49 | System.out.println(line); 50 | } 51 | final int expectedWrapAt35LineCount = 15; 52 | assertEquals(expectedWrapAt35LineCount, wrappedAt35.size()); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/com/sonyericsson/jenkins/plugins/bfa/test/utils/PrintToLogBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2012 Sony Ericsson Mobile Communications. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.sonyericsson.jenkins.plugins.bfa.test.utils; 26 | 27 | import hudson.Launcher; 28 | import hudson.model.AbstractBuild; 29 | import hudson.model.BuildListener; 30 | import hudson.tasks.Builder; 31 | 32 | /** 33 | * A builder that writes something in the build log. 34 | * 35 | * @author Robert Sandell, Tomas Westling 36 | */ 37 | public class PrintToLogBuilder extends Builder { 38 | private final String toPrint; 39 | 40 | /** 41 | * Standard Constructor. 42 | * 43 | * @param toPrint the thing to print. 44 | */ 45 | public PrintToLogBuilder(String toPrint) { 46 | this.toPrint = toPrint; 47 | } 48 | 49 | @Override 50 | public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) { 51 | listener.getLogger().println(toPrint); 52 | return true; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/TransientActionProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2012 Sony Ericsson Mobile Communications. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.sonyericsson.jenkins.plugins.bfa; 26 | 27 | import hudson.Extension; 28 | import hudson.model.Action; 29 | import hudson.model.Job; 30 | import jenkins.model.TransientActionFactory; 31 | 32 | import java.util.Collection; 33 | import java.util.Collections; 34 | 35 | /** 36 | * @author Robert Sandell <robert.sandell@sonyericsson.com> 37 | */ 38 | @Extension 39 | public class TransientActionProvider extends TransientActionFactory { 40 | 41 | 42 | @Override 43 | public Class type() { 44 | return Job.class; 45 | } 46 | 47 | @Override 48 | public Collection createFor(Job target) { 49 | if (PluginImpl.shouldScan(target)) { 50 | return Collections.singleton(new TransientCauseManagement(target)); 51 | } else { 52 | return Collections.emptyList(); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/TransientCauseManagement.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2012 Sony Ericsson Mobile Communications. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.sonyericsson.jenkins.plugins.bfa; 26 | 27 | import hudson.model.Item; 28 | import hudson.model.ModelObject; 29 | 30 | /** 31 | * A {@link CauseManagement} page that appears on all Project pages via {@link TransientActionProvider}. 32 | * 33 | * @author Robert Sandell <robert.sandell@sonyericsson.com> 34 | */ 35 | public class TransientCauseManagement extends CauseManagement { 36 | 37 | private Item owner; 38 | 39 | /** 40 | * Standard constructor. 41 | * 42 | * @param owner the "owner" of this action. Used to render the side panel. 43 | */ 44 | public TransientCauseManagement(Item owner) { 45 | this.owner = owner; 46 | } 47 | 48 | @Override 49 | public ModelObject getOwner() { 50 | return owner; 51 | } 52 | 53 | @Override 54 | protected String getOwnerUrl() { 55 | return "/" + owner.getUrl(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/sod/ScanOnDemandTransientActionProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2012 Sony Mobile Communications AB. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.sonyericsson.jenkins.plugins.bfa.sod; 25 | 26 | import com.sonyericsson.jenkins.plugins.bfa.PluginImpl; 27 | import hudson.Extension; 28 | import hudson.model.Action; 29 | import hudson.model.Job; 30 | 31 | import java.util.Arrays; 32 | import java.util.Collection; 33 | import java.util.Collections; 34 | 35 | import jenkins.model.TransientActionFactory; 36 | 37 | /** 38 | * Extension point for inserting SOD Transient Actions 39 | * into the Abstract project. 40 | * 41 | * @author Shemeer Sulaiman <shemeer.x.sulaiman@sonymobile.com> 42 | */ 43 | @Extension 44 | public class ScanOnDemandTransientActionProvider extends TransientActionFactory { 45 | 46 | @Override 47 | public Class type() { 48 | return Job.class; 49 | } 50 | 51 | @Override 52 | public Collection createFor(Job target) { 53 | if (PluginImpl.shouldScan(target)) { 54 | final ScanOnDemandBaseAction sodBaseAction = new ScanOnDemandBaseAction(target); 55 | if (sodBaseAction.hasPermission()) { 56 | return Arrays.asList(sodBaseAction); 57 | } 58 | } 59 | return Collections.emptyList(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/model/FailureCauseProjectAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2014 Red Hat, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.sonyericsson.jenkins.plugins.bfa.model; 25 | 26 | import edu.umd.cs.findbugs.annotations.NonNull; 27 | import hudson.model.InvisibleAction; 28 | 29 | import hudson.model.Job; 30 | import hudson.model.Run; 31 | import org.kohsuke.accmod.Restricted; 32 | import org.kohsuke.accmod.restrictions.NoExternalUse; 33 | 34 | /** 35 | * Project action showing failure cause of last build, if any. 36 | * 37 | * @author ogondza 38 | */ 39 | @Restricted(NoExternalUse.class) 40 | public class FailureCauseProjectAction extends InvisibleAction { 41 | 42 | private final Job job; 43 | 44 | /** 45 | * @param job A project to report. 46 | */ 47 | public FailureCauseProjectAction(@NonNull Job job) { 48 | this.job = job; 49 | } 50 | 51 | /** 52 | * @return Build action to report. 53 | */ 54 | public FailureCauseBuildAction getAction() { 55 | Run build = job.getLastCompletedBuild(); 56 | if (build == null) { 57 | return null; 58 | } 59 | 60 | FailureCauseBuildAction action = build.getAction(FailureCauseBuildAction.class); 61 | if (action == null) { 62 | return null; 63 | } 64 | 65 | return action; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/utils/BfaUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2013 Sony Mobile Communications AB. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.sonyericsson.jenkins.plugins.bfa.utils; 26 | 27 | import java.io.IOException; 28 | import java.net.URL; 29 | import java.util.logging.Level; 30 | import java.util.logging.Logger; 31 | 32 | import jenkins.model.Jenkins; 33 | 34 | /** 35 | * Utility class. 36 | * 37 | * @author Fredrik Persson <fredrik6.persson@sonymobile.com> 38 | * 39 | */ 40 | public final class BfaUtils { 41 | 42 | private static final Logger logger = Logger.getLogger(BfaUtils.class.getName()); 43 | 44 | /** 45 | * Utility classes should not have a public or default constructor. 46 | */ 47 | private BfaUtils() { 48 | } 49 | 50 | /** 51 | * Gets the Jenkins master name. 52 | * @return the master name 53 | */ 54 | public static String getMasterName() { 55 | String masterString = Jenkins.getInstance().getRootUrl(); 56 | String name = null; 57 | 58 | if (masterString == null) { 59 | logger.log(Level.WARNING, "Couldn't get name of master: Jenkins root url is null"); 60 | } else { 61 | try { 62 | name = new URL(masterString).getHost(); 63 | } catch (IOException e) { 64 | logger.log(Level.WARNING, "Couldn't get name of master: ", e); 65 | } 66 | } 67 | return name; 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/db/Semaphore.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2012 Sony Mobile Communications AB. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.sonyericsson.jenkins.plugins.bfa.db; 25 | 26 | /** 27 | * "Real" binary semaphore, where subsequent calls to release do not 28 | * make the semaphore be able to acquire more than the maximum permits. 29 | * @author Tomas Westling <tomas.westling@sonyericsson.com> 30 | */ 31 | public class Semaphore { 32 | 33 | private java.util.concurrent.Semaphore semaphoreLock; 34 | 35 | /** 36 | * Standard constructor. 37 | */ 38 | public Semaphore() { 39 | semaphoreLock = new java.util.concurrent.Semaphore(0); 40 | } 41 | 42 | /** 43 | * @see java.util.concurrent.Semaphore#acquire() 44 | * The difference is that this tries to acquire all available permits if there are any and 1 if there are none. 45 | * @throws InterruptedException if the java.util.concurrent.Semaphore is interrupted. 46 | */ 47 | public void acquire() throws InterruptedException { 48 | int take; 49 | if (semaphoreLock.availablePermits() < 1) { 50 | take = 1; 51 | } else { 52 | take = semaphoreLock.availablePermits(); 53 | } 54 | semaphoreLock.acquire(take); 55 | } 56 | 57 | /** 58 | * @see java.util.concurrent.Semaphore#release() 59 | * Releases a permit, returning it to the semaphore. 60 | */ 61 | public void release() { 62 | semaphoreLock.release(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/model/indication/BuildLogIndication/config.jelly: -------------------------------------------------------------------------------- 1 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 45 | 46 | 47 | 48 | 49 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/model/indication/MultilineBuildLogIndication/config.jelly: -------------------------------------------------------------------------------- 1 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 45 | 46 | 47 | 48 | 49 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/db/MongoDBKnowledgeBase/config.jelly: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/test/java/com/sonyericsson/jenkins/plugins/bfa/db/SemaphoreTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2012 Sony Mobile Communications AB. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.sonyericsson.jenkins.plugins.bfa.db; 25 | 26 | import com.sonyericsson.jenkins.plugins.bfa.test.utils.Whitebox; 27 | 28 | import java.util.concurrent.TimeUnit; 29 | import org.junit.jupiter.api.Test; 30 | import org.junit.jupiter.api.Timeout; 31 | 32 | import static org.junit.jupiter.api.Assertions.assertEquals; 33 | 34 | //CS IGNORE MagicNumber FOR NEXT 100 LINES. REASON: TestData. 35 | 36 | /** 37 | * Tests for the Semaphore. 38 | * @author Tomas Westling <tomas.westling@sonyericsson.com> 39 | */ 40 | class SemaphoreTest { 41 | 42 | /** 43 | * Tests that acquire and release works in the the correct way for the Semaphore. 44 | * @throws Exception if so. 45 | */ 46 | @Test 47 | @Timeout(value = 20000, unit = TimeUnit.MILLISECONDS) 48 | void testAcquireAndRelease() throws Exception { 49 | Semaphore semaphore = new Semaphore(); 50 | java.util.concurrent.Semaphore innerSemaphore = Whitebox.getInternalState(semaphore, "semaphoreLock"); 51 | assertEquals(0, 52 | innerSemaphore.availablePermits(), 53 | "The semaphore should have no available permits to start with"); 54 | semaphore.release(); 55 | semaphore.release(); 56 | assertEquals(2, innerSemaphore.availablePermits(), "The semaphore should have 2 available permits"); 57 | semaphore.acquire(); 58 | assertEquals(0, innerSemaphore.availablePermits(), "All of the semaphore's permits should be taken"); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/model/ScannerOffJobProperty.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2012 Sony Mobile Communications AB. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.sonyericsson.jenkins.plugins.bfa.model; 26 | 27 | import hudson.model.AbstractProject; 28 | import hudson.model.JobProperty; 29 | 30 | import java.io.Serializable; 31 | 32 | /** 33 | * A JobProperty that flags a job that should not be scanned. 34 | * 35 | * @author Robert Sandell <robert.sandell@sonyericsson.com> 36 | * @deprecated {@link ScannerJobProperty} is used instead, but this is kept to be able to de-serialize old jobs. 37 | */ 38 | @Deprecated 39 | public class ScannerOffJobProperty extends JobProperty> implements Serializable { 40 | private boolean doNotScan; 41 | 42 | /** 43 | * Standard Constructor. 44 | * 45 | * @param doNotScan signal that builds of this job should not be scanned. 46 | */ 47 | public ScannerOffJobProperty(boolean doNotScan) { 48 | this.doNotScan = doNotScan; 49 | } 50 | 51 | /** 52 | * Default Constructor. Do not use unless you are a serializer! 53 | */ 54 | public ScannerOffJobProperty() { 55 | } 56 | 57 | /** 58 | * The value. True turns the scanner off. 59 | * 60 | * @return if no scan should be done. 61 | */ 62 | public boolean isDoNotScan() { 63 | return doNotScan; 64 | } 65 | 66 | /** 67 | * De-serialize this object to a {@link ScannerJobProperty}. 68 | * 69 | * @return an instance of {@link ScannerJobProperty} with the same data. 70 | */ 71 | public Object readResolve() { 72 | return new ScannerJobProperty(doNotScan); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /docs/azure.md: -------------------------------------------------------------------------------- 1 | # Azure Cosmos DB 2 | 3 | This is a guide for setting up the MongoDB storage with the Azure cloud provider, 4 | 5 | ## Prerequisites 6 | 7 | * a mongodb client, e.g. the mongo shell from the [mongo installation guide](https://docs.mongodb.com/manual/installation/) 8 | 9 | ## Getting started 10 | 11 | 1. create the Azure Cosmos DB instance, [follow the Microsoft quickstart](https://docs.microsoft.com/en-us/azure/cosmos-db/create-mongodb-java) for this. 12 | * you can skip the 'create a collection' step and just create a database for now, 13 | the plugin will automatically create the collections for you 14 | 15 | 2. go to the 'Connection string' page on your Cosmos DB resource 16 | 17 | 18 | ## Configuring the plugin via UI 19 | 20 | In a separate tab you can now configure the plugin in Jenkins, 21 | 22 | * go to https://.mongo.cosmos.azure.com" 51 | password: "your password" # see docs for handling secrets https://github.com/jenkinsci/configuration-as-code-plugin/blob/master/docs/features/secrets.adoc 52 | port: 10255 53 | successfulLogging: false 54 | tls: true 55 | userName: "" 56 | ``` 57 | 58 | ## Adding required index 59 | 60 | Azure Cosmos DB requires an index when an order by query is performed, in order for this plugin to work you need to run the following commands: 61 | 62 | the example uses the mongo shell, but you can use any mongo client (except the one in the Azure portal which doesn't work for this) 63 | 64 | ```bash 65 | mongo ' # this should be the db name you chose earlier, e.g. bfa 68 | db.failureCauses.createIndex({ "name": 1 }) 69 | ``` 70 | 71 | ## Configure a failure cause 72 | 73 | * go to your jenkins home page 74 | * click 'Failure Cause Management' 75 | * fill out the fields 76 | * click save 77 | 78 | Go to the 'Data explorer' Azure, and click '' and then 'failureCauses'. 79 | 80 | You should now see the failure cause you just created. 81 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/model/FailureCauseModification.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2014 Sony Mobile Communications Inc. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.sonyericsson.jenkins.plugins.bfa.model; 25 | 26 | import com.fasterxml.jackson.annotation.JsonCreator; 27 | import com.fasterxml.jackson.annotation.JsonProperty; 28 | 29 | import java.io.Serializable; 30 | import java.util.Date; 31 | 32 | /** 33 | * A historical record of a modification occurrence by a user. 34 | * 35 | * @author Felix Hall <felix.hall@sonymobile.com> 36 | */ 37 | public class FailureCauseModification implements Serializable { 38 | private String user; 39 | private Date time; 40 | 41 | /** 42 | * Constructor for FailureCauseModification. 43 | * 44 | * @param user The user who made the modification. 45 | * @param time The time at which the modification was done. 46 | */ 47 | @JsonCreator 48 | public FailureCauseModification(@JsonProperty("user") String user, @JsonProperty("time") Date time) { 49 | this.user = user; 50 | if (time == null) { 51 | this.time = null; 52 | } else { 53 | this.time = (Date)time.clone(); 54 | } 55 | } 56 | 57 | /** 58 | * Getter for the time. 59 | * 60 | * @return The time at which the modification was done. 61 | */ 62 | public Date getTime() { 63 | if (time == null) { 64 | return null; 65 | } else { 66 | return (Date)time.clone(); 67 | } 68 | } 69 | 70 | /** 71 | * Getter for the user. 72 | * 73 | * @return The user who made the modification. 74 | */ 75 | public String getUser() { 76 | return user; 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/model/dbf/CoreDBF.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2013 Sony Mobile Communications AB. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.sonyericsson.jenkins.plugins.bfa.model.dbf; 26 | 27 | import hudson.Extension; 28 | import hudson.model.AbstractBuild; 29 | import hudson.model.Fingerprint; 30 | import hudson.model.Job; 31 | import hudson.model.Run; 32 | 33 | import java.util.LinkedList; 34 | import java.util.List; 35 | import java.util.Map; 36 | 37 | /** 38 | * Basic implementation to get downstream builds from Jenkins using core 39 | * functionality. 40 | * 41 | * @author Jan-Olof Sivtoft 42 | */ 43 | @Extension 44 | public class CoreDBF extends DownstreamBuildFinder { 45 | 46 | /** 47 | * Return a list of all downstream builds originating from provided build. 48 | * Using core functionality to retrieve build(s). 49 | * 50 | * @param build get the downstream build(s) relative this build 51 | * @return alist with downstream builds 52 | */ 53 | @Override 54 | public List> getDownstreamBuilds( 55 | final Run build) { 56 | 57 | Map buildMap = null; 58 | if (build instanceof AbstractBuild) { 59 | buildMap = ((AbstractBuild)build).getDownstreamBuilds(); 60 | } 61 | LinkedList> foundBuilds = 62 | new LinkedList>(); 63 | 64 | 65 | if (buildMap != null && !buildMap.isEmpty()) { 66 | for (Map.Entry entry 67 | : buildMap.entrySet()) { 68 | for (Integer buildId : entry.getValue().listNumbers()) { 69 | foundBuilds.add((Run) 70 | entry.getKey().getBuildByNumber(buildId)); 71 | } 72 | } 73 | } 74 | 75 | return foundBuilds; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/MetricsManager.java: -------------------------------------------------------------------------------- 1 | package com.sonyericsson.jenkins.plugins.bfa; 2 | 3 | import com.codahale.metrics.MetricRegistry; 4 | import com.sonyericsson.jenkins.plugins.bfa.model.FailureCause; 5 | import com.sonyericsson.jenkins.plugins.bfa.model.IFailureCauseMetricData; 6 | import jenkins.metrics.api.Metrics; 7 | 8 | import java.util.HashSet; 9 | import java.util.List; 10 | import java.util.Set; 11 | import java.util.SortedSet; 12 | 13 | public final class MetricsManager { 14 | static final String CAUSEPREFIX = "jenkins_bfa.cause."; 15 | static final String CATEGORYPREFIX = "jenkins_bfa.category."; 16 | 17 | /**A magic cause to represent builds that match no causes in the database. */ 18 | public static final FailureCause UNKNOWNCAUSE = new FailureCause("no matching cause", ""); 19 | 20 | private MetricsManager() { 21 | } 22 | 23 | private static Set getMetricNames(IFailureCauseMetricData cause) { 24 | Set metrics = new HashSet(); 25 | metrics.add(CAUSEPREFIX + cause.getName()); 26 | List categoriesForCause = cause.getCategories(); 27 | if (categoriesForCause != null) { 28 | for (String string : categoriesForCause) { 29 | metrics.add(CATEGORYPREFIX + string); 30 | } 31 | } 32 | return metrics; 33 | } 34 | 35 | /** 36 | * Add metrics into the MetricRegistry from the Metrics plugin. 37 | * 38 | * @param cause The Cause to add metrics for 39 | */ 40 | public static void addMetric(IFailureCauseMetricData cause) { 41 | MetricRegistry metricRegistry = Metrics.metricRegistry(); 42 | SortedSet existingMetrics = metricRegistry.getNames(); 43 | Set metrics = getMetricNames(cause); 44 | for (String metric : metrics) { 45 | if (!existingMetrics.contains(metric)) { 46 | metricRegistry.counter(metric); 47 | } 48 | } 49 | } 50 | 51 | /** 52 | * Increment counters for the metric and its categories. 53 | * @param causes The cause to increment counters for 54 | * @param squashCauses Whether or not to squash cause metrics 55 | */ 56 | public static void incCounters(List causes, boolean squashCauses) { 57 | MetricRegistry metricRegistry = Metrics.metricRegistry(); 58 | if (squashCauses) { 59 | Set metrics = new HashSet<>(); 60 | for (IFailureCauseMetricData cause : causes) { 61 | metrics.addAll(getMetricNames(cause)); 62 | } 63 | for (String metric : metrics) { 64 | metricRegistry.counter(metric).inc(); 65 | } 66 | } else { 67 | for (IFailureCauseMetricData cause : causes) { 68 | Set metrics = getMetricNames(cause); 69 | for (String metric : metrics) { 70 | metricRegistry.counter(metric).inc(); 71 | } 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/IndicationAnnotatorFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2012 Sony Mobile Communications AB. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.sonyericsson.jenkins.plugins.bfa; 25 | 26 | import com.sonyericsson.jenkins.plugins.bfa.model.FailureCauseBuildAction; 27 | import com.sonyericsson.jenkins.plugins.bfa.model.FoundFailureCause; 28 | import hudson.Extension; 29 | import hudson.console.ConsoleAnnotator; 30 | import hudson.console.ConsoleAnnotatorFactory; 31 | import hudson.model.Run; 32 | import org.kohsuke.stapler.Ancestor; 33 | import org.kohsuke.stapler.Stapler; 34 | import org.kohsuke.stapler.StaplerRequest2; 35 | 36 | import java.util.List; 37 | 38 | /** 39 | * Factory for creating a new {@link IndicationAnnotator} when the log should be annotated. 40 | * 41 | * @author Tomas Westling <tomas.westling@sonymobile.com> 42 | */ 43 | @Extension 44 | public class IndicationAnnotatorFactory extends ConsoleAnnotatorFactory { 45 | 46 | @Override 47 | public ConsoleAnnotator newInstance(Object context) { 48 | StaplerRequest2 currentRequest = Stapler.getCurrentRequest2(); 49 | if (currentRequest == null) { 50 | //Accessed through some other means than http, so lets assume it is not a human. 51 | return null; 52 | } 53 | Ancestor ancestor = currentRequest.findAncestor(Run.class); 54 | if (ancestor == null) { 55 | return null; 56 | } 57 | Object object = ancestor.getObject(); 58 | Run build = (Run)object; 59 | FailureCauseBuildAction action = build.getAction(FailureCauseBuildAction.class); 60 | if (action == null) { 61 | return null; 62 | } 63 | List foundFailureCauses = action.getFoundFailureCauses(); 64 | if (foundFailureCauses.isEmpty()) { 65 | return null; 66 | } 67 | return new IndicationAnnotator(foundFailureCauses); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/CauseManagement/remove.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2012 Sony Mobile Communications AB. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.sonyericsson.jenkins.plugins.bfa.CauseManagement; 25 | 26 | import com.sonyericsson.jenkins.plugins.bfa.model.FailureCause; 27 | import com.sonyericsson.jenkins.plugins.bfa.CauseManagement; 28 | import com.sonyericsson.jenkins.plugins.bfa.PluginImpl; 29 | import hudson.Functions 30 | 31 | def f = namespace(lib.FormTagLib) 32 | def l = namespace(lib.LayoutTagLib) 33 | def j = namespace(lib.JenkinsTagLib) 34 | def st = namespace("jelly:stapler") 35 | 36 | l.layout(permission: PluginImpl.REMOVE_PERMISSION) { 37 | l.header(title: _("Failure Cause Management - Confirm Remove")) 38 | 39 | def management = CauseManagement.getInstance(); 40 | def causeId = request2.getParameter("id"); 41 | def cause = null; 42 | if (causeId != null && !causeId.isEmpty()) { 43 | cause = PluginImpl.getInstance().getKnowledgeBase().getCause(causeId); 44 | } 45 | 46 | l.side_panel() { 47 | if (!management.isUnderTest()) { 48 | include(management.getOwner(), "sidepanel.jelly") 49 | } 50 | } 51 | 52 | l.main_panel() { 53 | h1(_("Failure Cause - Confirm Remove")) 54 | div(style: "width: 70%") { 55 | st.adjunct(includes: "com.sonyericsson.jenkins.plugins.bfa.CauseManagement.resource") 56 | if (cause != null) { 57 | form(method: "POST", action: "removeConfirm") { 58 | p(_("removeQuestion", cause.getName())) 59 | input(type: "hidden", value: cause.getId(), name: "id") 60 | raw("  "); 61 | f.submit(value: _("Yes")) 62 | raw("  "); 63 | button(type: "button", class: "jenkins-button bfa-cause-management-back-button", _("Back")) 64 | } 65 | } else { 66 | p(_("Not a valid cause id")) 67 | button(class: "jenkins-button bfa-cause-management-back-button", _("Back")) 68 | } 69 | 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/utils/ObjectCountPair.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2013 Sony Mobile Communications AB. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.sonyericsson.jenkins.plugins.bfa.utils; 25 | 26 | import java.util.Comparator; 27 | 28 | /** 29 | * Class for keeping track of the number of copies of the same object. 30 | * Can for example be used for keeping track of how many times 31 | * a specific FailureCause has been triggered. 32 | * 33 | * @author Fredrik Persson <fredrik6.persson@sonyericsson.com> 34 | * 35 | * @param the object type that we count 36 | */ 37 | public class ObjectCountPair { 38 | 39 | private T object; 40 | private int count; 41 | 42 | /** 43 | * Standard constructor. 44 | * @param object the object we are counting 45 | * @param count the number of copies we have of the object 46 | */ 47 | public ObjectCountPair(T object, int count) { 48 | this.object = object; 49 | this.count = count; 50 | } 51 | 52 | /** 53 | * Getter for the object we are counting. 54 | * @return the object we are counting 55 | */ 56 | public T getObject() { 57 | return object; 58 | } 59 | 60 | /** 61 | * Getter for the counter. 62 | * @return the number of copies of the object 63 | */ 64 | public int getCount() { 65 | return count; 66 | } 67 | 68 | /** 69 | * Adds argument number to the counter. 70 | * @param add integer value to add 71 | */ 72 | public void addCount(int add) { 73 | count += add; 74 | } 75 | 76 | /** 77 | * Gets a comparator that compares the count. 78 | * @return comparator 79 | */ 80 | public static Comparator countComparator() { 81 | return new Comparator() { 82 | @Override 83 | public int compare(ObjectCountPair o1, ObjectCountPair o2) { 84 | return o2.getCount() - o1.getCount(); 85 | } 86 | }; 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/tokens/TokenUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2014 Stellar Science Ltd Co 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.sonyericsson.jenkins.plugins.bfa.tokens; 25 | 26 | import com.google.common.base.Splitter; 27 | import org.apache.commons.lang.WordUtils; 28 | 29 | import java.util.ArrayList; 30 | import java.util.List; 31 | import java.util.regex.Matcher; 32 | import java.util.regex.Pattern; 33 | 34 | /** 35 | * Static helper methods for Token generation. 36 | */ 37 | public final class TokenUtils { 38 | 39 | /** Utility class */ 40 | private TokenUtils() { } 41 | 42 | /** 43 | * Wrap some text 44 | * @param text some text to wrap 45 | * @param width the text will be wrapped to this many characters 46 | * @return the text lines 47 | */ 48 | /* package private */ static List wrap(final String text, final int width) { 49 | final List lines = new ArrayList< String>(); 50 | final Splitter lineSplitter = Splitter.on(Pattern.compile("\\r?\\n")); 51 | //Split the text into lines 52 | for (final String line : lineSplitter.split(text)) { 53 | if (width > 0) { 54 | final Pattern firstNonwhitespacePattern = Pattern.compile("[^\\s]"); 55 | final Matcher firstNonwhiteSpaceMatcher = firstNonwhitespacePattern.matcher(line); 56 | String indent = ""; 57 | if (firstNonwhiteSpaceMatcher.find()) { 58 | indent = line.substring(0, firstNonwhiteSpaceMatcher.start()); 59 | } 60 | //Wrap each line 61 | final String wrappedLines = WordUtils.wrap(line, width - indent.length()); 62 | //Split the wrapped line into lines and add those lines to the result 63 | for (final String wrappedLine : lineSplitter.split(wrappedLines)) { 64 | lines.add(indent + wrappedLine.trim()); 65 | } 66 | } else { 67 | lines.add(line); 68 | } 69 | } 70 | return lines; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/test/java/com/sonyericsson/jenkins/plugins/bfa/model/FailureCauseProjectActionHudsonTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2014 Red Hat, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.sonyericsson.jenkins.plugins.bfa.model; 25 | 26 | import hudson.Functions; 27 | import hudson.model.FreeStyleBuild; 28 | import hudson.model.FreeStyleProject; 29 | import hudson.model.Result; 30 | import hudson.tasks.BatchFile; 31 | import hudson.tasks.CommandInterpreter; 32 | import hudson.tasks.Shell; 33 | 34 | import org.junit.jupiter.api.Test; 35 | import org.jvnet.hudson.test.JenkinsRule; 36 | import org.jvnet.hudson.test.junit.jupiter.WithJenkins; 37 | 38 | import static org.junit.jupiter.api.Assertions.assertEquals; 39 | import static org.junit.jupiter.api.Assertions.assertNotNull; 40 | import static org.junit.jupiter.api.Assertions.assertNull; 41 | 42 | /** 43 | * Test Failure Cause project action. 44 | */ 45 | @WithJenkins 46 | class FailureCauseProjectActionHudsonTest { 47 | 48 | /** 49 | * Should show failures of last completed build. 50 | * 51 | * @param j 52 | * 53 | * @throws Exception in some cases. 54 | */ 55 | @Test 56 | void testShowLastFailureOnProjectPage(JenkinsRule j) throws Exception { 57 | FreeStyleProject project = j.createFreeStyleProject(); 58 | CommandInterpreter commandInterpreter; 59 | if (Functions.isWindows()) { 60 | commandInterpreter = new BatchFile("@if %BUILD_NUMBER% == 1 exit /b 1"); 61 | } else { 62 | commandInterpreter = new Shell("test $BUILD_NUMBER -ne 1"); 63 | } 64 | project.getBuildersList().add(commandInterpreter); 65 | FreeStyleBuild build = project.scheduleBuild2(0).get(); 66 | j.assertBuildStatus(Result.FAILURE, build); 67 | 68 | FailureCauseProjectAction action = project.getAction(FailureCauseProjectAction.class); 69 | assertNotNull(action.getAction()); 70 | assertEquals(build.getAction(FailureCauseBuildAction.class), action.getAction()); 71 | 72 | j.buildAndAssertSuccess(project); 73 | assertNull(project.getAction(FailureCauseProjectAction.class).getAction()); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /docs/documentDB.md: -------------------------------------------------------------------------------- 1 | # AWS DocumentDB 2 | 3 | This is a guide for setting up the MongoDB storage with the AWS Document DB, 4 | 5 | ## Prerequisites 6 | 7 | * a mongodb client, e.g. the mongo shell from the [mongo installation guide](https://docs.mongodb.com/manual/installation/) 8 | 9 | ## Getting started 10 | 11 | 1. Create the DocumentDB cluster in AWS, [follow the AWS DocumentDb quickstart](https://docs.aws.amazon.com/documentdb/latest/developerguide/db-cluster-create.html) for this. 12 | * the plugin will automatically create the collections for you so no need to create a collection 13 | 14 | 2. Disable TLS on the cluster by following this step 15 | * Go to DocumentDB services and click on Parameter Groups 16 | * Click on create and create a new Parameter Groups. Provide relevant name and description 17 | * Once created, click on newly created Parameter Groups and select tls. Click on edit button on top 18 | * Choose value as disable and then click on modify cluster parameter. New cluster parameter group is saved with tls disabled 19 | * Click on Clusters and select modify in Action dropdown 20 | * Select your newly created cluster group in Cluster parameter group option and save the cluster. Reboot cluster and associated instance 21 | 22 | 3. Add inbound rule to security group of your cluster to access cluster 23 | * Create a new inbound rule with following values 24 | * Type : Custom TCP 25 | * Protocol : TCP 26 | * Port Range : 27017 27 | * Source : IP range of your network 28 | 29 | 4. Go to Amazon DocumentDB and then go to Clusters. Select the cluster which you have created. Then go to Connectivity & Security tab 30 | 31 | 32 | 33 | ## Configuring the plugin via UI 34 | 35 | In a separate tab you can now configure the plugin in Jenkins, 36 | 37 | * go to https://.us-west-2.docdb.amazonaws.com" 67 | password: "your documentdb masterpasswrd" # see docs for handling secrets https://github.com/jenkinsci/configuration-as-code-plugin/blob/master/docs/features/secrets.adoc 68 | port: 27017 69 | successfulLogging: false 70 | tls: false 71 | userName: "" 72 | ``` 73 | 74 | 75 | ## Configure a failure cause 76 | 77 | * go to your jenkins home page 78 | * click 'Failure Cause Management' 79 | * fill out the fields 80 | * click save 81 | 82 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/FailureCauseMatrixAggregator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2012 Sony Ericsson Mobile Communications. All rights reserved. 5 | * Copyright 2012 Sony Mobile Communications AB. All rights reserved. 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | package com.sonyericsson.jenkins.plugins.bfa; 26 | 27 | import com.sonyericsson.jenkins.plugins.bfa.model.FailureCauseMatrixBuildAction; 28 | import hudson.Launcher; 29 | import hudson.matrix.MatrixAggregator; 30 | import hudson.matrix.MatrixBuild; 31 | import hudson.matrix.MatrixRun; 32 | import hudson.model.BuildListener; 33 | 34 | import java.util.LinkedList; 35 | import java.util.List; 36 | 37 | /** 38 | * Aggregates the failure causes from downstream builds to the parent build. 39 | * 40 | * @author Tomas Westling <thomas.westling@sonyericsson.com> 41 | */ 42 | public class FailureCauseMatrixAggregator extends MatrixAggregator { 43 | 44 | /** 45 | * Standard constructor. 46 | * 47 | * @param build the MatrixBuild to aggregate FailureCauses for. 48 | * @param launcher the launcher. 49 | * @param listener the listener. 50 | */ 51 | public FailureCauseMatrixAggregator(MatrixBuild build, Launcher launcher, BuildListener listener) { 52 | super(build, launcher, listener); 53 | } 54 | 55 | @Override 56 | public boolean endBuild() { 57 | if (PluginImpl.shouldScan(build) && PluginImpl.needToAnalyze(build.getResult())) { 58 | List runsWithCorrectNumber = getRuns(build); 59 | build.addAction(new FailureCauseMatrixBuildAction(build, runsWithCorrectNumber)); 60 | } 61 | return true; 62 | } 63 | 64 | /** 65 | * Gets the runs that has the same number as the build. 66 | * 67 | * @param matrixBuild the build. 68 | * @return the list of runs. 69 | */ 70 | public static List getRuns(MatrixBuild matrixBuild) { 71 | List runs = matrixBuild.getRuns(); 72 | List runsWithCorrectNumber = new LinkedList(); 73 | for (MatrixRun run : runs) { 74 | if (run.getNumber() == matrixBuild.getNumber()) { 75 | runsWithCorrectNumber.add(run); 76 | } 77 | } 78 | return runsWithCorrectNumber; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/test/resources/com/sonyericsson/jenkins/plugins/bfa/model/FailureCauseColumnTest/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1.0 5 | 2 6 | NORMAL 7 | true 8 | 9 | 10 | 11 | ${JENKINS_HOME}/workspace/${ITEM_FULLNAME} 12 | ${ITEM_ROOTDIR}/builds 13 | 14 | 15 | 16 | 17 | 18 | 0 19 | 20 | 21 | 22 | All 23 | false 24 | false 25 | 26 | 27 | 28 | 29 | columnwithouttext 30 | false 31 | false 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | false 43 | 44 | 45 | 46 | 47 | 48 | 49 | .* 50 | 51 | 52 | 53 | columnwithtext 54 | false 55 | false 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | true 67 | 68 | 69 | 70 | 71 | 72 | 73 | .* 74 | 75 | 76 | All 77 | 0 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /src/test/java/com/sonyericsson/jenkins/plugins/bfa/tokens/PipelineTokenTest.java: -------------------------------------------------------------------------------- 1 | package com.sonyericsson.jenkins.plugins.bfa.tokens; 2 | 3 | import hudson.FilePath; 4 | import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; 5 | import org.jenkinsci.plugins.workflow.job.WorkflowJob; 6 | import org.jenkinsci.plugins.workflow.job.WorkflowRun; 7 | import org.junit.jupiter.api.Test; 8 | import org.jvnet.hudson.test.JenkinsRule; 9 | import org.jvnet.hudson.test.junit.jupiter.WithJenkins; 10 | 11 | import static org.junit.jupiter.api.Assertions.assertEquals; 12 | 13 | /** 14 | * Tests that the plugin is compatible with the token macro pipeline step. 15 | */ 16 | @WithJenkins 17 | class PipelineTokenTest { 18 | 19 | private static final String DECLARATIVE_PIPELINE = 20 | """ 21 | pipeline { 22 | agent any 23 | stages { 24 | stage("Run declarative bfa") { 25 | steps { 26 | writeFile file: 'bfa.log', text: tm('''${BUILD_FAILURE_ANALYZER, \ 27 | noFailureText="No errors found - Declarative"}''') 28 | } 29 | } 30 | } 31 | } 32 | """; 33 | 34 | private static final String SCRIPTED_PIPELINE = 35 | """ 36 | node { 37 | stage("Run scripted bfa") { 38 | writeFile file: 'bfa.log', text: tm('''${BUILD_FAILURE_ANALYZER, \ 39 | noFailureText="No errors found - Scripted"}''') 40 | } 41 | } 42 | """; 43 | 44 | /** 45 | * Tests that the plugin is run by the tm pipeline step in a declarative pipeline by writing the result to a file. 46 | * 47 | * @param jenkinsRule 48 | * 49 | * @throws Exception If necessary 50 | */ 51 | @Test 52 | void declarativePipelineTokenMacro(JenkinsRule jenkinsRule) throws Exception { 53 | WorkflowJob project = jenkinsRule.createProject(WorkflowJob.class); 54 | project.setDefinition(new CpsFlowDefinition(DECLARATIVE_PIPELINE, true)); 55 | 56 | final WorkflowRun build = jenkinsRule.buildAndAssertSuccess(project); 57 | final FilePath workspace = jenkinsRule.jenkins.getWorkspaceFor(project); 58 | final FilePath bfaLog = workspace.child("bfa.log"); 59 | 60 | final String bfaLogText = bfaLog.readToString(); 61 | 62 | assertEquals("No errors found - Declarative", bfaLogText); 63 | } 64 | 65 | /** 66 | * Tests that the plugin is run by the tm pipeline step in a scripted pipeline by writing the result to a file. 67 | * 68 | * @param jenkinsRule 69 | * 70 | * @throws Exception If necessary 71 | */ 72 | @Test 73 | void scriptedPipelineTokenMacro(JenkinsRule jenkinsRule) throws Exception { 74 | WorkflowJob project = jenkinsRule.createProject(WorkflowJob.class); 75 | project.setDefinition(new CpsFlowDefinition(SCRIPTED_PIPELINE, true)); 76 | 77 | final WorkflowRun build = jenkinsRule.buildAndAssertSuccess(project); 78 | final FilePath workspace = jenkinsRule.jenkins.getWorkspaceFor(project); 79 | final FilePath bfaLog = workspace.child("bfa.log"); 80 | 81 | final String bfaLogText = bfaLog.readToString(); 82 | 83 | assertEquals("No errors found - Scripted", bfaLogText); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/statistics/FailureCauseStatistics.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2012 Sony Mobile Communications AB. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.sonyericsson.jenkins.plugins.bfa.statistics; 26 | 27 | import com.fasterxml.jackson.annotation.JsonCreator; 28 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 29 | import com.fasterxml.jackson.annotation.JsonProperty; 30 | import com.sonyericsson.jenkins.plugins.bfa.model.FailureCause; 31 | import com.sonyericsson.jenkins.plugins.bfa.model.indication.FoundIndication; 32 | import org.mongojack.DBRef; 33 | 34 | import java.util.List; 35 | 36 | /** 37 | * The FailureCause statistics object. 38 | * Contains the id of a FailureCause and its found indications. 39 | * @author Tomas Westling <tomas.westling@sonymobile.com> 40 | */ 41 | @JsonIgnoreProperties(ignoreUnknown = true) 42 | public class FailureCauseStatistics { 43 | private String id; 44 | private List foundIndications; 45 | 46 | /** 47 | * Getter for the id. 48 | * @return the id. 49 | */ 50 | public String getId() { 51 | return id; 52 | } 53 | 54 | /** 55 | * Getter for the FoundIndications. 56 | * @return the FoundIndications. 57 | */ 58 | public List getIndications() { 59 | return foundIndications; 60 | } 61 | 62 | /** 63 | * Standard constructor. 64 | * @param id the id of the FailureCause. 65 | * @param indications the list of indications. 66 | */ 67 | public FailureCauseStatistics(String id, List indications) { 68 | this.id = id; 69 | this.foundIndications = indications; 70 | } 71 | 72 | /** 73 | * JSON constructor. 74 | * 75 | * @param failureCause database reference to the FailureCause. 76 | * @param indications the list of indications. 77 | * @throws Exception if the database reference is invalid 78 | */ 79 | @JsonCreator 80 | public FailureCauseStatistics( 81 | @JsonProperty("failureCause") DBRef failureCause, 82 | @JsonProperty("indications") List indications) 83 | throws Exception { 84 | if (failureCause == null) { 85 | throw new Exception("Unable to resolve DBRef; failureCause mapping is null"); 86 | } 87 | this.id = failureCause.getId().toString(); 88 | this.foundIndications = indications; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/test/java/com/sonyericsson/jenkins/plugins/bfa/PluginImplTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2012 Sony Ericsson Mobile Communications. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.sonyericsson.jenkins.plugins.bfa; 26 | 27 | import jenkins.model.Jenkins; 28 | import org.junit.jupiter.api.AfterEach; 29 | import org.junit.jupiter.api.BeforeEach; 30 | import org.junit.jupiter.api.Test; 31 | import org.mockito.MockedStatic; 32 | 33 | import static org.junit.jupiter.api.Assertions.assertEquals; 34 | import static org.junit.jupiter.api.Assertions.assertThrows; 35 | import static org.mockito.Mockito.mock; 36 | import static org.mockito.Mockito.mockStatic; 37 | 38 | /** 39 | * JUnit Tests for {@link PluginImpl}. 40 | * 41 | * @author Robert Sandell <robert.sandell@sonyericsson.com> 42 | */ 43 | class PluginImplTest { 44 | 45 | private MockedStatic jenkinsMockedStatic; 46 | 47 | /** 48 | * Initial mocking. 49 | */ 50 | @BeforeEach 51 | void setUp() { 52 | Jenkins jenkins = mock(Jenkins.class); 53 | jenkinsMockedStatic = mockStatic(Jenkins.class); 54 | jenkinsMockedStatic.when(Jenkins::get).thenReturn(jenkins); 55 | jenkinsMockedStatic.when(Jenkins::getInstance).thenReturn(jenkins); 56 | } 57 | 58 | /** 59 | * Release all the static mocks. 60 | */ 61 | @AfterEach 62 | void tearDown() { 63 | jenkinsMockedStatic.close(); 64 | } 65 | 66 | /** 67 | * Tests {@link PluginImpl#getStaticResourcesBase()}. Just a simple one. 68 | *

69 | * TODO Make a similar test in a full Jenkins context. 70 | * 71 | */ 72 | @Test 73 | void testGetStaticResourcesBase() { 74 | assertEquals("/plugin/build-failure-analyzer", PluginImpl.getStaticResourcesBase()); 75 | } 76 | 77 | 78 | /** 79 | * Tests {@link PluginImpl#getStaticImagesBase()}}. Just a simple one. 80 | *

81 | * TODO Make a similar test in a full Jenkins context. 82 | * 83 | */ 84 | @Test 85 | void testGetStaticImagesBase() { 86 | assertEquals("/plugin/build-failure-analyzer/images", PluginImpl.getStaticImagesBase()); 87 | } 88 | 89 | /** 90 | * Tests that you can't set {@link PluginImpl#setNrOfScanThreads(int)} to 0. 91 | */ 92 | @Test 93 | void testSetNrOfScanThreadsZero() { 94 | PluginImpl plugin = new PluginImpl(); 95 | assertThrows(IllegalArgumentException.class, () -> 96 | plugin.setNrOfScanThreads(0)); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/test/java/com/sonyericsson/jenkins/plugins/bfa/FailureCauseWorkFlowTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2016 Sony Mobile Communications Inc. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.sonyericsson.jenkins.plugins.bfa; 25 | 26 | import com.sonyericsson.jenkins.plugins.bfa.model.FailureCauseBuildAction; 27 | import hudson.model.Result; 28 | import hudson.model.queue.QueueTaskFuture; 29 | import org.hamcrest.Matchers; 30 | import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; 31 | import org.jenkinsci.plugins.workflow.job.WorkflowJob; 32 | import org.jenkinsci.plugins.workflow.job.WorkflowRun; 33 | import org.junit.jupiter.api.Test; 34 | import org.jvnet.hudson.test.JenkinsRule; 35 | import org.jvnet.hudson.test.junit.jupiter.WithJenkins; 36 | 37 | import static org.hamcrest.MatcherAssert.assertThat; 38 | import static org.junit.jupiter.api.Assertions.assertNotNull; 39 | import static org.junit.jupiter.api.Assertions.assertNull; 40 | 41 | /** 42 | * Tests for WorkflowJobs. 43 | * @author Tomas Westling <tomas.westling@sonymobile.com> 44 | */ 45 | @WithJenkins 46 | class FailureCauseWorkFlowTest { 47 | 48 | /** 49 | * Tests that an action is added when the builds fail. 50 | * 51 | * @param j 52 | * 53 | * @throws Exception if so. 54 | */ 55 | @Test 56 | void testWorkflowFailureCauseBuildAction(JenkinsRule j) throws Exception { 57 | WorkflowJob proj = j.jenkins.createProject(WorkflowJob.class, "proj"); 58 | proj.setDefinition(new CpsFlowDefinition("error()", false)); 59 | QueueTaskFuture f = proj.scheduleBuild2(0); 60 | assertThat("build was actually scheduled", f, Matchers.notNullValue()); 61 | WorkflowRun run = j.assertBuildStatus(Result.FAILURE, f.get()); 62 | FailureCauseBuildAction action = run.getAction(FailureCauseBuildAction.class); 63 | assertNotNull(action); 64 | } 65 | 66 | /** 67 | * Tests that no action is added if all builds are successful. 68 | * 69 | * @param j 70 | * 71 | * @throws Exception if so. 72 | */ 73 | @Test 74 | void testFailureCausesWhenNotFailed(JenkinsRule j) throws Exception { 75 | WorkflowJob proj = j.jenkins.createProject(WorkflowJob.class, "proj"); 76 | proj.setDefinition(new CpsFlowDefinition("//Do nothing!", false)); 77 | WorkflowRun run = j.assertBuildStatusSuccess(proj.scheduleBuild2(0)); 78 | FailureCauseBuildAction action = run.getAction(FailureCauseBuildAction.class); 79 | assertNull(action); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/AnnotationHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2012 Sony Mobile Communications AB. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.sonyericsson.jenkins.plugins.bfa; 25 | 26 | import hudson.Functions; 27 | import java.io.Serializable; 28 | 29 | /** 30 | * Helper for annotating the lines, creates the strings to annotate with. 31 | * 32 | * @author Tomas Westling<tomas.westling@sonymobile.com> 33 | */ 34 | public class AnnotationHelper implements Serializable { 35 | 36 | private String before = ""; 37 | private String after = ""; 38 | private String title = ""; 39 | 40 | /** 41 | * Gets the String to annotate with before the console text. 42 | * 43 | * @return the String to put before the console text. 44 | */ 45 | public String getBefore() { 46 | if (!title.isEmpty()) { 47 | return before 48 | + ""; 50 | } else { 51 | return before; 52 | } 53 | } 54 | 55 | /** 56 | * Gets the String to annotate with after the console text. 57 | * 58 | * @return the String to put after the console text. 59 | */ 60 | public String getAfter() { 61 | return after; 62 | } 63 | 64 | /** 65 | * Adds a focus id line before the console text. 66 | * 67 | * @param id the id for the line, to refer to in links. 68 | */ 69 | public void addFocus(String id) { 70 | // This style should shift the anchor down below the header so that it's visible. 71 | // " " may be required to make this work for WebKit-based browsers. 72 | this.before += " "; 75 | } 76 | 77 | /** 78 | * Adds a title for the line. 79 | * 80 | * @param addedTitle the title of the line. 81 | */ 82 | public void addTitle(String addedTitle) { 83 | if (this.title.equals("")) { 84 | this.title = addedTitle; 85 | } else { 86 | this.title += "\n" + addedTitle; 87 | } 88 | } 89 | 90 | /** 91 | * Adds a String to annotate with, after the console text. 92 | * 93 | * @param addedAfter the String to put after the console text. 94 | */ 95 | public void addAfter(String addedAfter) { 96 | this.after += addedAfter; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/ScanLogAction.java: -------------------------------------------------------------------------------- 1 | package com.sonyericsson.jenkins.plugins.bfa; 2 | 3 | import edu.umd.cs.findbugs.annotations.NonNull; 4 | import hudson.model.Run; 5 | import java.io.File; 6 | import java.io.IOException; 7 | import java.nio.charset.StandardCharsets; 8 | import jenkins.model.RunAction2; 9 | import org.apache.commons.io.FileUtils; 10 | import org.kohsuke.accmod.Restricted; 11 | import org.kohsuke.accmod.restrictions.NoExternalUse; 12 | import org.kohsuke.stapler.export.Exported; 13 | import org.kohsuke.stapler.export.ExportedBean; 14 | 15 | /** 16 | * The Action for adding a link to the analysis for each run. 17 | */ 18 | @ExportedBean 19 | public class ScanLogAction implements RunAction2 { 20 | 21 | /** 22 | * Log file name. 23 | */ 24 | public static final String FILE_NAME = "com.sonyericsson.jenkins.plugins.bfa.ScanLogAction.log"; 25 | 26 | private transient Run run; 27 | 28 | private long startTime = System.currentTimeMillis(); 29 | 30 | private Long endTime; 31 | 32 | private String exceptionMessage; 33 | 34 | /** 35 | * {@inheritDoc} 36 | */ 37 | @NonNull 38 | @Override 39 | public String getIconFileName() { 40 | return PluginImpl.getDefaultIcon(); 41 | } 42 | 43 | /** 44 | * {@inheritDoc} 45 | */ 46 | @NonNull 47 | @Override 48 | public String getDisplayName() { 49 | return Messages.ScanLogAction_DisplayName(); 50 | } 51 | 52 | /** 53 | * The run associated with this action, called by jelly. 54 | * @return the run 55 | */ 56 | public Run getRun() { 57 | return run; 58 | } 59 | 60 | /** 61 | * {@inheritDoc} 62 | */ 63 | @NonNull 64 | @Override 65 | public String getUrlName() { 66 | return "failure-cause-scan-log"; 67 | } 68 | 69 | /** 70 | * Log text for the analysis. 71 | * @return the log text, lines are separated by \n 72 | * @throws IOException if the log can't be found 73 | */ 74 | public String getLogText() throws IOException { 75 | return FileUtils.readFileToString(new File(run.getRootDir(), FILE_NAME), StandardCharsets.UTF_8); 76 | } 77 | 78 | /** 79 | * The start time of the current scan. 80 | * @return time in milliseconds {@link System#currentTimeMillis} 81 | */ 82 | @Exported 83 | public long getStartTime() { 84 | return startTime; 85 | } 86 | 87 | /** 88 | * The end time of the current scan. 89 | * @return time in milliseconds {@link System#currentTimeMillis} 90 | */ 91 | @Exported 92 | public Long getEndTime() { 93 | return endTime; 94 | } 95 | 96 | /** 97 | * To call when the scan is finished. 98 | */ 99 | @Restricted(NoExternalUse.class) 100 | protected void finished() { 101 | this.endTime = System.currentTimeMillis(); 102 | } 103 | 104 | /** 105 | * Get the exception message if any. 106 | * @return the first exception faced during scan 107 | */ 108 | public String getExceptionMessage() { 109 | return exceptionMessage; 110 | } 111 | 112 | /** 113 | * Set an exception. 114 | * @param exceptionMessage the exception message to set 115 | */ 116 | public void setExceptionMessage(String exceptionMessage) { 117 | this.exceptionMessage = exceptionMessage; 118 | } 119 | 120 | /** 121 | * {@inheritDoc} 122 | */ 123 | @Override 124 | public void onAttached(Run r) { 125 | this.run = r; 126 | } 127 | 128 | /** 129 | * {@inheritDoc} 130 | */ 131 | @Override 132 | public void onLoad(Run r) { 133 | this.run = r; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/IndicationAnnotator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2012 Sony Mobile Communications AB. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.sonyericsson.jenkins.plugins.bfa; 25 | 26 | import com.sonyericsson.jenkins.plugins.bfa.model.FoundFailureCause; 27 | import com.sonyericsson.jenkins.plugins.bfa.model.indication.FoundIndication; 28 | import hudson.MarkupText; 29 | import hudson.console.ConsoleAnnotator; 30 | 31 | import java.util.HashMap; 32 | import java.util.List; 33 | import java.util.Map; 34 | 35 | /** 36 | * Annotates the build log so that we can create links to it and mark found indications. 37 | * 38 | * @author Tomas Westling <tomas.westling@sonymobile.com> 39 | */ 40 | public class IndicationAnnotator extends ConsoleAnnotator { 41 | 42 | private Map helperMap; 43 | 44 | 45 | /** 46 | * Standard constructor. 47 | * 48 | * @param foundFailureCauses the {@link FoundFailureCause}s to add annotation for. 49 | */ 50 | public IndicationAnnotator(List foundFailureCauses) { 51 | helperMap = new HashMap(); 52 | for (FoundFailureCause foundFailureCause : foundFailureCauses) { 53 | addToHelperMap(foundFailureCause); 54 | } 55 | } 56 | 57 | /** 58 | * Adds the matching and focus lines to the helper map, to ease annotating later. 59 | * 60 | * @param cause the {@link FoundFailureCause}} to add lines for. 61 | */ 62 | private void addToHelperMap(FoundFailureCause cause) { 63 | for (FoundIndication indication : cause.getIndications()) { 64 | String matchingString = indication.getFirstMatchingLine(); 65 | if (matchingString != null && !matchingString.isEmpty()) { 66 | AnnotationHelper matchingHelper = helperMap.get(matchingString); 67 | if (matchingHelper == null) { 68 | matchingHelper = new AnnotationHelper(); 69 | } 70 | matchingHelper.addTitle(cause.getName()); 71 | matchingHelper.addFocus(indication.getMatchingHash() + cause.getId()); 72 | matchingHelper.addAfter(""); 73 | helperMap.put(matchingString, matchingHelper); 74 | } 75 | } 76 | } 77 | 78 | @Override 79 | public ConsoleAnnotator annotate(Object context, MarkupText text) { 80 | AnnotationHelper match = helperMap.get(text.getText().replace("\n", "").replace("\r", "")); 81 | if (match != null) { 82 | text.wrapBy(match.getBefore(), match.getAfter()); 83 | } 84 | return this; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/model/indication/MultilineBuildLogIndication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2012 Sony Mobile Communications AB. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.sonyericsson.jenkins.plugins.bfa.model.indication; 25 | 26 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 27 | import com.fasterxml.jackson.annotation.JsonProperty; 28 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 29 | import com.sonyericsson.jenkins.plugins.bfa.Messages; 30 | import com.sonyericsson.jenkins.plugins.bfa.model.FailureReader; 31 | import com.sonyericsson.jenkins.plugins.bfa.model.MultilineBuildLogFailureReader; 32 | import hudson.Extension; 33 | import hudson.model.Hudson; 34 | import org.kohsuke.stapler.DataBoundConstructor; 35 | 36 | import java.util.regex.Pattern; 37 | 38 | /** 39 | * Build log indication that matches over multiple lines. 40 | * 41 | * @author Andrew Bayer 42 | */ 43 | @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "@class", visible = true) 44 | @JsonIgnoreProperties(ignoreUnknown = true) 45 | public class MultilineBuildLogIndication extends BuildLogIndication { 46 | 47 | private static final long serialVersionUID = 8436383594898812087L; 48 | private transient Pattern compiled = null; 49 | 50 | /** 51 | * Standard constructor. 52 | * 53 | * @param pattern the string value to search for. 54 | */ 55 | @DataBoundConstructor 56 | public MultilineBuildLogIndication(@JsonProperty("pattern") String pattern) { 57 | super(pattern); 58 | } 59 | 60 | @Override 61 | public FailureReader getReader() { 62 | return new MultilineBuildLogFailureReader(this); 63 | } 64 | 65 | @Override 66 | public Pattern getPattern() { 67 | if (compiled == null) { 68 | compiled = Pattern.compile("(?m)(?s)^[^\\r\\n]*?" + getUserProvidedExpression() + "[^\\r\\n]*?$", 69 | Pattern.MULTILINE | Pattern.DOTALL); 70 | } 71 | return compiled; 72 | } 73 | 74 | @Override 75 | public IndicationDescriptor getDescriptor() { 76 | return Hudson.getInstance().getDescriptorByType(MultilineBuildLogIndicationDescriptor.class); 77 | } 78 | 79 | /** 80 | * The descriptor. 81 | */ 82 | @Extension 83 | public static class MultilineBuildLogIndicationDescriptor extends BuildLogIndicationDescriptor { 84 | @Override 85 | public String getDisplayName() { 86 | return Messages.MultilineBuildLogIndication_DisplayName(); 87 | } 88 | 89 | @Override 90 | protected FailureReader getFailureReader(final String testPattern) { 91 | return new MultilineBuildLogFailureReader(new MultilineBuildLogIndication(testPattern)); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/test/java/com/sonyericsson/jenkins/plugins/bfa/MetricsManagerTest.java: -------------------------------------------------------------------------------- 1 | package com.sonyericsson.jenkins.plugins.bfa; 2 | 3 | import com.codahale.metrics.Counter; 4 | import com.codahale.metrics.MetricRegistry; 5 | 6 | import com.sonyericsson.jenkins.plugins.bfa.model.FailureCause; 7 | import com.sonyericsson.jenkins.plugins.bfa.model.IFailureCauseMetricData; 8 | import com.sonyericsson.jenkins.plugins.bfa.model.indication.BuildLogIndication; 9 | import com.sonyericsson.jenkins.plugins.bfa.model.indication.Indication; 10 | import jenkins.metrics.api.Metrics; 11 | import org.junit.jupiter.api.AfterEach; 12 | import org.junit.jupiter.api.BeforeEach; 13 | import org.junit.jupiter.api.Test; 14 | import org.mockito.MockedStatic; 15 | 16 | import java.util.ArrayList; 17 | import java.util.Arrays; 18 | import java.util.Date; 19 | import java.util.LinkedList; 20 | import java.util.List; 21 | 22 | import static com.sonyericsson.jenkins.plugins.bfa.MetricsManager.addMetric; 23 | import static com.sonyericsson.jenkins.plugins.bfa.MetricsManager.incCounters; 24 | import static org.mockito.ArgumentMatchers.anyString; 25 | import static org.mockito.Mockito.mock; 26 | import static org.mockito.Mockito.mockStatic; 27 | import static org.mockito.Mockito.times; 28 | import static org.mockito.Mockito.verify; 29 | import static org.mockito.Mockito.when; 30 | 31 | 32 | /** 33 | * Tests for {@link MetricsManager}. 34 | */ 35 | class MetricsManagerTest { 36 | private MetricRegistry metricRegistry; 37 | private Counter counter; 38 | 39 | private FailureCause mockedCause; 40 | private List mockedCauseList; 41 | private MockedStatic metricsMockedStatic; 42 | 43 | /** 44 | * Common stuff to set up for the tests. 45 | */ 46 | @BeforeEach 47 | void setUp() { 48 | metricRegistry = mock(MetricRegistry.class); 49 | counter = mock(Counter.class); 50 | List indications = new LinkedList<>(); 51 | Indication indication = new BuildLogIndication("something"); 52 | indications.add(indication); 53 | mockedCause = new FailureCause("id", "myFailureCause", "description", "comment", new Date(), 54 | "category", indications, null); 55 | mockedCauseList = new ArrayList<>(Arrays.asList(mockedCause, mockedCause)); 56 | 57 | metricsMockedStatic = mockStatic(Metrics.class); 58 | metricsMockedStatic.when(Metrics::metricRegistry).thenReturn(metricRegistry); 59 | 60 | when(metricRegistry.counter(anyString())).thenReturn(counter); 61 | } 62 | 63 | /** 64 | * Release all the static mocks. 65 | */ 66 | @AfterEach 67 | void tearDown() { 68 | metricsMockedStatic.close(); 69 | } 70 | 71 | /** 72 | * Test that the case and category counters are created from a FailureCause. 73 | */ 74 | @Test 75 | void testAddMetric() { 76 | addMetric(mockedCause); 77 | 78 | verify(metricRegistry, times(1)).counter("jenkins_bfa.cause.myFailureCause"); 79 | verify(metricRegistry, times(1)).counter("jenkins_bfa.category.category"); 80 | } 81 | 82 | /** 83 | * Test that the cause and category counters are incremented twice for a FailureCause when not using squashing. 84 | */ 85 | @Test 86 | void testIncCountersWithSquashingDisabled() { 87 | incCounters(mockedCauseList, false); 88 | 89 | verify(counter, times(mockedCauseList.size() * 2)).inc(); 90 | } 91 | 92 | /** 93 | * Test that the cause and category counters are incremented once for a FailureCause when using squashing. 94 | */ 95 | @Test 96 | void testIncCountersWithSquashingEnabled() { 97 | incCounters(mockedCauseList, true); 98 | 99 | verify(counter, times(mockedCauseList.size())).inc(); 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/providers/FailureCauseProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2017 Axis Communications AB. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.sonyericsson.jenkins.plugins.bfa.providers; 25 | 26 | import com.sonyericsson.jenkins.plugins.bfa.model.FailureCauseBuildAction; 27 | import com.sonyericsson.jenkins.plugins.bfa.model.FoundFailureCause; 28 | import com.sonyericsson.jenkins.plugins.bfa.model.indication.FoundIndication; 29 | import hudson.Extension; 30 | import hudson.model.Run; 31 | import net.sf.json.JSONArray; 32 | import net.sf.json.JSONObject; 33 | import com.sonymobile.jenkins.plugins.mq.mqnotifier.providers.MQDataProvider; 34 | 35 | import java.util.List; 36 | 37 | /** 38 | * Provides information about the failure causes for a build. 39 | * 40 | * @author Tomas Westling <tomas.westling@axis.com> 41 | */ 42 | @Extension(optional = true) 43 | public class FailureCauseProvider extends MQDataProvider { 44 | 45 | @Override 46 | public void provideCompletedRunData(Run run, JSONObject json) { 47 | FailureCauseBuildAction action = run.getAction(FailureCauseBuildAction.class); 48 | if (action != null) { 49 | List foundFailureCausesList = action.getFoundFailureCauses(); 50 | JSONArray failureCausesJSONArray = new JSONArray(); 51 | for (FoundFailureCause foundFailureCause : foundFailureCausesList) { 52 | JSONObject failureCauseJSONObject = new JSONObject(); 53 | failureCauseJSONObject.put("id", foundFailureCause.getId()); 54 | failureCauseJSONObject.put("name", foundFailureCause.getName()); 55 | failureCauseJSONObject.put("description", foundFailureCause.getDescription()); 56 | failureCauseJSONObject.put("categories", foundFailureCause.getCategories()); 57 | JSONArray foundIndicationsJSONArray = new JSONArray(); 58 | for (FoundIndication indication : foundFailureCause.getIndications()) { 59 | JSONObject foundIndicationJSONObject = new JSONObject(); 60 | foundIndicationJSONObject.put("pattern", indication.getPattern()); 61 | foundIndicationJSONObject.put("matchingString", indication.getMatchingString()); 62 | foundIndicationJSONObject.put("matchingLine", indication.getMatchingLine()); 63 | foundIndicationsJSONArray.add(foundIndicationJSONObject); 64 | } 65 | failureCauseJSONObject.put("indications", foundIndicationsJSONArray); 66 | failureCausesJSONArray.add(failureCauseJSONObject); 67 | } 68 | json.put("failurecauses", failureCausesJSONArray); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/model/dbf/DownstreamBuildFinder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2013 Sony Mobile Communications AB. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.sonyericsson.jenkins.plugins.bfa.model.dbf; 26 | 27 | import hudson.ExtensionList; 28 | import hudson.ExtensionPoint; 29 | import hudson.Util; 30 | import hudson.model.AbstractBuild; 31 | import hudson.model.Hudson; 32 | import hudson.model.Run; 33 | 34 | import java.util.Collections; 35 | import java.util.LinkedList; 36 | import java.util.List; 37 | 38 | /** 39 | * There is no general way to find downstream build in Jenkins Core. Different 40 | * plugin have there own way of keeping this information. 41 | * Extend this class and implement 42 | * {@link #getDownstreamBuilds(hudson.model.Run)} 43 | * in a way suitable for the plugin 44 | * 45 | * @author Jan-Olof Sivtoft 46 | */ 47 | public abstract class DownstreamBuildFinder implements ExtensionPoint { 48 | 49 | /** 50 | * No need to create a new empty list each time there is nothing to return. 51 | * Make it unmodifiable to make sure it isn't used. 52 | */ 53 | protected static final List> EMPTY = 54 | Collections.unmodifiableList(new LinkedList>()); 55 | 56 | /** 57 | * Return a list of all downstream builds originating from provided build. 58 | * 59 | * @param build get the downstream build(s) relative this build 60 | * @return a list with downstream builds 61 | * @deprecated use {@link #getDownstreamBuilds(hudson.model.Run)} 62 | */ 63 | @Deprecated 64 | public List> getDownstreamBuilds(final AbstractBuild build) { 65 | if (Util.isOverridden(DownstreamBuildFinder.class, getClass(), "getDownstreamBuilds", Run.class)) { 66 | return getDownstreamBuilds((Run)build); 67 | } 68 | return null; 69 | } 70 | 71 | /** 72 | * Return a list of all downstream builds originating from provided build. 73 | * 74 | * @param build get the downstream build(s) relative this build 75 | * @return a list with downstream builds 76 | */ 77 | public List> getDownstreamBuilds(final Run build) { 78 | if (Util.isOverridden(DownstreamBuildFinder.class, getClass(), "getDownstreamBuilds", AbstractBuild.class)) { 79 | return getDownstreamBuilds((AbstractBuild)build); 80 | } 81 | return null; 82 | } 83 | 84 | /** 85 | * Return a list of all registered DownstreamBuildFinder of this type. 86 | * 87 | * @return a list of DownstreamBuildFinder 88 | */ 89 | public static ExtensionList getAll() { 90 | return Hudson.getInstance(). 91 | getExtensionList(DownstreamBuildFinder.class); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/sod/ScanOnDemandBaseAction/ScanMode/index.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2012 Sony Mobile Communications AB. All rights reserved. 5 | * Copyright (c) 2016, CloudBees, Inc. 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | import com.sonyericsson.jenkins.plugins.bfa.sod.ScanOnDemandBaseAction 27 | 28 | def l = namespace(lib.LayoutTagLib) 29 | def st = namespace("jelly:stapler") 30 | def f = namespace(lib.FormTagLib) 31 | 32 | ScanOnDemandBaseAction.ScanMode mode = my; 33 | mode.setAsDefault() 34 | 35 | l.layout(title: _("Failure Scan Options"), norefresh: true) { 36 | l.header { 37 | mode.parent.checkPermission() 38 | style(type: "text/css", """ 39 | tr.disablehover:hover { 40 | background-color: white; 41 | } 42 | """) 43 | 44 | } 45 | st.include(it: mode.parent.project, page: "sidepanel.jelly") 46 | l.'main-panel' { 47 | st.adjunct(includes: "com.sonyericsson.jenkins.plugins.bfa.sod.ScanOnDemandBaseAction.ScanMode.resource") 48 | f.form { 49 | f.section(title: _("Select the option and scan the builds")) { 50 | ScanOnDemandBaseAction.ScanMode.all().each { ScanOnDemandBaseAction.ScanMode option -> 51 | f.entry(field: option.urlName, class: "bfa-scan-mode-build-type-radio-entry", 52 | help: "/plugin/build-failure-analyzer/help/sod/${option.urlName}.html") { 53 | span(class: "bfa-entry-data-holder", "data-root-url": "${rootURL}", "data-option-full-url": "${option.getFullUrl()}") 54 | f.radio(name: "buildType", 55 | value: option.urlName, 56 | checked: option == mode, 57 | title: option.displayName) 58 | } 59 | } 60 | } 61 | } 62 | if (!mode.hasAnyRun(mode.parent.project)) { 63 | f.section(title: _("No build found")) { 64 | f.block { 65 | table(width: "100%", border: "0", cellpadding: "2", cellspacing: "0", 66 | class: "pane bigtable", style: "margin-top: 0") { 67 | tr { 68 | td() 69 | td { 70 | strong(_("No build found to scan")) 71 | } 72 | } 73 | } 74 | } 75 | } 76 | } else { 77 | f.form(method: "POST", action: "performScan") { 78 | f.section { 79 | f.block { 80 | f.submit(value: _("Scan")) 81 | } 82 | } 83 | } 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/model/ScannerJobProperty.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2012 Sony Mobile Communications AB. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.sonyericsson.jenkins.plugins.bfa.model; 26 | 27 | import com.sonyericsson.jenkins.plugins.bfa.FailureCauseMatrixAggregator; 28 | import com.sonyericsson.jenkins.plugins.bfa.Messages; 29 | import hudson.Extension; 30 | import hudson.Launcher; 31 | import hudson.matrix.MatrixAggregatable; 32 | import hudson.matrix.MatrixAggregator; 33 | import hudson.matrix.MatrixBuild; 34 | import hudson.model.Action; 35 | import hudson.model.BuildListener; 36 | import hudson.model.Job; 37 | import hudson.model.JobProperty; 38 | import hudson.model.JobPropertyDescriptor; 39 | import org.kohsuke.stapler.DataBoundConstructor; 40 | 41 | import java.io.Serializable; 42 | 43 | import org.kohsuke.accmod.Restricted; 44 | import org.kohsuke.accmod.restrictions.NoExternalUse; 45 | 46 | /** 47 | * A JobProperty that flags a job that should not be scanned. Also works as the {@link MatrixAggregatable} 48 | * 49 | * @author Robert Sandell <robert.sandell@sonymobile.com> 50 | */ 51 | public class ScannerJobProperty extends JobProperty> implements MatrixAggregatable, Serializable { 52 | 53 | private boolean doNotScan; 54 | 55 | /** 56 | * Standard DataBound Constructor. 57 | * 58 | * @param doNotScan signal that builds of this job should not be scanned. 59 | */ 60 | @DataBoundConstructor 61 | public ScannerJobProperty(boolean doNotScan) { 62 | this.doNotScan = doNotScan; 63 | } 64 | 65 | /** 66 | * Default Constructor. Do not use unless you are a serializer! 67 | */ 68 | public ScannerJobProperty() { 69 | } 70 | 71 | /** 72 | * The value. True turns the scanner off. 73 | * 74 | * @return if no scan should be done. 75 | */ 76 | public boolean isDoNotScan() { 77 | return doNotScan; 78 | } 79 | 80 | @Override 81 | @Restricted(NoExternalUse.class) 82 | public Action getJobAction(Job job) { 83 | return new FailureCauseProjectAction(job); 84 | } 85 | 86 | @Override 87 | public MatrixAggregator createAggregator(MatrixBuild build, Launcher launcher, BuildListener listener) { 88 | return new FailureCauseMatrixAggregator(build, launcher, listener); 89 | } 90 | 91 | /** 92 | * Descriptor for {@link ScannerJobProperty}. 93 | */ 94 | @Extension 95 | public static class ScannerJobPropertyDescriptor extends JobPropertyDescriptor { 96 | 97 | @Override 98 | public String getDisplayName() { 99 | return Messages.ScannerJobProperty_DisplayName(); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/model/BuildLogFailureReader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2012 Sony Mobile Communications AB. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.sonyericsson.jenkins.plugins.bfa.model; 26 | 27 | import com.sonyericsson.jenkins.plugins.bfa.model.indication.BuildLogIndication; 28 | import com.sonyericsson.jenkins.plugins.bfa.model.indication.FoundIndication; 29 | import hudson.model.Run; 30 | 31 | import java.io.BufferedReader; 32 | import java.io.IOException; 33 | import java.util.ArrayList; 34 | import java.util.List; 35 | import java.util.logging.Level; 36 | import java.util.logging.Logger; 37 | 38 | 39 | /** 40 | * Reader used to find indications of a failure cause. 41 | * 42 | * @author Tomas Westling <tomas.westling@sonymobile.com> 43 | */ 44 | public class BuildLogFailureReader extends FailureReader { 45 | 46 | private static final Logger logger = Logger.getLogger(BuildLogFailureReader.class.getName()); 47 | 48 | /** 49 | * Standard constructor. 50 | * @param indication the indication to look for. 51 | */ 52 | public BuildLogFailureReader(BuildLogIndication indication) { 53 | super(indication); 54 | } 55 | 56 | /** 57 | * Scans a build log. 58 | * 59 | * @param build - the build whose log should be scanned. 60 | * @return a FoundIndication if the pattern given by this BuildLogFailureReader 61 | * is found in the log of the given build; return null otherwise. 62 | * @throws IOException if so. 63 | */ 64 | @Override 65 | public FoundIndication scan(Run build) throws IOException { 66 | BufferedReader reader = null; 67 | try { 68 | reader = new BufferedReader(build.getLogReader()); 69 | List causes = new ArrayList(1); 70 | FailureCause fc = new FailureCause("somename", "somedescription"); 71 | causes.add(fc); 72 | fc.addIndication(indication); 73 | List foundFailureCauses = FailureReader.scanSingleLinePatterns(causes, 74 | build, 75 | reader, 76 | "log"); 77 | if (foundFailureCauses.isEmpty()) { 78 | return null; 79 | } else { 80 | return foundFailureCauses.get(0).getIndications().get(0); 81 | } 82 | } finally { 83 | if (reader != null) { 84 | try { 85 | reader.close(); 86 | } catch (IOException e) { 87 | logger.log(Level.WARNING, "Failed to close the reader. ", e); 88 | } 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/test/java/com/sonyericsson/jenkins/plugins/bfa/jcasc/ConfigurationAsCodeLocalTest.java: -------------------------------------------------------------------------------- 1 | package com.sonyericsson.jenkins.plugins.bfa.jcasc; 2 | 3 | import com.sonyericsson.jenkins.plugins.bfa.PluginImpl; 4 | import com.sonyericsson.jenkins.plugins.bfa.db.LocalFileKnowledgeBase; 5 | import com.sonyericsson.jenkins.plugins.bfa.sod.ScanOnDemandVariables; 6 | import io.jenkins.plugins.casc.ConfigurationContext; 7 | import io.jenkins.plugins.casc.ConfiguratorRegistry; 8 | import io.jenkins.plugins.casc.misc.ConfiguredWithCode; 9 | import io.jenkins.plugins.casc.misc.JenkinsConfiguredWithCodeRule; 10 | import io.jenkins.plugins.casc.misc.junit.jupiter.WithJenkinsConfiguredWithCode; 11 | import io.jenkins.plugins.casc.model.CNode; 12 | import org.junit.jupiter.api.Test; 13 | 14 | import static io.jenkins.plugins.casc.misc.Util.getUnclassifiedRoot; 15 | import static io.jenkins.plugins.casc.misc.Util.toStringFromYamlFile; 16 | import static io.jenkins.plugins.casc.misc.Util.toYamlString; 17 | import static org.hamcrest.MatcherAssert.assertThat; 18 | import static org.hamcrest.core.Is.is; 19 | import static org.hamcrest.core.IsInstanceOf.instanceOf; 20 | 21 | /** 22 | * Checks configuration as code integration for local DB. 23 | */ 24 | @WithJenkinsConfiguredWithCode 25 | class ConfigurationAsCodeLocalTest { 26 | 27 | static final String NO_CAUSES_MESSAGE = "No problems were identified. Please contribute causes to help others"; 28 | static final int EXPECTED_SCAN_THREADS = 6; 29 | static final int EXPECTED_MAXIMUM_SOD_WORKER_THREADS = 7; 30 | static final int EXPECTED_MINIMUM_SOD_WORKER_THREADS = 2; 31 | static final int EXPECTED_SOD_CORE_POOL_NUMBER_OF_THREADS = 6; 32 | static final int EXPECTED_SOD_THREAD_KEEP_ALIVE_TIME = 17; 33 | static final int EXPECTED_SOD_JOB_SHUTDOWN_TIMEOUT = 32; 34 | 35 | /** 36 | * Support config as code import. 37 | * 38 | * @param j 39 | * 40 | */ 41 | @Test 42 | @ConfiguredWithCode("jcasc-local.yml") 43 | void shouldSupportConfigurationAsCode(JenkinsConfiguredWithCodeRule j) { 44 | PluginImpl plugin = PluginImpl.getInstance(); 45 | 46 | assertThat(plugin.isDoNotAnalyzeAbortedJob(), is(true)); 47 | assertThat(plugin.isGerritTriggerEnabled(), is(true)); 48 | assertThat(plugin.isGlobalEnabled(), is(true)); 49 | assertThat(plugin.isGraphsEnabled(), is(false)); 50 | assertThat(plugin.getKnowledgeBase(), instanceOf(LocalFileKnowledgeBase.class)); 51 | assertThat(plugin.getNoCausesMessage(), is(NO_CAUSES_MESSAGE)); 52 | 53 | assertThat(plugin.getNrOfScanThreads(), is(EXPECTED_SCAN_THREADS)); 54 | 55 | ScanOnDemandVariables sodVariables = plugin.getSodVariables(); 56 | 57 | assertThat(sodVariables.getMaximumSodWorkerThreads(), is(EXPECTED_MAXIMUM_SOD_WORKER_THREADS)); 58 | assertThat(sodVariables.getMinimumSodWorkerThreads(), is(EXPECTED_MINIMUM_SOD_WORKER_THREADS)); 59 | assertThat(sodVariables.getSodCorePoolNumberOfThreads(), is(EXPECTED_SOD_CORE_POOL_NUMBER_OF_THREADS)); 60 | assertThat(sodVariables.getSodThreadKeepAliveTime(), is(EXPECTED_SOD_THREAD_KEEP_ALIVE_TIME)); 61 | assertThat(sodVariables.getSodWaitForJobShutdownTimeout(), is(EXPECTED_SOD_JOB_SHUTDOWN_TIMEOUT)); 62 | 63 | assertThat(plugin.getTestResultCategories(), is("hgjghhlllllaa")); 64 | assertThat(plugin.isTestResultParsingEnabled(), is(true)); 65 | 66 | assertThat(plugin.isMetricSquashingEnabled(), is(false)); 67 | } 68 | 69 | /** 70 | * Support config as code export. 71 | * 72 | * @param j 73 | * 74 | * @throws Exception if so. 75 | */ 76 | @Test 77 | @ConfiguredWithCode("jcasc-local.yml") 78 | void shouldSupportConfigurationExport(JenkinsConfiguredWithCodeRule j) throws Exception { 79 | ConfiguratorRegistry registry = ConfiguratorRegistry.get(); 80 | ConfigurationContext context = new ConfigurationContext(registry); 81 | CNode yourAttribute = getUnclassifiedRoot(context).get("buildFailureAnalyzer"); 82 | 83 | String exported = toYamlString(yourAttribute); 84 | 85 | String expected = toStringFromYamlFile(this, "jcasc-local-expected.yml"); 86 | 87 | assertThat(exported, is(expected)); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/test/java/com/sonyericsson/jenkins/plugins/bfa/model/FailureCauseColumnTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2014 Vincent Latombe 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.sonyericsson.jenkins.plugins.bfa.model; 25 | 26 | import static org.junit.jupiter.api.Assertions.assertNotNull; 27 | import static org.junit.jupiter.api.Assertions.assertNull; 28 | 29 | import hudson.model.FreeStyleBuild; 30 | import hudson.model.Result; 31 | import hudson.model.FreeStyleProject; 32 | 33 | import org.junit.jupiter.api.Test; 34 | import org.jvnet.hudson.test.JenkinsRule; 35 | import org.jvnet.hudson.test.JenkinsRule.WebClient; 36 | import org.jvnet.hudson.test.FailureBuilder; 37 | import org.jvnet.hudson.test.junit.jupiter.WithJenkins; 38 | import org.jvnet.hudson.test.recipes.LocalData; 39 | 40 | import org.htmlunit.html.HtmlPage; 41 | 42 | /** 43 | * Tests for {@link FailureCauseColumn}. 44 | * 45 | * @author Vincent Latombe <vincent@latombe.net> 46 | */ 47 | @WithJenkins 48 | class FailureCauseColumnTest { 49 | 50 | /** 51 | * Happy test case with a view containing a {@link FailureCauseColumn}, text option being disabled. 52 | * 53 | * @param j 54 | * 55 | * @throws Exception 56 | * if so 57 | */ 58 | @LocalData 59 | @Test 60 | void givenAViewWithTheFailureCauseColumnDisplayTheFirstFailureCauseAsTitle(JenkinsRule j) throws Exception { 61 | FreeStyleProject fs = j.createFreeStyleProject("total_failure"); 62 | fs.getBuildersList().add(new FailureBuilder()); 63 | fs.save(); 64 | 65 | FreeStyleBuild r = fs.scheduleBuild2(0).get(); 66 | j.assertBuildStatus(Result.FAILURE, r); 67 | 68 | WebClient webClient = j.createWebClient(); 69 | HtmlPage page = webClient.goTo("view/columnwithouttext"); 70 | assertNotNull(page.getFirstByXPath("//*[local-name()='svg'][@tooltip='Failure Builder']"), 71 | "Couldn't find the failure cause svg in columnwithouttext view"); 72 | assertNull(page.getDocumentElement().getFirstByXPath("//*[.='Failure Builder']")); 73 | } 74 | 75 | /** 76 | * Happy test case with a view containing a {@link FailureCauseColumn}, text option being enabled. 77 | * 78 | * @param j 79 | * 80 | * @throws Exception 81 | * if so 82 | */ 83 | @LocalData 84 | @Test 85 | void givenAViewWithTheFailureCauseColumnWithTextDisplayTheFirstFailureCauseAsTitleAndText(JenkinsRule j) 86 | throws Exception { 87 | FreeStyleProject fs = j.createFreeStyleProject("total_failure"); 88 | fs.getBuildersList().add(new FailureBuilder()); 89 | fs.save(); 90 | 91 | FreeStyleBuild r = fs.scheduleBuild2(0).get(); 92 | j.assertBuildStatus(Result.FAILURE, r); 93 | 94 | WebClient webClient = j.createWebClient(); 95 | HtmlPage page = webClient.goTo("view/columnwithtext"); 96 | System.out.println(page.getTextContent()); 97 | assertNotNull(page.getFirstByXPath("//*[local-name()='svg'][@tooltip='Failure Builder']"), 98 | "Couldn't find the failure cause svg in columnwithtext view"); 99 | assertNotNull(page.getFirstByXPath("//*[contains(text(), 'Failure Builder')]")); 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/model/dbf/ParameterizedTriggerDBF.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2013 Sony Mobile Communications AB. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.sonyericsson.jenkins.plugins.bfa.model.dbf; 26 | 27 | import hudson.Extension; 28 | import hudson.model.Action; 29 | import hudson.model.Run; 30 | 31 | import java.lang.reflect.InvocationTargetException; 32 | import java.lang.reflect.Method; 33 | import java.util.List; 34 | import java.util.logging.Level; 35 | import java.util.logging.Logger; 36 | 37 | /** 38 | * Get downstream builds for the Parameterized Trigger Plugin. 39 | * We want to avoid having dependencies to other plugins thus using reflection. 40 | * 41 | * @author Jan-Olof Sivtoft 42 | */ 43 | @Extension 44 | public class ParameterizedTriggerDBF extends DownstreamBuildFinder { 45 | 46 | private static final Logger logger = Logger. 47 | getLogger(ParameterizedTriggerDBF.class.getName()); 48 | 49 | /** 50 | * Return a list of all downstream builds originating from provided build. 51 | * Getting build originating from the usage of the parameterized trigger 52 | * plugin. 53 | * 54 | * @param build get the downstream build(s) relative this build 55 | * @return a list with downstream builds 56 | */ 57 | @Override 58 | public List> getDownstreamBuilds( 59 | final Run build) { 60 | 61 | if (build == null) { 62 | return EMPTY; 63 | } 64 | 65 | // The action class to examine for downstream builds 66 | String className = 67 | "hudson.plugins.parameterizedtrigger.BuildInfoExporterAction"; 68 | // The method returning triggered builds 69 | String methodName = "getTriggeredBuilds"; 70 | 71 | try { 72 | // The BuildInfoExporterAction class 73 | Class clazz = Class.forName(className); 74 | // The BuildInfoExporterAction instance 75 | Action action = build.getAction(clazz); 76 | 77 | // Check triggered builds 78 | if (action != null) { 79 | Method method = clazz.getMethod(methodName); 80 | return (List)method.invoke(action); 81 | } else { 82 | return EMPTY; 83 | } 84 | // All exceptions below are due to using reflection, thus silently 85 | // return an empty list as it doesn't exists. 86 | } catch (ClassNotFoundException e) { 87 | // Either the plugin doesn't exist, silently exit. 88 | // Or className is wrong - treated as it doesn't exist 89 | logger.log(Level.FINER, "Class " + className + " not installed. " 90 | + "Can't get downstream builds"); 91 | return EMPTY; 92 | } catch (NoSuchMethodException e) { 93 | logger.log(Level.FINER, "Method " + methodName 94 | + " doesn't exists in " + "class " + className + "."); 95 | return EMPTY; 96 | } catch (InvocationTargetException e) { 97 | return EMPTY; 98 | } catch (IllegalAccessException e) { 99 | return EMPTY; 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/test/java/com/sonyericsson/jenkins/plugins/bfa/jcasc/ConfigurationAsCodeMongoTest.java: -------------------------------------------------------------------------------- 1 | package com.sonyericsson.jenkins.plugins.bfa.jcasc; 2 | 3 | import com.sonyericsson.jenkins.plugins.bfa.PluginImpl; 4 | import com.sonyericsson.jenkins.plugins.bfa.db.MongoDBKnowledgeBase; 5 | import com.sonyericsson.jenkins.plugins.bfa.sod.ScanOnDemandVariables; 6 | import io.jenkins.plugins.casc.ConfigurationContext; 7 | import io.jenkins.plugins.casc.ConfiguratorRegistry; 8 | import io.jenkins.plugins.casc.misc.ConfiguredWithCode; 9 | import io.jenkins.plugins.casc.misc.JenkinsConfiguredWithCodeRule; 10 | import io.jenkins.plugins.casc.misc.junit.jupiter.WithJenkinsConfiguredWithCode; 11 | import io.jenkins.plugins.casc.model.CNode; 12 | import org.junit.jupiter.api.Test; 13 | 14 | import static io.jenkins.plugins.casc.misc.Util.getUnclassifiedRoot; 15 | import static io.jenkins.plugins.casc.misc.Util.toStringFromYamlFile; 16 | import static io.jenkins.plugins.casc.misc.Util.toYamlString; 17 | import static org.hamcrest.MatcherAssert.assertThat; 18 | import static org.hamcrest.core.Is.is; 19 | 20 | /** 21 | * Checks configuration as code integration for mongo DB. 22 | */ 23 | @WithJenkinsConfiguredWithCode 24 | class ConfigurationAsCodeMongoTest { 25 | 26 | /** 27 | * Support config as code import. 28 | * 29 | * @param j 30 | * 31 | */ 32 | @Test 33 | @ConfiguredWithCode("jcasc-mongo.yml") 34 | void shouldSupportConfigurationAsCode(JenkinsConfiguredWithCodeRule j) { 35 | PluginImpl plugin = PluginImpl.getInstance(); 36 | 37 | assertThat(plugin.isDoNotAnalyzeAbortedJob(), is(true)); 38 | assertThat(plugin.isGerritTriggerEnabled(), is(true)); 39 | assertThat(plugin.isGlobalEnabled(), is(true)); 40 | assertThat(plugin.isGraphsEnabled(), is(false)); 41 | 42 | MongoDBKnowledgeBase knowledgeBase = (MongoDBKnowledgeBase)plugin.getKnowledgeBase(); 43 | assertThat(knowledgeBase.getHost(), is("localhost")); 44 | assertThat(knowledgeBase.getDbName(), is("bfa")); 45 | assertThat(knowledgeBase.isEnableStatistics(), is(true)); 46 | assertThat(knowledgeBase.getUserName(), is("bfa")); 47 | assertThat(knowledgeBase.getPassword().getPlainText(), is("changeme")); 48 | assertThat(knowledgeBase.isSuccessfulLogging(), is(false)); 49 | 50 | assertThat(plugin.getNoCausesMessage(), is(ConfigurationAsCodeLocalTest.NO_CAUSES_MESSAGE)); 51 | 52 | assertThat(plugin.getNrOfScanThreads(), is(ConfigurationAsCodeLocalTest.EXPECTED_SCAN_THREADS)); 53 | 54 | ScanOnDemandVariables sodVariables = plugin.getSodVariables(); 55 | 56 | assertThat(sodVariables.getMaximumSodWorkerThreads(), 57 | is(ConfigurationAsCodeLocalTest.EXPECTED_MAXIMUM_SOD_WORKER_THREADS)); 58 | assertThat(sodVariables.getMinimumSodWorkerThreads(), 59 | is(ConfigurationAsCodeLocalTest.EXPECTED_MINIMUM_SOD_WORKER_THREADS)); 60 | assertThat(sodVariables.getSodCorePoolNumberOfThreads(), 61 | is(ConfigurationAsCodeLocalTest.EXPECTED_SOD_CORE_POOL_NUMBER_OF_THREADS)); 62 | assertThat(sodVariables.getSodThreadKeepAliveTime(), 63 | is(ConfigurationAsCodeLocalTest.EXPECTED_SOD_THREAD_KEEP_ALIVE_TIME)); 64 | assertThat(sodVariables.getSodWaitForJobShutdownTimeout(), 65 | is(ConfigurationAsCodeLocalTest.EXPECTED_SOD_JOB_SHUTDOWN_TIMEOUT)); 66 | 67 | assertThat(plugin.getTestResultCategories(), is("hgjghhlllllaa")); 68 | assertThat(plugin.isTestResultParsingEnabled(), is(true)); 69 | 70 | assertThat(plugin.isMetricSquashingEnabled(), is(false)); 71 | } 72 | 73 | /** 74 | * Support config as code export. 75 | * 76 | * @param j 77 | * 78 | * @throws Exception if so. 79 | */ 80 | @Test 81 | @ConfiguredWithCode("jcasc-mongo.yml") 82 | void shouldSupportConfigurationExport(JenkinsConfiguredWithCodeRule j) throws Exception { 83 | ConfiguratorRegistry registry = ConfiguratorRegistry.get(); 84 | ConfigurationContext context = new ConfigurationContext(registry); 85 | CNode yourAttribute = getUnclassifiedRoot(context).get("buildFailureAnalyzer"); 86 | 87 | String exported = toYamlString(yourAttribute) 88 | .replaceAll(".+password: .+", ""); // ignore dynamic password secret 89 | 90 | String expected = toStringFromYamlFile(this, "jcasc-mongo-expected.yml"); 91 | 92 | assertThat(exported, is(expected)); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/resources/com/sonyericsson/jenkins/plugins/bfa/model/FailureCause/index.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2012 Sony Mobile Communications Inc. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.sonyericsson.jenkins.plugins.bfa.model.FailureCause 25 | import com.sonyericsson.jenkins.plugins.bfa.PluginImpl 26 | import hudson.Util 27 | 28 | import java.text.DateFormat 29 | 30 | def f = namespace(lib.FormTagLib) 31 | def l = namespace(lib.LayoutTagLib) 32 | def j = namespace(lib.JenkinsTagLib) 33 | 34 | l.layout(permission: PluginImpl.UPDATE_PERMISSION) { 35 | l.header(title: _("Failure Cause Management") + " " + my.getName()) 36 | 37 | def management = my.getAncestorCauseManagement(); 38 | 39 | context.setVariable("descriptor", my.getDescriptor()); 40 | descriptor.setLastFailedBuildUrl(); 41 | 42 | l.side_panel() { 43 | if (!management.isUnderTest()) { 44 | include(management.getOwner(), "sidepanel.jelly") 45 | } 46 | } 47 | 48 | l.main_panel() { 49 | l.app_bar(title:"Failure Cause") { 50 | if (Util.fixEmpty(my.getId()) != null) { 51 | a(class: "jenkins-button jenkins-!-destructive-color", href: "../remove?id=" + my.getId(), tooltip: _("Remove this cause")) { 52 | l.icon(src:"symbol-trash") 53 | text(_("Remove")) 54 | } 55 | } 56 | } 57 | 58 | f.form(action: "configSubmit", method: "POST", name: "causeForm", class: "jenkins-form") { 59 | f.invisibleEntry() { 60 | f.textbox(field: "id", value: my.getId()) 61 | } 62 | f.entry(title: _("Name"), field: "name") { 63 | f.textbox(value: my.getName(), checkMethod: "post") 64 | } 65 | f.entry(title: _("Description"), field: "description") { 66 | f.textarea(value: my.getDescription(), checkMethod: "post") 67 | } 68 | f.entry(title: _("Comment"), field: "comment") { 69 | f.textarea(value: my.getComment()) 70 | } 71 | f.entry(title: _("Categories"), field: "categories") { 72 | f.textbox(value: my.getCategoriesAsString(), autoCompleteDelimChar: " ") 73 | } 74 | f.section(title: _("Indications")) { 75 | f.block { 76 | f.hetero_list( 77 | name: "indications", 78 | hasHeader: true, 79 | descriptors: management.getIndicationDescriptors(), 80 | items: my.getIndications(), 81 | addCaption: _("Add Indication"), 82 | deleteCaption: _("Delete Indication")) 83 | } 84 | } 85 | f.section(title: _("Modification history")) { 86 | def history = my.getAndInitiateModifications(); 87 | f.block { 88 | if (history != null) { 89 | ul(id: "modifications") { 90 | history.each{ entry -> 91 | def dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, 92 | DateFormat.SHORT).format(entry.getTime()); 93 | li {text(_("ModifiedBy", dateFormat, 94 | entry.getUser() == null ? "unknown": entry.getUser()))} 95 | } 96 | } 97 | } 98 | } 99 | } 100 | f.block { 101 | div(style: "margin-top: 10px") 102 | f.submit(value: _("Save")) 103 | } 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/model/FailureCauseColumn.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2014 Vincent Latombe 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.sonyericsson.jenkins.plugins.bfa.model; 25 | 26 | import hudson.Extension; 27 | import hudson.model.Job; 28 | import hudson.model.Run; 29 | import hudson.views.ListViewColumnDescriptor; 30 | import hudson.views.ListViewColumn; 31 | 32 | import java.util.Collections; 33 | import java.util.List; 34 | 35 | import org.kohsuke.stapler.DataBoundConstructor; 36 | 37 | /** 38 | * A column that user can add to a view to display the failure cause of the last build. 39 | * 40 | * @author vlatombe 41 | * 42 | */ 43 | public class FailureCauseColumn extends ListViewColumn { 44 | 45 | /** 46 | * The descriptor for {@link FailureCauseColumn}. 47 | * @author vlatombe 48 | * 49 | */ 50 | @Extension 51 | public static class DescriptorImpl extends ListViewColumnDescriptor { 52 | @Override 53 | public String getDisplayName() { 54 | return "Failure Cause"; 55 | } 56 | 57 | @Override 58 | public boolean shownByDefault() { 59 | return false; 60 | } 61 | } 62 | 63 | private boolean showText; 64 | 65 | /** 66 | * The standard data-bound constructor. 67 | * 68 | * @param showText 69 | * if true, will display the text of the failure cause next to the icon 70 | */ 71 | @DataBoundConstructor 72 | public FailureCauseColumn(boolean showText) { 73 | this.showText = showText; 74 | } 75 | 76 | /** 77 | * @see FailureCauseBuildAction#getBadgeImageUrl() 78 | * @param job The given job we want the badge image url for 79 | * @return the image url 80 | * @deprecated plugin now uses icons. Please use {@link #getIconFileName(Job)} instead. 81 | */ 82 | @Deprecated 83 | public String getBadgeImageUrl(Job job) { 84 | FailureCauseBuildAction action = findFailureCauseBuildAction(job); 85 | if (action == null) { 86 | return null; 87 | } 88 | return action.getBadgeImageUrl(); 89 | } 90 | 91 | /** 92 | * @see FailureCauseBuildAction#getIconFileName() 93 | * @param job The given job we want the badge icon name for 94 | * @return the icon name 95 | */ 96 | public String getIconFileName(Job job) { 97 | FailureCauseBuildAction action = findFailureCauseBuildAction(job); 98 | if (action == null) { 99 | return null; 100 | } 101 | return action.getIconFileName(); 102 | } 103 | 104 | 105 | /** 106 | * @see FailureCauseBuildAction#getFoundFailureCauses() 107 | * @param job the job we want to retrieve actions for 108 | * @return the list of found failure causes 109 | */ 110 | public List getFoundFailureCauses(Job job) { 111 | FailureCauseBuildAction action = findFailureCauseBuildAction(job); 112 | if (action == null) { 113 | return Collections.emptyList(); 114 | } 115 | return action.getFoundFailureCauses(); 116 | } 117 | 118 | /** 119 | * @return true if text should be displayed next to the failure cause icon 120 | */ 121 | public boolean isShowText() { 122 | return showText; 123 | } 124 | 125 | /** 126 | * A helper method to retrieve the {@link FailureCauseBuildAction} from the given {@link Job} 127 | * @param job the given job 128 | * @return The {@link FailureCauseBuildAction} if it exists, otherwise null 129 | */ 130 | private FailureCauseBuildAction findFailureCauseBuildAction(Job job) { 131 | if (job == null) { 132 | return null; 133 | } 134 | Run lastBuild = job.getLastBuild(); 135 | if (lastBuild == null) { 136 | return null; 137 | } 138 | return lastBuild.getAction(FailureCauseBuildAction.class); 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /src/test/java/com/sonyericsson/jenkins/plugins/bfa/db/EmbeddedMongoTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2013 Sony Mobile Communications AB. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.sonyericsson.jenkins.plugins.bfa.db; 25 | 26 | import de.flapdoodle.embed.mongo.Command; 27 | import de.flapdoodle.embed.mongo.MongodExecutable; 28 | import de.flapdoodle.embed.mongo.MongodProcess; 29 | import de.flapdoodle.embed.mongo.MongodStarter; 30 | import de.flapdoodle.embed.mongo.config.DownloadConfigBuilder; 31 | import de.flapdoodle.embed.mongo.config.ExtractedArtifactStoreBuilder; 32 | import de.flapdoodle.embed.mongo.config.IMongodConfig; 33 | import de.flapdoodle.embed.mongo.config.MongodConfigBuilder; 34 | import de.flapdoodle.embed.mongo.config.RuntimeConfigBuilder; 35 | import de.flapdoodle.embed.mongo.distribution.Version; 36 | import de.flapdoodle.embed.process.config.IRuntimeConfig; 37 | import de.flapdoodle.embed.process.config.store.IDownloadConfig; 38 | import org.junit.jupiter.api.AfterEach; 39 | import org.junit.jupiter.api.BeforeEach; 40 | import java.io.IOException; 41 | 42 | /** 43 | * Abstract class to be extended for running tests with Embedded MongoDB. 44 | * A knowledgeBase is created during setUp, which is backed up by a 45 | * real MongoDB instance. 46 | * 47 | * @author Fredrik Persson <fredrik6.persson@sonymobile.com> 48 | * 49 | */ 50 | abstract class EmbeddedMongoTest { 51 | 52 | /** 53 | * KnowledgeBase to be used for testing. 54 | */ 55 | protected KnowledgeBase knowledgeBase; 56 | 57 | private static final String LOCALHOST = "127.0.0.1"; 58 | private static final String DB_NAME = "jenkinsbfa"; 59 | 60 | private static final String mongoURL = System.getProperty(EmbeddedMongoTest.class.getName() + ".mongoURL"); 61 | 62 | private MongodExecutable mongodExe = null; 63 | private MongodProcess mongodProc = null; 64 | 65 | /** 66 | * Sets up an instance of {@link MongoDBKnowledgeBase} backed up by a real MongoDB, to be used for testing. 67 | * @throws IOException if something goes wrong 68 | */ 69 | @BeforeEach 70 | public void setUp() throws IOException { 71 | MongodStarter runtime; 72 | if (mongoURL != null) { 73 | // Use separate URL for fetching mongoDB artifacts. 74 | Command command = Command.MongoD; 75 | IDownloadConfig downloadConf = 76 | new DownloadConfigBuilder().defaultsForCommand(command).downloadPath(mongoURL).build(); 77 | de.flapdoodle.embed.process.store.ExtractedArtifactStoreBuilder artifactStoreBuilder = 78 | new ExtractedArtifactStoreBuilder().defaults(command).download(downloadConf); 79 | 80 | IRuntimeConfig runtimeConfig = new RuntimeConfigBuilder() 81 | .defaults(command) 82 | .artifactStore(artifactStoreBuilder) 83 | .build(); 84 | 85 | runtime = MongodStarter.getInstance(runtimeConfig); 86 | } else { 87 | runtime = MongodStarter.getDefaultInstance(); 88 | } 89 | 90 | IMongodConfig conf = new MongodConfigBuilder().version(Version.Main.V3_6).build(); 91 | mongodExe = runtime.prepare(conf); 92 | mongodProc = mongodExe.start(); 93 | 94 | int port = conf.net().getPort(); 95 | knowledgeBase = new MongoDBKnowledgeBase(LOCALHOST, port, DB_NAME, null, null, true, false); 96 | } 97 | 98 | /** 99 | * Tears down the test environment. 100 | */ 101 | @AfterEach 102 | public void tearDown() { 103 | if (this.mongodProc != null) { 104 | this.mongodProc.stop(); 105 | this.mongodExe.stop(); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/test/java/com/sonyericsson/jenkins/plugins/bfa/test/utils/DifferentKnowledgeBase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2012 Sony Mobile Communications AB. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package com.sonyericsson.jenkins.plugins.bfa.test.utils; 26 | 27 | import com.sonyericsson.jenkins.plugins.bfa.db.KnowledgeBase; 28 | import com.sonyericsson.jenkins.plugins.bfa.db.LocalFileKnowledgeBase; 29 | import com.sonyericsson.jenkins.plugins.bfa.model.FailureCause; 30 | import hudson.Extension; 31 | import hudson.model.Descriptor; 32 | import jenkins.model.Jenkins; 33 | import org.kohsuke.stapler.DataBoundConstructor; 34 | 35 | import java.util.List; 36 | import java.util.Objects; 37 | import java.util.UUID; 38 | 39 | import static hudson.Util.fixEmpty; 40 | 41 | /** 42 | * @author Robert Sandell <robert.sandell@sonyericsson.com> 43 | */ 44 | public class DifferentKnowledgeBase extends LocalFileKnowledgeBase { 45 | 46 | private String someString; 47 | 48 | /** 49 | * Standard Databound constructor. 50 | * 51 | * @param someString the string. 52 | */ 53 | @DataBoundConstructor 54 | public DifferentKnowledgeBase(String someString) { 55 | this.someString = someString; 56 | } 57 | 58 | /** 59 | * Standard constructor. 60 | * 61 | * @param initial the initial db, can be null. 62 | */ 63 | public DifferentKnowledgeBase(List initial) { 64 | if (initial != null) { 65 | for (FailureCause c : initial) { 66 | if (fixEmpty(c.getId()) == null) { 67 | c.setId(UUID.randomUUID().toString()); 68 | } 69 | put(c); 70 | } 71 | } 72 | } 73 | 74 | @Override 75 | public boolean equals(KnowledgeBase oldKnowledgeBase) { 76 | return super.equals(oldKnowledgeBase) 77 | && ((DifferentKnowledgeBase)oldKnowledgeBase).someString.equals(someString); 78 | } 79 | 80 | //CS IGNORE AvoidInlineConditionals FOR NEXT 29 LINES. REASON: Auto generated code. 81 | 82 | @Override 83 | public boolean equals(Object o) { 84 | if (this == o) { 85 | return true; 86 | } 87 | if (o == null || getClass() != o.getClass()) { 88 | return false; 89 | } 90 | if (!super.equals(o)) { 91 | return false; 92 | } 93 | 94 | DifferentKnowledgeBase that = (DifferentKnowledgeBase)o; 95 | 96 | return Objects.equals(someString, that.someString); 97 | } 98 | 99 | @Override 100 | public int hashCode() { 101 | //CS IGNORE MagicNumber FOR NEXT 3 LINES. REASON: Auto generated code. 102 | int result = super.hashCode(); 103 | result = 31 * result + (someString != null ? someString.hashCode() : 0); 104 | return result; 105 | } 106 | 107 | /** 108 | * A configurable string. 109 | * 110 | * @return some string. 111 | */ 112 | public String getSomeString() { 113 | return someString; 114 | } 115 | 116 | /** 117 | * A configurable string. 118 | * 119 | * @param someString some string. 120 | */ 121 | public void setSomeString(String someString) { 122 | this.someString = someString; 123 | } 124 | 125 | @Override 126 | public Descriptor getDescriptor() { 127 | return Jenkins.get().getDescriptorByType(DifferentKnowledgeBaseDescriptor.class); 128 | } 129 | 130 | /** 131 | * Descriptor for {@link DifferentKnowledgeBase}. 132 | */ 133 | @Extension 134 | public static class DifferentKnowledgeBaseDescriptor extends KnowledgeBaseDescriptor { 135 | 136 | @Override 137 | public String getDisplayName() { 138 | return "A Different One"; 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/main/java/com/sonyericsson/jenkins/plugins/bfa/GerritMessageProviderExtension.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright 2012 Sony Mobile Communications AB. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | package com.sonyericsson.jenkins.plugins.bfa; 25 | 26 | import com.sonyericsson.hudson.plugins.gerrit.trigger.gerritnotifier.GerritMessageProvider; 27 | import com.sonyericsson.jenkins.plugins.bfa.model.FailureCauseBuildAction; 28 | import com.sonyericsson.jenkins.plugins.bfa.model.FailureCauseDisplayData; 29 | import com.sonyericsson.jenkins.plugins.bfa.model.FoundFailureCause; 30 | 31 | import hudson.Extension; 32 | import hudson.model.Run; 33 | import jenkins.model.Jenkins; 34 | 35 | import java.util.List; 36 | 37 | /** 38 | * ExtensionPoint that allows BFA to send the failure cause description 39 | * directly to Gerrit. 40 | * 41 | * @author Gustaf Lundh <gustaf.lundh@sonymobile.com> 42 | */ 43 | @Extension(optional = true) 44 | public class GerritMessageProviderExtension extends GerritMessageProvider { 45 | 46 | @Override 47 | public String getBuildCompletedMessage(Run build) { 48 | if (PluginImpl.getInstance().isGerritTriggerEnabled()) { 49 | StringBuilder customMessage = new StringBuilder(); 50 | if (build != null) { 51 | FailureCauseBuildAction action = build.getAction(FailureCauseBuildAction.class); 52 | if (action != null) { 53 | FailureCauseDisplayData displayData = action.getFailureCauseDisplayData(); 54 | 55 | addFailureCausesFromData(customMessage, displayData); 56 | printDownstream(customMessage, displayData.getDownstreamFailureCauses()); 57 | 58 | if (customMessage.length() > 0) { 59 | return customMessage.toString().replace("'", "\""); 60 | } 61 | } 62 | } 63 | } 64 | return null; 65 | } 66 | 67 | /** 68 | * 69 | * Adds all causes from downstream builds in recursion 70 | * 71 | * @param message the StringBuilder to add to. 72 | * @param downstreamFailureCauses the list of downstream failures. 73 | */ 74 | private void printDownstream(StringBuilder message, List downstreamFailureCauses) { 75 | if (!downstreamFailureCauses.isEmpty()) { 76 | for (FailureCauseDisplayData displayData : downstreamFailureCauses) { 77 | addFailureCausesFromData(message, displayData); 78 | printDownstream(message, displayData.getDownstreamFailureCauses()); 79 | } 80 | } 81 | } 82 | 83 | /** 84 | * Appends FailureCause information to provided StringBuilder. 85 | * 86 | * @param message the StringBuilder to add to 87 | * @param displayData the data of downstream failures 88 | */ 89 | private void addFailureCausesFromData(StringBuilder message, FailureCauseDisplayData displayData) { 90 | for (FoundFailureCause failureCause : displayData.getFoundFailureCauses()) { 91 | if (message.length() > 0) { 92 | message.append("\n\n"); 93 | } 94 | message.append(failureCause.getDescription()); 95 | 96 | message.append(" ( ") 97 | .append(Jenkins.getInstance().getRootUrl()) 98 | .append(displayData.getLinks().getBuildUrl()) 99 | .append(" )"); 100 | } 101 | 102 | if (displayData.getDownstreamFailureCauses().isEmpty() && displayData.getFoundFailureCauses().isEmpty()) { 103 | if (message.length() > 0) { 104 | message.append("\n\n"); 105 | } 106 | 107 | message.append(PluginImpl.getInstance().getNoCausesMessage()) 108 | .append(" ( ") 109 | .append(Jenkins.getInstance().getRootUrl()) 110 | .append(displayData.getLinks().getBuildUrl()) 111 | .append(" )"); 112 | } 113 | } 114 | } 115 | --------------------------------------------------------------------------------