├── .gitignore ├── .travis.yml ├── LICENSE ├── changelog.md ├── config ├── checkstyle-suppressions.xml └── checkstyle.xml ├── docs ├── add-credentials.png ├── advanced.md ├── conduit-token.png ├── configure-credentials.png ├── configure-job-environment.png ├── configure-job-parameters.png ├── configure-job-post-build.png ├── custom-comment.png ├── custom-lint.png ├── example-path-haiku.png ├── harbormaster-plan.png ├── harbormaster-suspend-param.png ├── herald-rule.png ├── inline-haiku.png ├── jenkins-suspend-param.png └── uberalls-integration.png ├── phabricator-plugin.iml ├── pom.xml ├── readme.md └── src ├── main ├── java │ └── com │ │ └── uber │ │ └── jenkins │ │ └── phabricator │ │ ├── BuildResultProcessor.java │ │ ├── CommentBuilder.java │ │ ├── ConduitCredentialsDescriptor.java │ │ ├── LauncherFactory.java │ │ ├── PhabricatorBuildWrapper.java │ │ ├── PhabricatorBuildWrapperDescriptor.java │ │ ├── PhabricatorCauseOfInterruption.java │ │ ├── PhabricatorNotifier.java │ │ ├── PhabricatorNotifierDescriptor.java │ │ ├── PhabricatorPlugin.java │ │ ├── PhabricatorPostbuildAction.java │ │ ├── PhabricatorPostbuildSummaryAction.java │ │ ├── RemoteFileFetcher.java │ │ ├── conduit │ │ ├── ArcanistClient.java │ │ ├── ArcanistUsageException.java │ │ ├── ConduitAPIClient.java │ │ ├── ConduitAPIException.java │ │ ├── Differential.java │ │ ├── DifferentialClient.java │ │ └── HarbormasterClient.java │ │ ├── coverage │ │ ├── CoberturaCoverageProvider.java │ │ ├── CoberturaXMLParser.java │ │ ├── CodeCoverageMetrics.java │ │ ├── CoverageConverter.java │ │ ├── CoverageProvider.java │ │ └── PathResolver.java │ │ ├── credentials │ │ ├── ConduitCredentials.java │ │ ├── ConduitCredentialsImpl.java │ │ └── ConduitCredentialsNameProvider.java │ │ ├── lint │ │ ├── LintResult.java │ │ └── LintResults.java │ │ ├── provider │ │ ├── BaseProvider.java │ │ ├── InstanceProvider.java │ │ └── Provider.java │ │ ├── tasks │ │ ├── ApplyPatchTask.java │ │ ├── NonDifferentialBuildTask.java │ │ ├── NonDifferentialHarbormasterTask.java │ │ ├── PostCommentTask.java │ │ ├── SendHarbormasterResultTask.java │ │ ├── SendHarbormasterUriTask.java │ │ └── Task.java │ │ ├── uberalls │ │ └── UberallsClient.java │ │ ├── unit │ │ ├── JUnitTestProvider.java │ │ ├── UnitResult.java │ │ ├── UnitResults.java │ │ └── UnitTestProvider.java │ │ └── utils │ │ ├── CommonUtils.java │ │ └── Logger.java ├── resources │ ├── com │ │ └── uber │ │ │ └── jenkins │ │ │ └── phabricator │ │ │ ├── PhabricatorBuildWrapper │ │ │ ├── config.jelly │ │ │ └── global.jelly │ │ │ ├── PhabricatorNotifier │ │ │ ├── config.jelly │ │ │ ├── global.jelly │ │ │ └── help-conduitURL.html │ │ │ ├── PhabricatorPostbuildAction │ │ │ └── badge.jelly │ │ │ ├── PhabricatorPostbuildSummaryAction │ │ │ └── summary.jelly │ │ │ └── credentials │ │ │ └── ConduitCredentialsImpl │ │ │ ├── config.jelly │ │ │ └── help-gateway.html │ └── index.jelly └── webapp │ └── images │ └── phabricator.png └── test ├── java └── com │ └── uber │ └── jenkins │ └── phabricator │ ├── BuildIntegrationTest.java │ ├── BuildResultProcessorTest.java │ ├── CommentBuilderTest.java │ ├── FakeConduit.java │ ├── LauncherFactoryTest.java │ ├── PhabricatorBuildWrapperTest.java │ ├── PhabricatorNotifierTest.java │ ├── PhabricatorPostbuildActionTest.java │ ├── RemoteFileFetcherTest.java │ ├── conduit │ ├── ArcanistClientTest.java │ ├── ConduitAPIClientTest.java │ ├── DifferentialClientTest.java │ └── DifferentialTest.java │ ├── coverage │ ├── CoberturaCoverageProviderTest.java │ ├── CoberturaXMLParserTest.java │ ├── FakeCoverageProvider.java │ └── PathResolverTest.java │ ├── credentials │ └── ConduitCredentialsImplTest.java │ ├── provider │ ├── BaseProviderTest.java │ └── InstanceProviderTest.java │ ├── tasks │ ├── ApplyPatchTaskTest.java │ ├── NonDifferentialBuildTaskTest.java │ ├── NonDifferentialHarbormasterTaskTest.java │ ├── PostCommentTaskTest.java │ ├── SendHarbormasterResultTaskTest.java │ └── SendHarbormasterUriTaskTest.java │ ├── uberalls │ └── UberallsClientTest.java │ ├── unit │ ├── JUnitTestProviderTest.java │ ├── UnitResultTest.java │ └── UnitResultsTest.java │ └── utils │ ├── CommonUtilsTest.java │ ├── LoggerTest.java │ └── TestUtils.java └── resources └── com └── uber └── jenkins └── phabricator ├── conduit ├── ResponseWithChanges.json ├── fetchDiffResponseMissingDiff.json ├── fetchDiffWithResponseArray.json ├── missingAuthorResponse.json ├── unitResultWithFailureRequest.json ├── validDifferentialQueryResponse.json └── validFetchDiffResponse.json ├── coverage ├── go-torch-coverage.xml ├── go-torch-coverage1.xml ├── go-torch-coverage2.xml ├── go-torch-coverage3.xml ├── go-torch-coverage_overwrite.xml └── python-coverage.xml ├── uberalls └── validCoverage.json └── unit ├── go-torch-junit-fail.xml └── go-torch-junit.xml /.gitignore: -------------------------------------------------------------------------------- 1 | work/ 2 | target/ 3 | .idea 4 | .DS_Store 5 | *.iml 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: java 3 | sudo: true 4 | 5 | matrix: 6 | fast_finish: true 7 | include: 8 | - jdk: openjdk7 9 | env: MAIN_ARGS="test" 10 | - jdk: oraclejdk7 11 | env: MAIN_ARGS="test" 12 | - jdk: oraclejdk8 13 | env: MAIN_ARGS="cobertura:cobertura coveralls:report" 14 | 15 | script: 16 | - mvn clean $MAIN_ARGS 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Uber 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ### 1.9.8 (2016/08/26) 4 | 5 | * Abort existing builds when a new build referencing same diff is scheduled (Gautam Korlam) 6 | * Add a gateway option - used as an override to url in Conduit credentials 7 | 8 | ### 1.9.7 (2016/08/09) 9 | 10 | * Report lint warnings from file (Anup Talwalkar) 11 | * Add "details" to unit results from "failure" in JUnit files (Haotian Liu) 12 | * Soften error message on URI artifact to prevent confusion about build failures 13 | 14 | ### 1.9.6 (2016/07/17) 15 | 16 | * Fix incorrect line coverage when merging multiple cobertura reports 17 | 18 | ### 1.9.5 (2016/05/02) 19 | 20 | * Use filenames to compute set of files to publish line coverage 21 | 22 | ### 1.9.4 (2016/04/28) 23 | 24 | * Publish inline coverage data only for changed files in the diff 25 | * Cleanup coverage files on jenkins master to save disk space 26 | 27 | ### 1.9.3 (2016/04/1) 28 | 29 | * Remove deprecated "Build started" comments in favor of Harbormaster 30 | 31 | ### 1.9.2 (2016/03/10) 32 | 33 | * Fix Harbormaster coverage filename/path detection for Python's coverage>=4.0.3 34 | * Add differential variables to environment, display differential summary on build 35 | summary view 36 | * Send build URL to Harbormaster when build starts (Chaitanya Pramod) 37 | 38 | ### 1.9.1 (2016/01/25) 39 | 40 | * Remove coverage dependency on cobertura build action. Allows Uberalls coverage 41 | to work when the cobertura plugin is not enabled (for performance 42 | reasons). (Gautam Korlam) 43 | * Improve readme (Brody Klapko) 44 | * Search for coverage files recursively when Cobertura publisher is disabled 45 | (Gautam Korlam) 46 | 47 | ### 1.9.0 (2016/01/19) 48 | 49 | * Add more logging on differential fetch failure 50 | * Allow user to apply patch with force flag (Chaitanya Pramod) 51 | * Fix crash when missing cobertura plugin 52 | * Send Harbormaster status on non-Differential commits 53 | 54 | ### 1.8.3 (2015/12/09) 55 | 56 | * JENKINS-31335: Add checkbox to skip git clean step (Alexander Yerenkow) 57 | * Add option to create branch when applying diff (cellscape) 58 | * Collapse comment checkboxes when disabled (Gautam Korlam) 59 | 60 | ### 1.8.2 (2015/11/01) 61 | 62 | * Fix "comment size" option not being saved 63 | * Support merging multiple Cobertura coverage files, and fix source root 64 | detection (Gautam Korlam) 65 | 66 | ### 1.8.1 (2015/09/22) 67 | 68 | * Don't require Uberalls to be enabled to post coverage data to Harbormaster 69 | * Handle UTF-8 strings properly in comment file 70 | 71 | ### 1.8.0 (2015/09/09) 72 | 73 | * Qualify log statements with "phabricator:" 74 | * Send a Harbormaster URI Artifacts for the Jenkins build (Chris Burroughs) 75 | * Clean up internal Harbormaster API 76 | * Make the Cobertura plugin an optional dependency (only used for Uberalls) 77 | * Consistently set defaults for notifiers (Chris Burroughs) 78 | * Increase unit test coverage to >85% 79 | * Gracefully ignore missing author names/emails from conduit for summary badge 80 | * Report Cobertura coverage data to Harbormaster API 81 | * Add option to preserve formatting in additional comments (Gautam Korlam) 82 | * Report XUnit results to Harbormaster 83 | 84 | ### 1.7.2 (2015/08/13) 85 | 86 | * Fix HTML escaping on build summary view (regression from auto-escape in 1.7.1) 87 | 88 | ### 1.7.1 (2015/08/13) 89 | 90 | * Fix class loading error in Apache HTTP client 91 | * Bump minimum required Jenkins version to 1.609.2 (from 1.609) so that class exclusions work for above fix 92 | * Add escape-by-default to Jelly templates 93 | * Re-enable Javadoc step 94 | 95 | ### 1.7 (2015/08/12) 96 | 97 | * Conduit token and Phabricator URL are now configured via the [Credentials plugin](https://wiki.jenkins-ci.org/display/JENKINS/Credentials+Plugin) 98 | * Harbormaster messages are now sent over conduit (no more `arc` dependency) 99 | * Removed deprecated "uber-dot-arcanist" functionality 100 | * Removed unused JNA and trove4j dependencies 101 | * Various bugfixes 102 | * Major refactoring and testing 103 | 104 | ### 1.6.1 (2015/06/15) 105 | 106 | * Update wiki path for plugin 107 | 108 | ### 1.6 (2015/06/14) 109 | 110 | * Rename plugin from "Phabricator Plugin" to "Phabricator Differential Plugin" 111 | * Add checkbox to control "Build Started" comments being posted to Phabricator 112 | 113 | ### 1.5 (2015/06/09) 114 | 115 | * Handle invalid responses from conduit 116 | -------------------------------------------------------------------------------- /config/checkstyle-suppressions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 10 | 11 | -------------------------------------------------------------------------------- /config/checkstyle.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 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 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /docs/add-credentials.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/phabricator-plugin/00e0e549f9456fef3ea9a737197a62265e8c336f/docs/add-credentials.png -------------------------------------------------------------------------------- /docs/advanced.md: -------------------------------------------------------------------------------- 1 | Advanced Usage 2 | ============== 3 | 4 | In addition to Unit and Coverage results, this plugin supports two additional features 5 | you may want to take use of. Both options take a maximum number of bytes to copy, since the plugin 6 | is executed on the Jenkins master and syncing multiple megabytes of data can cause 7 | performance problems. 8 | 9 | Custom Comments 10 | --------------- 11 | 12 | If you'd like to post additional text back to Phabricator, you can add text to the `.phabricator-comment` file 13 | (you can change the name of the file in your job configuration page): 14 | 15 | ![Comment Configuration](/docs/custom-comment.png) 16 | 17 | Any text present in this file will be echoed verbatim to the comment that Jenkins posts back to 18 | Phabricator. If you'd like to preserve formatting, check the "Preserve Formatting" block and the 19 | plugin will surround the comment in triple-backticks (```) 20 | 21 | Custom Lint 22 | ----------- 23 | 24 | If you'd like to send Lint Violations as well, you can echo Harbormaster-compatible JSON 25 | (where each line is a valid JSON dictionary) into the `.phabricator-lint` file. 26 | 27 | Although each **line** must be valid JSON, note that the file as a whole is **not valid JSON** 28 | (e.g. if you call `JSON.parse('.phabricator-lint')`) it will fail. This is a design decision to 29 | make it easy for build scripts to `tee` (echo line-by-line) violations without having to 30 | produce well-formed JSON, which requires knowing upfront how many violations are present. 31 | 32 | ![Lint Configuration](/docs/custom-lint.png) 33 | 34 | If a job was configured to run the following shell script: 35 | 36 | ```bash 37 | mkdir example 38 | echo "Once upon a time\nThere was a Jenkins plugin" > example/path 39 | # NOTE: tee -a to support appending multiple lints 40 | echo '{"name": "Comment Name", "code": "Haiku", "severity": "error", "path": "example/path", "line": 2, "char": 0, "description": "Line is not a Haiku" }' | tee -a .phabricator-lint 41 | ``` 42 | 43 | You would see the following in your differential at the top: 44 | 45 | ![Inline Diff Lint](/docs/example-path-haiku.png) 46 | 47 | And the following in the code view: 48 | 49 | ![Inline Diff Lint](/docs/inline-haiku.png) 50 | 51 | See [Harbormaster Lint](https://secure.phabricator.com/conduit/method/harbormaster.sendmessage/) 52 | API for details on the supported JSON keys. `line`, `char`, and `description` are all optional. 53 | The rest are required. 54 | 55 | The severity parameter recognizes these severity levels: 56 | 57 | | Key | Name | 58 | |----------|----------| 59 | | advice | Advice | 60 | | autofix | Auto-Fix | 61 | | warning | Warning | 62 | | error | Error | 63 | | disabled | Disabled | 64 | 65 | Suspend Useless Jobs 66 | --------------------- 67 | 68 | When new builds are triggered from Phabricator due to new changes to the same diff or 69 | rebuilding via harbormaster, it may be desirable to suspend existing jobs that were triggered 70 | for the same diff. This can be done by adding the `ABORT_ON_REVISION_ID` string parameter to your job. 71 | 72 | ![abort on revision id parameter](/docs/jenkins-suspend-param.png) 73 | 74 | You need to also add the parameter to your harbormaster request 75 | ![abort on revision id parameter](/docs/harbormaster-suspend-param.png) 76 | 77 | This makes the latest build triggered for a diff automatically abort the existing running builds 78 | for the same diff on the job. Jobs aborted this way will skip notifying phabricator to 79 | avoid confusion. Please note that builds on the same diff triggered by the same upstream build will not be aborted this way. This can be useful when running multi-configuration jobs and parallel builds that run on the same diff. 80 | 81 | Also note that if you pass additional arguments to your harbormaster request they may need to be included in the `ABORT_ON_REVISION_ID` field as well. A good example is when you use the same CI job to build multiple targets on a single diff. So for example, if the jenkins request params have 82 | `TARGET=some_target`, then to ensure other targets are not cancelled for the same diff, you may want to set `ABORT_ON_REVISION_ID=some_target_${buildable.revision}`. 83 | -------------------------------------------------------------------------------- /docs/conduit-token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/phabricator-plugin/00e0e549f9456fef3ea9a737197a62265e8c336f/docs/conduit-token.png -------------------------------------------------------------------------------- /docs/configure-credentials.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/phabricator-plugin/00e0e549f9456fef3ea9a737197a62265e8c336f/docs/configure-credentials.png -------------------------------------------------------------------------------- /docs/configure-job-environment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/phabricator-plugin/00e0e549f9456fef3ea9a737197a62265e8c336f/docs/configure-job-environment.png -------------------------------------------------------------------------------- /docs/configure-job-parameters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/phabricator-plugin/00e0e549f9456fef3ea9a737197a62265e8c336f/docs/configure-job-parameters.png -------------------------------------------------------------------------------- /docs/configure-job-post-build.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/phabricator-plugin/00e0e549f9456fef3ea9a737197a62265e8c336f/docs/configure-job-post-build.png -------------------------------------------------------------------------------- /docs/custom-comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/phabricator-plugin/00e0e549f9456fef3ea9a737197a62265e8c336f/docs/custom-comment.png -------------------------------------------------------------------------------- /docs/custom-lint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/phabricator-plugin/00e0e549f9456fef3ea9a737197a62265e8c336f/docs/custom-lint.png -------------------------------------------------------------------------------- /docs/example-path-haiku.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/phabricator-plugin/00e0e549f9456fef3ea9a737197a62265e8c336f/docs/example-path-haiku.png -------------------------------------------------------------------------------- /docs/harbormaster-plan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/phabricator-plugin/00e0e549f9456fef3ea9a737197a62265e8c336f/docs/harbormaster-plan.png -------------------------------------------------------------------------------- /docs/harbormaster-suspend-param.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/phabricator-plugin/00e0e549f9456fef3ea9a737197a62265e8c336f/docs/harbormaster-suspend-param.png -------------------------------------------------------------------------------- /docs/herald-rule.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/phabricator-plugin/00e0e549f9456fef3ea9a737197a62265e8c336f/docs/herald-rule.png -------------------------------------------------------------------------------- /docs/inline-haiku.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/phabricator-plugin/00e0e549f9456fef3ea9a737197a62265e8c336f/docs/inline-haiku.png -------------------------------------------------------------------------------- /docs/jenkins-suspend-param.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/phabricator-plugin/00e0e549f9456fef3ea9a737197a62265e8c336f/docs/jenkins-suspend-param.png -------------------------------------------------------------------------------- /docs/uberalls-integration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/phabricator-plugin/00e0e549f9456fef3ea9a737197a62265e8c336f/docs/uberalls-integration.png -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/ConduitCredentialsDescriptor.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator; 22 | 23 | import com.cloudbees.plugins.credentials.CredentialsMatcher; 24 | import com.cloudbees.plugins.credentials.CredentialsMatchers; 25 | import com.cloudbees.plugins.credentials.CredentialsProvider; 26 | import com.cloudbees.plugins.credentials.common.StandardCredentials; 27 | import com.cloudbees.plugins.credentials.common.StandardListBoxModel; 28 | import com.cloudbees.plugins.credentials.domains.DomainRequirement; 29 | import com.uber.jenkins.phabricator.credentials.ConduitCredentials; 30 | import hudson.model.Item; 31 | import hudson.model.Job; 32 | import hudson.security.ACL; 33 | import hudson.util.ListBoxModel; 34 | import jenkins.model.Jenkins; 35 | import org.kohsuke.stapler.AncestorInPath; 36 | 37 | import java.util.ArrayList; 38 | import java.util.List; 39 | 40 | public class ConduitCredentialsDescriptor { 41 | private static List availableCredentials(Job owner) { 42 | return CredentialsProvider.lookupCredentials( 43 | ConduitCredentials.class, 44 | owner, 45 | null, 46 | new ArrayList() 47 | ); 48 | } 49 | 50 | public static ConduitCredentials getCredentials(Job owner, String credentialsID) { 51 | List available = availableCredentials(owner); 52 | if (available.size() == 0) { 53 | return null; 54 | } 55 | CredentialsMatcher matcher; 56 | if (credentialsID != null) { 57 | matcher = CredentialsMatchers.allOf(CredentialsMatchers.withId(credentialsID)); 58 | } else { 59 | matcher = CredentialsMatchers.always(); 60 | } 61 | return CredentialsMatchers.firstOrDefault( 62 | available, 63 | matcher, 64 | available.get(0) 65 | ); 66 | } 67 | 68 | public static ListBoxModel doFillCredentialsIDItems(@AncestorInPath Jenkins context) { 69 | if (context == null || !context.hasPermission(Item.CONFIGURE)) { 70 | return new StandardListBoxModel(); 71 | } 72 | 73 | List domainRequirements = new ArrayList(); 74 | return new StandardListBoxModel() 75 | .withEmptySelection() 76 | .withMatching( 77 | CredentialsMatchers.anyOf( 78 | CredentialsMatchers.instanceOf(ConduitCredentials.class)), 79 | CredentialsProvider.lookupCredentials( 80 | StandardCredentials.class, 81 | context, 82 | ACL.SYSTEM, 83 | domainRequirements)); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/LauncherFactory.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator; 22 | 23 | import hudson.EnvVars; 24 | import hudson.FilePath; 25 | import hudson.Launcher; 26 | 27 | import java.io.PrintStream; 28 | 29 | public class LauncherFactory { 30 | private final Launcher launcher; 31 | private final PrintStream stderr; 32 | private final EnvVars environment; 33 | private final FilePath pwd; 34 | 35 | public LauncherFactory(Launcher launcher, EnvVars environment, PrintStream stderr, FilePath pwd) { 36 | this.launcher = launcher; 37 | this.environment = environment; 38 | this.stderr = stderr; 39 | this.pwd = pwd; 40 | } 41 | 42 | public PrintStream getStderr() { 43 | return this.stderr; 44 | } 45 | 46 | /** 47 | * Create a launcher 48 | * @return a launcher suitable for executing programs within Jenkins 49 | */ 50 | public Launcher.ProcStarter launch() { 51 | return launcher.launch().envs(environment).stderr(stderr).pwd(pwd); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/PhabricatorBuildWrapperDescriptor.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator; 22 | 23 | import com.uber.jenkins.phabricator.credentials.ConduitCredentials; 24 | import hudson.Extension; 25 | import hudson.model.AbstractProject; 26 | import hudson.model.Job; 27 | import hudson.tasks.BuildWrapperDescriptor; 28 | import hudson.util.ListBoxModel; 29 | import jenkins.model.Jenkins; 30 | import net.sf.json.JSONObject; 31 | import org.kohsuke.stapler.AncestorInPath; 32 | import org.kohsuke.stapler.QueryParameter; 33 | import org.kohsuke.stapler.StaplerRequest; 34 | 35 | @SuppressWarnings("UnusedDeclaration") 36 | @Extension 37 | public final class PhabricatorBuildWrapperDescriptor extends BuildWrapperDescriptor { 38 | private String credentialsID; 39 | private String arcPath; 40 | 41 | public PhabricatorBuildWrapperDescriptor() { 42 | super(PhabricatorBuildWrapper.class); 43 | load(); 44 | } 45 | 46 | @Override 47 | public boolean isApplicable(AbstractProject abstractProject) { 48 | return true; 49 | } 50 | 51 | /** 52 | * This human readable name is used in the configuration screen. 53 | */ 54 | public String getDisplayName() { 55 | return "Apply Phabricator Differential"; 56 | } 57 | 58 | @SuppressWarnings("unused") 59 | public ListBoxModel doFillCredentialsIDItems(@AncestorInPath Jenkins context, 60 | @QueryParameter String remoteBase) { 61 | return ConduitCredentialsDescriptor.doFillCredentialsIDItems( 62 | context); 63 | } 64 | 65 | public ConduitCredentials getCredentials(Job owner) { 66 | return ConduitCredentialsDescriptor.getCredentials(owner, credentialsID); 67 | } 68 | 69 | @Override 70 | public boolean configure(StaplerRequest req, JSONObject formData) throws FormException { 71 | // To persist global configuration information, 72 | // set that to properties and call save(). 73 | req.bindJSON(this, formData.getJSONObject("phabricator")); 74 | save(); 75 | return super.configure(req,formData); 76 | } 77 | 78 | public String getCredentialsID() { 79 | return credentialsID; 80 | } 81 | 82 | public void setCredentialsID(String credentialsID) { 83 | this.credentialsID = credentialsID; 84 | } 85 | 86 | public String getArcPath() { 87 | return arcPath; 88 | } 89 | 90 | public void setArcPath(String arcPath) { 91 | this.arcPath = arcPath; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/PhabricatorCauseOfInterruption.java: -------------------------------------------------------------------------------- 1 | package com.uber.jenkins.phabricator; 2 | 3 | import jenkins.model.CauseOfInterruption; 4 | 5 | public final class PhabricatorCauseOfInterruption extends CauseOfInterruption { 6 | private final String buildUrl; 7 | 8 | PhabricatorCauseOfInterruption(String buildUrl) { 9 | this.buildUrl = buildUrl; 10 | } 11 | 12 | @Override 13 | public String getShortDescription() { 14 | return String.format("Aborted by %s", buildUrl); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/PhabricatorNotifierDescriptor.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator; 22 | 23 | import com.uber.jenkins.phabricator.credentials.ConduitCredentials; 24 | import com.uber.jenkins.phabricator.utils.CommonUtils; 25 | import hudson.Extension; 26 | import hudson.model.AbstractProject; 27 | import hudson.model.Job; 28 | import hudson.tasks.BuildStepDescriptor; 29 | import hudson.tasks.Publisher; 30 | import hudson.util.ListBoxModel; 31 | import jenkins.model.Jenkins; 32 | import net.sf.json.JSONObject; 33 | import org.kohsuke.stapler.AncestorInPath; 34 | import org.kohsuke.stapler.QueryParameter; 35 | import org.kohsuke.stapler.StaplerRequest; 36 | 37 | /** 38 | * Descriptor for {@link PhabricatorNotifier}. Used as a singleton. 39 | * The class is marked as public so that it can be accessed from views. 40 | * 41 | *

42 | * See src/main/resources/hudson/plugins/hello_world/PhabricatorNotifier/*.jelly 43 | * for the actual HTML fragment for the configuration screen. 44 | */ 45 | @SuppressWarnings("UnusedDeclaration") 46 | @Extension 47 | public final class PhabricatorNotifierDescriptor extends BuildStepDescriptor { 48 | private String credentialsID; 49 | private String uberallsURL; 50 | 51 | public PhabricatorNotifierDescriptor() { 52 | super(PhabricatorNotifier.class); 53 | load(); 54 | } 55 | 56 | public boolean isApplicable(Class aClass) { 57 | // Indicates that this builder can be used with all kinds of project types 58 | return true; 59 | } 60 | 61 | /** 62 | * This human readable name is used in the configuration screen. 63 | */ 64 | public String getDisplayName() { 65 | return "Post to Phabricator"; 66 | } 67 | 68 | @SuppressWarnings("unused") 69 | public ListBoxModel doFillCredentialsIDItems(@AncestorInPath Jenkins context, 70 | @QueryParameter String remoteBase) { 71 | return ConduitCredentialsDescriptor.doFillCredentialsIDItems( 72 | context); 73 | } 74 | 75 | public ConduitCredentials getCredentials(Job owner) { 76 | return ConduitCredentialsDescriptor.getCredentials(owner, credentialsID); 77 | } 78 | 79 | @Override 80 | public boolean configure(StaplerRequest req, JSONObject formData) throws FormException { 81 | // To persist global configuration information, 82 | // set that to properties and call save(). 83 | req.bindJSON(this, formData.getJSONObject("uberalls")); 84 | save(); 85 | return super.configure(req, formData); 86 | } 87 | 88 | public String getCredentialsID() { 89 | return credentialsID; 90 | } 91 | 92 | public void setCredentialsID(String credentialsID) { 93 | this.credentialsID = credentialsID; 94 | } 95 | 96 | public String getUberallsURL() { 97 | if (!CommonUtils.isBlank(uberallsURL)) { 98 | return uberallsURL; 99 | } 100 | return null; 101 | } 102 | 103 | public void setUberallsURL(String value) { 104 | uberallsURL = value; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/PhabricatorPlugin.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator; 22 | 23 | import hudson.Plugin; 24 | import hudson.PluginWrapper; 25 | import jenkins.model.Jenkins; 26 | 27 | import java.io.File; 28 | 29 | public class PhabricatorPlugin extends Plugin { 30 | // Diff ID (not differential ID) 31 | public static final String DIFFERENTIAL_ID_FIELD = "DIFF_ID"; 32 | // Phabricator object ID (for Harbormaster) 33 | public static final String PHID_FIELD = "PHID"; 34 | // Revision ID (to abort old running jobs) 35 | public static final String ABORT_ON_REVISION_ID_FIELD = "ABORT_ON_REVISION_ID"; 36 | 37 | public static String getIconPath(String icon) { 38 | if (icon == null) { 39 | return null; 40 | } 41 | if (icon.startsWith("/")) { 42 | return icon; 43 | } 44 | 45 | // Try plugin images dir, fallback to Hudson images dir 46 | PluginWrapper wrapper = Jenkins.getInstance().getPluginManager().getPlugin(PhabricatorPlugin.class); 47 | 48 | boolean pluginIconExists = (wrapper != null) && new File(wrapper.baseResourceURL.getPath() + "/images/" + icon).exists(); 49 | return pluginIconExists ? "/plugin/" + wrapper.getShortName() + "/images/" + icon : Jenkins.RESOURCE_PATH + "/images/16x16/" + icon; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/PhabricatorPostbuildAction.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator; 22 | 23 | import hudson.model.BuildBadgeAction; 24 | import org.kohsuke.stapler.export.Exported; 25 | 26 | /** 27 | * Ripped from https://github.com/jenkinsci/groovy-postbuild-plugin/blob/master/src/main/java/org/jvnet/hudson/plugins/groovypostbuild/GroovyPostbuildAction.java 28 | */ 29 | public class PhabricatorPostbuildAction implements BuildBadgeAction { 30 | private final String iconPath; 31 | private final String text; 32 | private final String color = "#1FBAD6"; 33 | private final String background = "transparent"; 34 | private final String border = "0"; 35 | private final String borderColor = "transparent"; 36 | private final String link; 37 | 38 | private PhabricatorPostbuildAction(String text, String link) { 39 | this.iconPath = null; 40 | this.text = text; 41 | this.link = link; 42 | } 43 | 44 | public static PhabricatorPostbuildAction createShortText(String text, String link) { 45 | return new PhabricatorPostbuildAction(text, link); 46 | } 47 | 48 | /* Action methods */ 49 | public String getUrlName() { 50 | return ""; 51 | } 52 | 53 | public String getDisplayName() { 54 | return ""; 55 | } 56 | 57 | public String getIconFileName() { 58 | return null; 59 | } 60 | 61 | @Exported public boolean isTextOnly() { 62 | return (iconPath == null); 63 | } 64 | 65 | @Exported public String getIconPath() { 66 | return iconPath; 67 | } 68 | 69 | @Exported public String getText() { 70 | return text; 71 | } 72 | 73 | @Exported public String getColor() { 74 | return color; 75 | } 76 | 77 | @Exported public String getBackground() { 78 | return background; 79 | } 80 | 81 | @Exported public String getBorder() { 82 | return border; 83 | } 84 | 85 | @Exported public String getBorderColor() { 86 | return borderColor; 87 | } 88 | 89 | @Exported public String getLink() { 90 | return link; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/PhabricatorPostbuildSummaryAction.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator; 22 | 23 | import hudson.model.Action; 24 | import org.kohsuke.stapler.export.Exported; 25 | import org.kohsuke.stapler.export.ExportedBean; 26 | 27 | /** 28 | * Ripped from https://github.com/jenkinsci/groovy-postbuild-plugin/blob/master/src/main/java/org/jvnet/hudson/plugins/groovypostbuild/GroovyPostbuildSummaryAction.java 29 | */ 30 | @ExportedBean(defaultVisibility = 2) 31 | public class PhabricatorPostbuildSummaryAction implements Action { 32 | private final String iconPath; 33 | private final String url; 34 | private final String revisionID; 35 | private final String authorName; 36 | private final String authorEmail; 37 | private final String commitMessage; 38 | 39 | public PhabricatorPostbuildSummaryAction(String iconPath, String phabricatorLink, String revisionID, 40 | String authorName, String authorEmail, String commitMessage) { 41 | this.iconPath = iconPath; 42 | this.url = phabricatorLink; 43 | this.revisionID = revisionID; 44 | this.authorName = authorName; 45 | this.authorEmail = authorEmail; 46 | this.commitMessage = commitMessage; 47 | } 48 | 49 | /* Action methods */ 50 | public String getUrlName() { 51 | return ""; 52 | } 53 | 54 | public String getDisplayName() { 55 | return ""; 56 | } 57 | 58 | public String getIconFileName() { 59 | return null; 60 | } 61 | 62 | @Exported public String getIconPath() { 63 | return PhabricatorPlugin.getIconPath(iconPath); 64 | } 65 | 66 | @Exported public String getUrl() { 67 | return url; 68 | } 69 | 70 | @Exported public String getRevisionID() { 71 | return revisionID; 72 | } 73 | 74 | @Exported public String getAuthorName() { 75 | return authorName; 76 | } 77 | 78 | @Exported public String getAuthorEmail() { 79 | return authorEmail; 80 | } 81 | 82 | @Exported public String getCommitMessage() { 83 | return commitMessage; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/RemoteFileFetcher.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator; 22 | 23 | import com.uber.jenkins.phabricator.utils.CommonUtils; 24 | import com.uber.jenkins.phabricator.utils.Logger; 25 | import hudson.FilePath; 26 | 27 | import java.io.IOException; 28 | 29 | import static java.lang.Integer.parseInt; 30 | 31 | public class RemoteFileFetcher { 32 | private static final int DEFAULT_MAX_SIZE = 1000; 33 | private static final String LOGGER_TAG = "file-fetcher"; 34 | 35 | private final FilePath workspace; 36 | private final Logger logger; 37 | private final String fileName; 38 | private final String maxSize; 39 | 40 | public RemoteFileFetcher(FilePath workspace, Logger logger, String fileName, String maxSize) { 41 | this.workspace = workspace; 42 | this.logger = logger; 43 | this.fileName = fileName; 44 | this.maxSize = maxSize; 45 | } 46 | 47 | /** 48 | * Attempt to read a remote file 49 | * @return the content of the remote comment file, if present 50 | * @throws InterruptedException if there is an error fetching the file 51 | * @throws IOException if any network error occurs 52 | */ 53 | public String getRemoteFile() throws InterruptedException, IOException { 54 | if (CommonUtils.isBlank(fileName)) { 55 | logger.info(LOGGER_TAG, "no file configured"); 56 | return null; 57 | } 58 | 59 | FilePath[] src = workspace.list(fileName); 60 | if (src.length == 0) { 61 | logger.info(LOGGER_TAG, "no files found by path: '" + fileName + "'"); 62 | return null; 63 | } 64 | if (src.length > 1) { 65 | logger.info(LOGGER_TAG, "Found multiple matches. Reading first only."); 66 | } 67 | 68 | FilePath source = src[0]; 69 | 70 | int maxLength = DEFAULT_MAX_SIZE; 71 | if (!CommonUtils.isBlank(maxSize)) { 72 | maxLength = parseInt(maxSize, 10); 73 | } 74 | if (source.length() < maxLength) { 75 | maxLength = (int)source.length(); 76 | } 77 | byte[] buffer = new byte[maxLength]; 78 | source.read().read(buffer, 0, maxLength); 79 | 80 | return new String(buffer); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/conduit/ArcanistClient.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.conduit; 22 | 23 | import com.uber.jenkins.phabricator.utils.CommonUtils; 24 | import hudson.Launcher; 25 | import hudson.util.ArgumentListBuilder; 26 | 27 | import java.io.IOException; 28 | import java.io.PrintStream; 29 | 30 | public class ArcanistClient { 31 | private final String arcPath; 32 | private final String methodName; 33 | private final String conduitToken; 34 | private final String[] arguments; 35 | 36 | public ArcanistClient(String arcPath, String methodName, String conduitToken, String... arguments) { 37 | this.arcPath = arcPath; 38 | this.methodName = methodName; 39 | this.conduitToken = conduitToken; 40 | this.arguments = arguments; 41 | } 42 | 43 | private ArgumentListBuilder getConduitCommand() { 44 | ArgumentListBuilder builder = new ArgumentListBuilder(this.arcPath, this.methodName); 45 | builder.add(arguments); 46 | 47 | if (!CommonUtils.isBlank(this.conduitToken)) { 48 | builder.addMasked("--conduit-token=" + this.conduitToken); 49 | } 50 | return builder; 51 | } 52 | 53 | private Launcher.ProcStarter getCommand(Launcher.ProcStarter starter) throws IOException { 54 | return starter.cmds(this.getConduitCommand()); 55 | } 56 | 57 | public int callConduit(Launcher.ProcStarter starter, PrintStream stderr) throws IOException, InterruptedException { 58 | Launcher.ProcStarter command = this.getCommand(starter); 59 | return command.stdout(stderr).stderr(stderr).join(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/conduit/ArcanistUsageException.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.conduit; 22 | 23 | class ArcanistUsageException extends Exception { 24 | public ArcanistUsageException(String message) { 25 | super(message); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/conduit/ConduitAPIClient.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.conduit; 22 | 23 | import net.sf.json.JSONObject; 24 | import net.sf.json.groovy.JsonSlurper; 25 | import org.apache.commons.httpclient.HttpStatus; 26 | import org.apache.http.HttpResponse; 27 | import org.apache.http.NameValuePair; 28 | import org.apache.http.client.ClientProtocolException; 29 | import org.apache.http.client.entity.UrlEncodedFormEntity; 30 | import org.apache.http.client.methods.HttpPost; 31 | import org.apache.http.client.methods.HttpUriRequest; 32 | import org.apache.http.impl.client.CloseableHttpClient; 33 | import org.apache.http.impl.client.HttpClientBuilder; 34 | import org.apache.http.message.BasicNameValuePair; 35 | 36 | import java.io.IOException; 37 | import java.io.InputStream; 38 | import java.io.UnsupportedEncodingException; 39 | import java.net.MalformedURLException; 40 | import java.net.URISyntaxException; 41 | import java.net.URL; 42 | import java.util.ArrayList; 43 | import java.util.List; 44 | 45 | public class ConduitAPIClient { 46 | private static final String API_TOKEN_KEY = "token"; 47 | private static final String CONDUIT_METADATA_KEY = "__conduit__"; 48 | 49 | private final String conduitURL; 50 | private final String conduitToken; 51 | 52 | public ConduitAPIClient(String conduitURL, String conduitToken) { 53 | this.conduitURL = conduitURL; 54 | this.conduitToken = conduitToken; 55 | } 56 | 57 | /** 58 | * Call the conduit API of Phabricator 59 | * @param action Name of the API call 60 | * @param params The data to send to Harbormaster 61 | * @return The result as a JSONObject 62 | * @throws IOException If there was a problem reading the response 63 | * @throws ConduitAPIException If there was an error calling conduit 64 | */ 65 | public JSONObject perform(String action, JSONObject params) throws IOException, ConduitAPIException { 66 | CloseableHttpClient client = HttpClientBuilder.create().build(); 67 | HttpUriRequest request = createRequest(action, params); 68 | 69 | HttpResponse response; 70 | try { 71 | response = client.execute(request); 72 | } catch (ClientProtocolException e) { 73 | throw new ConduitAPIException(e.getMessage()); 74 | } 75 | 76 | InputStream responseBody = response.getEntity().getContent(); 77 | 78 | if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { 79 | throw new ConduitAPIException(responseBody.toString(), response.getStatusLine().getStatusCode()); 80 | } 81 | 82 | JsonSlurper jsonParser = new JsonSlurper(); 83 | return (JSONObject)jsonParser.parse(responseBody); 84 | } 85 | 86 | /** 87 | * Post a URL-encoded "params" key with a JSON-encoded body as per the Conduit API 88 | * @param action The name of the Conduit method 89 | * @param params The data to be sent to the Conduit method 90 | * @return The request to perform 91 | * @throws UnsupportedEncodingException when the POST data can't be encoded 92 | * @throws ConduitAPIException when the conduit URL is misconfigured 93 | */ 94 | public HttpUriRequest createRequest(String action, JSONObject params) throws UnsupportedEncodingException, ConduitAPIException { 95 | HttpPost post; 96 | try { 97 | post = new HttpPost( 98 | new URL(new URL(new URL(conduitURL), "/api/"), action).toURI() 99 | ); 100 | } catch (MalformedURLException e) { 101 | throw new ConduitAPIException(e.getMessage()); 102 | } catch (URISyntaxException e) { 103 | throw new ConduitAPIException(e.getMessage()); 104 | } 105 | 106 | JSONObject conduitParams = new JSONObject(); 107 | conduitParams.put(API_TOKEN_KEY, conduitToken); 108 | params.put(CONDUIT_METADATA_KEY, conduitParams); 109 | 110 | List formData = new ArrayList(); 111 | formData.add(new BasicNameValuePair("params", params.toString())); 112 | 113 | UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formData, "UTF-8"); 114 | post.setEntity(entity); 115 | 116 | return post; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/conduit/ConduitAPIException.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.conduit; 22 | 23 | public class ConduitAPIException extends Exception { 24 | public final int code; 25 | 26 | public ConduitAPIException(String message) { 27 | super(message); 28 | this.code = 0; 29 | } 30 | 31 | public ConduitAPIException(String message, int code) { 32 | super(message); 33 | this.code = code; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/conduit/HarbormasterClient.java: -------------------------------------------------------------------------------- 1 | package com.uber.jenkins.phabricator.conduit; 2 | 3 | import com.uber.jenkins.phabricator.lint.LintResults; 4 | import com.uber.jenkins.phabricator.unit.UnitResults; 5 | import net.sf.json.JSONObject; 6 | 7 | import java.io.IOException; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | public class HarbormasterClient { 13 | private final ConduitAPIClient conduit; 14 | 15 | public HarbormasterClient(ConduitAPIClient conduit) { 16 | this.conduit = conduit; 17 | } 18 | 19 | /** 20 | * Sets a sendHarbormasterMessage build status 21 | * @param phid Phabricator object ID 22 | * @param pass whether or not the build passed 23 | * @param unitResults the results from the unit tests 24 | * @param coverage the results from the coverage provider 25 | * @param lintResults 26 | * @return the Conduit API response 27 | * @throws IOException if there is a network error talking to Conduit 28 | * @throws ConduitAPIException if any error is experienced talking to Conduit 29 | */ 30 | public JSONObject sendHarbormasterMessage(String phid, boolean pass, UnitResults unitResults, Map coverage, LintResults lintResults) throws ConduitAPIException, IOException { 31 | 32 | List unit = new ArrayList(); 33 | 34 | if (unitResults != null) { 35 | unit.addAll(unitResults.toHarbormaster()); 36 | } 37 | 38 | List lint = new ArrayList(); 39 | 40 | if (lintResults != null) { 41 | lint.addAll(lintResults.toHarbormaster()); 42 | } 43 | 44 | if (coverage != null) { 45 | JSONObject coverageUnit = new JSONObject() 46 | .element("result", "pass") 47 | .element("name", "Coverage Data") 48 | .element("coverage", coverage); 49 | unit.add(coverageUnit); 50 | } 51 | 52 | JSONObject params = new JSONObject(); 53 | params.element("type", pass ? "pass" : "fail") 54 | .element("buildTargetPHID", phid); 55 | 56 | if (!unit.isEmpty()) { 57 | params.element("unit", unit); 58 | } 59 | 60 | if (!lint.isEmpty()) { 61 | params.element("lint", lint); 62 | } 63 | 64 | return conduit.perform("harbormaster.sendmessage", params); 65 | } 66 | 67 | /** 68 | * Uploads a uri as an 'artifact' for Harbormaster to display 69 | * @param phid Phabricator object ID 70 | * @param buildUri Uri to display, presumably the jenkins builds 71 | * @return the Conduit API response 72 | * @throws IOException if there is a network error talking to Conduit 73 | * @throws ConduitAPIException if any error is experienced talking to Conduit 74 | */ 75 | public JSONObject sendHarbormasterUri(String phid, String buildUri) throws ConduitAPIException, IOException { 76 | JSONObject artifactData = new JSONObject(); 77 | artifactData = artifactData.element("uri", buildUri) 78 | .element("name", "Jenkins") 79 | .element("ui.external", true); 80 | 81 | JSONObject params = new JSONObject(); 82 | params.element("buildTargetPHID", phid) 83 | .element("artifactKey", "jenkins.uri") 84 | .element("artifactType", "uri") 85 | .element("artifactData", artifactData); 86 | 87 | return conduit.perform("harbormaster.createartifact", params); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/coverage/CodeCoverageMetrics.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.coverage; 22 | 23 | public class CodeCoverageMetrics { 24 | private float packagesCoveragePercent = -1; 25 | private float filesCoveragePercent = -1; 26 | private float classesCoveragePercent = -1; 27 | private float methodCoveragePercent = -1; 28 | private float lineCoveragePercent = -1; 29 | private float conditionalCoveragePercent = -1; 30 | 31 | public CodeCoverageMetrics(float packagesCoveragePercent, float filesCoveragePercent, 32 | float classesCoveragePercent, float methodCoveragePercent, float lineCoveragePercent, 33 | float conditionalCoveragePercent) { 34 | this.packagesCoveragePercent = packagesCoveragePercent; 35 | this.filesCoveragePercent = filesCoveragePercent; 36 | this.classesCoveragePercent = classesCoveragePercent; 37 | this.methodCoveragePercent = methodCoveragePercent; 38 | this.lineCoveragePercent = lineCoveragePercent; 39 | this.conditionalCoveragePercent = conditionalCoveragePercent; 40 | } 41 | 42 | public boolean isValid() { 43 | return lineCoveragePercent != -1; 44 | } 45 | 46 | public float getPackageCoveragePercent() { 47 | return packagesCoveragePercent; 48 | } 49 | 50 | public float getFilesCoveragePercent() { 51 | return filesCoveragePercent; 52 | } 53 | 54 | public float getClassesCoveragePercent() { 55 | return classesCoveragePercent; 56 | } 57 | 58 | public float getMethodCoveragePercent() { 59 | return methodCoveragePercent; 60 | } 61 | 62 | public float getLineCoveragePercent() { 63 | return lineCoveragePercent; 64 | } 65 | 66 | public float getConditionalCoveragePercent() { 67 | return conditionalCoveragePercent; 68 | } 69 | 70 | public String toString() { 71 | StringBuilder sb = new StringBuilder(); 72 | sb.append("package coverage = "); 73 | sb.append(packagesCoveragePercent); 74 | sb.append(", files coverage = "); 75 | sb.append(filesCoveragePercent); 76 | sb.append(", classes coverage = "); 77 | sb.append(classesCoveragePercent); 78 | sb.append(", method coverage = "); 79 | sb.append(methodCoveragePercent); 80 | sb.append(", line coverage = "); 81 | sb.append(lineCoveragePercent); 82 | sb.append(", conditional coverage = "); 83 | sb.append(conditionalCoveragePercent); 84 | return sb.toString(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/coverage/CoverageConverter.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.coverage; 22 | 23 | import java.util.HashMap; 24 | import java.util.List; 25 | import java.util.Map; 26 | 27 | /** 28 | * Convert {filename: int[] hitCount} data into the Harbormaster format 29 | * 30 | * This is a string, where each character represents a line. The code is as follows: 31 | * 32 | * 'N': not executable 33 | * 'C': covered 34 | * 'U': uncovered 35 | * 36 | * For example a hit count of {null, 2, 0, 1} we would get "NCUC" 37 | */ 38 | public class CoverageConverter { 39 | /** 40 | * Convert line coverage to the Harbormaster coverage format 41 | * @return The Harbormaster-formatted coverage 42 | */ 43 | public Map convert(Map> lineCoverage) { 44 | Map results = new HashMap(); 45 | for (Map.Entry> entry : lineCoverage.entrySet()) { 46 | results.put(entry.getKey(), convertFileCoverage(entry.getValue())); 47 | } 48 | 49 | return results; 50 | } 51 | 52 | private String convertFileCoverage(List lineCoverage) { 53 | StringBuilder sb = new StringBuilder(); 54 | for (Integer line : lineCoverage) { 55 | // Can't use a case statement because NULL 56 | if (line == null) { 57 | sb.append('N'); 58 | } else if (line == 0) { 59 | sb.append('U'); 60 | } else { 61 | sb.append('C'); 62 | } 63 | } 64 | return sb.toString(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/coverage/CoverageProvider.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.coverage; 22 | 23 | import hudson.model.AbstractBuild; 24 | 25 | import java.util.List; 26 | import java.util.Map; 27 | 28 | public abstract class CoverageProvider { 29 | private AbstractBuild build; 30 | 31 | /** 32 | * Set the owning build for this provider 33 | * @param build The build that is associated with the current run 34 | */ 35 | public void setBuild(AbstractBuild build) { 36 | this.build = build; 37 | } 38 | 39 | protected AbstractBuild getBuild() { 40 | return build; 41 | } 42 | 43 | public abstract Map> readLineCoverage(); 44 | 45 | public abstract boolean hasCoverage(); 46 | 47 | /** 48 | * Get the coverage metrics for the provider 49 | * @return The metrics, if any are available 50 | */ 51 | public CodeCoverageMetrics getMetrics() { 52 | if (!hasCoverage()) { 53 | return null; 54 | } 55 | return getCoverageMetrics(); 56 | } 57 | 58 | protected abstract CodeCoverageMetrics getCoverageMetrics(); 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/coverage/PathResolver.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Uber 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.coverage; 22 | 23 | import hudson.FilePath; 24 | 25 | import java.io.IOException; 26 | import java.util.List; 27 | 28 | public class PathResolver { 29 | private final FilePath root; 30 | private final List candidates; 31 | 32 | public PathResolver(FilePath root, List candidates) { 33 | this.root = root; 34 | this.candidates = candidates; 35 | } 36 | 37 | /** 38 | * Using the workspace's root FilePath and a file that is presumed to exist on the node running the tests, 39 | * recurse over the `sources` provided by Cobertura and look for a combination where the file exists. 40 | * 41 | * This is a heuristic, and not perfect, to overcome changes to Python's coverage.py module which introduced 42 | * additional `source` directories in version 4.0.3 43 | */ 44 | public String choose(String filename) { 45 | for (String sourceDir : candidates) { 46 | FilePath candidate = new FilePath(root, sourceDir); 47 | candidate = new FilePath(candidate, filename); 48 | try { 49 | if (candidate.exists()) { 50 | return sourceDir; 51 | } 52 | } catch (IOException e) { 53 | e.printStackTrace(); 54 | } catch (InterruptedException e) { 55 | e.printStackTrace(); 56 | } 57 | } 58 | return null; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/credentials/ConduitCredentials.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.credentials; 22 | 23 | import com.cloudbees.plugins.credentials.Credentials; 24 | import hudson.util.Secret; 25 | 26 | public interface ConduitCredentials extends Credentials { 27 | 28 | Secret getToken(); 29 | 30 | String getGateway(); 31 | 32 | String getUrl(); 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/credentials/ConduitCredentialsImpl.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.credentials; 22 | 23 | import com.cloudbees.plugins.credentials.CredentialsDescriptor; 24 | import com.cloudbees.plugins.credentials.NameWith; 25 | import com.cloudbees.plugins.credentials.impl.BaseStandardCredentials; 26 | import com.uber.jenkins.phabricator.utils.CommonUtils; 27 | import edu.umd.cs.findbugs.annotations.CheckForNull; 28 | import edu.umd.cs.findbugs.annotations.NonNull; 29 | import edu.umd.cs.findbugs.annotations.Nullable; 30 | import hudson.Extension; 31 | import hudson.util.Secret; 32 | import org.kohsuke.stapler.DataBoundConstructor; 33 | 34 | @NameWith(value = ConduitCredentialsNameProvider.class, priority = 50) 35 | @SuppressWarnings("unused") 36 | public class ConduitCredentialsImpl extends BaseStandardCredentials implements ConduitCredentials { 37 | @NonNull 38 | private final Secret token; 39 | 40 | @Nullable 41 | private final String gateway; 42 | 43 | @NonNull 44 | private final String url; 45 | 46 | @DataBoundConstructor 47 | public ConduitCredentialsImpl(@CheckForNull String id, 48 | @NonNull @CheckForNull String url, 49 | @Nullable String gateway, 50 | @CheckForNull String description, 51 | @CheckForNull String token) { 52 | super(id, description); 53 | this.url = url; 54 | this.gateway = gateway; 55 | this.token = Secret.fromString(token); 56 | } 57 | 58 | @NonNull 59 | public String getUrl() { 60 | return url; 61 | } 62 | 63 | @Nullable 64 | public String getGateway() { 65 | return !CommonUtils.isBlank(gateway) ? gateway : getUrl(); 66 | } 67 | 68 | @NonNull 69 | public Secret getToken() { 70 | return token; 71 | } 72 | 73 | @Extension 74 | @SuppressWarnings("unused") 75 | public static class Descriptor extends CredentialsDescriptor { 76 | /** {@inheritDoc} */ 77 | @Override 78 | public String getDisplayName() { 79 | return "Phabricator Conduit Key"; 80 | } 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/credentials/ConduitCredentialsNameProvider.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.credentials; 22 | 23 | import com.cloudbees.plugins.credentials.CredentialsNameProvider; 24 | import edu.umd.cs.findbugs.annotations.NonNull; 25 | 26 | public class ConduitCredentialsNameProvider extends CredentialsNameProvider { 27 | @NonNull 28 | @Override 29 | public String getName(@NonNull ConduitCredentialsImpl credentials) { 30 | return credentials.getUrl(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/lint/LintResult.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Uber 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | package com.uber.jenkins.phabricator.lint; 24 | 25 | import net.sf.json.JSONObject; 26 | 27 | /** 28 | * This currently mirrors the API format of Harbormaster lint messages 29 | * 30 | * Reference: https://secure.phabricator.com/conduit/method/harbormaster.sendmessage/ 31 | * 32 | * name string Short message name, like "Syntax Error". 33 | * code string Lint message code identifying the type of message, like "ERR123". 34 | * severity string Severity of the message. 35 | * path string Path to the file containing the lint message, from the project root. 36 | * line optional int Line number in the file where the text which triggered the message first appears. The first line of the file is line 1, not line 0. 37 | * char optional int Byte position on the line where the text which triggered the message starts. The first byte on the line is byte 1, not byte 0. This position is byte-based (not character-based) because not all lintable files have a valid character encoding. 38 | * description optional string Long explanation of the lint message. 39 | */ 40 | public class LintResult { 41 | final String name; 42 | final String code; 43 | final String severity; 44 | final String path; 45 | final int line; 46 | final int charPosition; // NOTE "char" parameter in JSON 47 | final String description; 48 | 49 | public LintResult(String name, String code, String severity, String path, int line, int charPosition, String description) { 50 | this.name = name; 51 | this.code = code; 52 | this.severity = severity; 53 | this.path = path; 54 | this.line = line; 55 | this.charPosition = charPosition; 56 | this.description = description; 57 | } 58 | 59 | /** 60 | * Create a Harbormaster-API-compatible representation of the lint result 61 | * @return A JSON representation of the lint result 62 | */ 63 | public JSONObject toHarbormaster() { 64 | return new JSONObject() 65 | .element("name", name) 66 | .element("code", code) 67 | .element("severity", severity) 68 | .element("path", path) 69 | .element("line", line) 70 | .element("char", charPosition) 71 | .element("description", description); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/lint/LintResults.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Uber 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | package com.uber.jenkins.phabricator.lint; 24 | 25 | import net.sf.json.JSONObject; 26 | 27 | import java.util.ArrayList; 28 | import java.util.List; 29 | 30 | /** 31 | * Represent a list of lint results 32 | */ 33 | public class LintResults { 34 | private final List results; 35 | 36 | public LintResults() { 37 | this.results = new ArrayList(); 38 | } 39 | 40 | public void add(LintResult result) { 41 | results.add(result); 42 | } 43 | 44 | public List getResults() { 45 | return results; 46 | } 47 | 48 | /** 49 | * Convert a suite of unit results to Harbormaster JSON format 50 | * @return Harbormaster-formatted unit results 51 | */ 52 | public List toHarbormaster() { 53 | List harbormasterData = new ArrayList(); 54 | 55 | for (LintResult result : results) { 56 | harbormasterData.add(result.toHarbormaster()); 57 | } 58 | 59 | return harbormasterData; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/provider/BaseProvider.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.provider; 22 | 23 | import com.uber.jenkins.phabricator.utils.Logger; 24 | import jenkins.model.Jenkins; 25 | 26 | public class BaseProvider extends Provider { 27 | private final Jenkins jenkins; 28 | 29 | public BaseProvider(Jenkins jenkins, String pluginName, Logger logger) { 30 | super(pluginName, logger); 31 | this.jenkins = jenkins; 32 | } 33 | 34 | /** 35 | * {@inheritDoc} 36 | */ 37 | @Override 38 | public boolean isAvailable() { 39 | return jenkins.getPlugin(pluginName) != null; 40 | } 41 | 42 | /** 43 | * {@inheritDoc} 44 | */ 45 | @Override 46 | public T getInstance(final String className) { 47 | try { 48 | return (T) getClass().getClassLoader().loadClass(className).newInstance(); 49 | } catch (ClassNotFoundException e) { 50 | e.printStackTrace(logger.getStream()); 51 | } catch (InstantiationException e) { 52 | e.printStackTrace(logger.getStream()); 53 | } catch (IllegalAccessException e) { 54 | e.printStackTrace(logger.getStream()); 55 | } 56 | return null; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/provider/InstanceProvider.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.provider; 22 | 23 | import com.uber.jenkins.phabricator.utils.Logger; 24 | import jenkins.model.Jenkins; 25 | 26 | public class InstanceProvider { 27 | private static final String LOGGER_TAG = "plugin-provider"; 28 | private final Provider provider; 29 | private final String className; 30 | private final Logger logger; 31 | private final String pluginName; 32 | 33 | /** 34 | * Encapsulate lazilly loading a concrete implementation when a plugin is available 35 | * @param jenkins the instance of Jenkins 36 | * @param pluginName the name of the plugin, e.g. "cobertura" or "junit" (maven name) 37 | * @param className the concrete class name (com.uber.phabricator...) 38 | * @param logger the logger to use 39 | */ 40 | public InstanceProvider(Jenkins jenkins, String pluginName, String className, Logger logger) { 41 | this.provider = new BaseProvider( 42 | jenkins, 43 | pluginName, 44 | logger 45 | ); 46 | this.pluginName = pluginName; 47 | this.className = className; 48 | this.logger = logger; 49 | } 50 | 51 | /** 52 | * Get an instance of the desired implementation, if available 53 | * @return the class desired 54 | */ 55 | public T getInstance() { 56 | if (!provider.isAvailable()) { 57 | logger.info(LOGGER_TAG, String.format("'%s' plugin not installed.", pluginName)); 58 | return null; 59 | } 60 | T instance = provider.getInstance(className); 61 | if (instance == null) { 62 | logger.warn(LOGGER_TAG, 63 | String.format("Unable to instantiate plugin provider for '%s'. This should not happen.", pluginName)); 64 | } 65 | return instance; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/provider/Provider.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.provider; 22 | 23 | import com.uber.jenkins.phabricator.utils.Logger; 24 | 25 | public abstract class Provider { 26 | protected final Logger logger; 27 | protected final String pluginName; 28 | 29 | public Provider(final String pluginName, final Logger logger) { 30 | this.pluginName = pluginName; 31 | this.logger = logger; 32 | } 33 | 34 | /** 35 | * Determine if the provider is available for the plugin 36 | * @return Whether the plugin is available 37 | */ 38 | public abstract boolean isAvailable(); 39 | 40 | /** 41 | * Instantiate a new instance of the class given the implementation class name 42 | * @param implementationName The fully-qualified name of the class 43 | * @return An instance of the class 44 | */ 45 | public abstract T getInstance(final String implementationName); 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/tasks/ApplyPatchTask.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.tasks; 22 | 23 | import com.uber.jenkins.phabricator.LauncherFactory; 24 | import com.uber.jenkins.phabricator.conduit.ArcanistClient; 25 | import com.uber.jenkins.phabricator.utils.Logger; 26 | 27 | import java.io.IOException; 28 | import java.io.PrintStream; 29 | import java.util.ArrayList; 30 | import java.util.Arrays; 31 | import java.util.List; 32 | 33 | public class ApplyPatchTask extends Task { 34 | private final LauncherFactory starter; 35 | private final String baseCommit; 36 | private final String diffID; 37 | private final PrintStream logStream; 38 | private final String conduitToken; 39 | private final String arcPath; 40 | private final boolean createCommit; 41 | private final String gitPath; 42 | private final boolean skipForcedClean; 43 | private final boolean createBranch; 44 | private final boolean patchWithForceFlag; 45 | 46 | public ApplyPatchTask(Logger logger, LauncherFactory starter, String baseCommit, 47 | String diffID, String conduitToken, String arcPath, 48 | String gitPath, boolean createCommit, boolean skipForcedClean, 49 | boolean createBranch, boolean patchWithForceFlag) { 50 | super(logger); 51 | this.starter = starter; 52 | this.baseCommit = baseCommit; 53 | this.diffID = diffID; 54 | this.conduitToken = conduitToken; 55 | this.arcPath = arcPath; 56 | this.gitPath = gitPath; 57 | this.createCommit = createCommit; 58 | this.skipForcedClean = skipForcedClean; 59 | this.createBranch = createBranch; 60 | this.patchWithForceFlag = patchWithForceFlag; 61 | 62 | this.logStream = logger.getStream(); 63 | } 64 | 65 | /** 66 | * {@inheritDoc} 67 | */ 68 | @Override 69 | protected String getTag() { 70 | return "arc-patch"; 71 | } 72 | 73 | /** 74 | * {@inheritDoc} 75 | */ 76 | @Override 77 | protected void setup() { 78 | // Do nothing 79 | } 80 | 81 | /** 82 | * {@inheritDoc} 83 | */ 84 | @Override 85 | protected void execute() { 86 | try { 87 | int exitCode = starter.launch() 88 | .cmds(Arrays.asList(gitPath, "reset", "--hard", baseCommit)) 89 | .stdout(logStream) 90 | .join(); 91 | 92 | if (exitCode != 0) { 93 | info("Got non-zero exit code resetting to base commit " + baseCommit + ": " + exitCode); 94 | } 95 | 96 | if (!skipForcedClean) { 97 | // Clean workspace, otherwise `arc patch` may fail 98 | starter.launch() 99 | .stdout(logStream) 100 | .cmds(Arrays.asList(gitPath, "clean", "-fd", "-f")) 101 | .join(); 102 | } 103 | 104 | // Update submodules recursively. 105 | starter.launch() 106 | .stdout(logStream) 107 | .cmds(Arrays.asList(gitPath, "submodule", "update", "--init", "--recursive")) 108 | .join(); 109 | 110 | List arcPatchParams = new ArrayList(Arrays.asList("--diff", diffID)); 111 | if (!createCommit) { 112 | arcPatchParams.add("--nocommit"); 113 | } 114 | 115 | if (!createBranch) { 116 | arcPatchParams.add("--nobranch"); 117 | } 118 | 119 | if (patchWithForceFlag) { 120 | arcPatchParams.add("--force"); 121 | } 122 | 123 | ArcanistClient arc = new ArcanistClient( 124 | arcPath, 125 | "patch", 126 | conduitToken, 127 | arcPatchParams.toArray(new String[arcPatchParams.size()])); 128 | 129 | exitCode = arc.callConduit(starter.launch(), logStream); 130 | this.result = exitCode == 0 ? Result.SUCCESS : Result.FAILURE; 131 | } catch (IOException e) { 132 | e.printStackTrace(logStream); 133 | this.result = Result.FAILURE; 134 | } catch (InterruptedException e) { 135 | e.printStackTrace(logStream); 136 | this.result = Result.FAILURE; 137 | } 138 | } 139 | 140 | /** 141 | * {@inheritDoc} 142 | */ 143 | @Override 144 | protected void tearDown() { 145 | // Do nothing 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/tasks/NonDifferentialBuildTask.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.tasks; 22 | 23 | import com.uber.jenkins.phabricator.coverage.CodeCoverageMetrics; 24 | import com.uber.jenkins.phabricator.uberalls.UberallsClient; 25 | import com.uber.jenkins.phabricator.utils.CommonUtils; 26 | import com.uber.jenkins.phabricator.utils.Logger; 27 | 28 | /** 29 | * Generic build task. 30 | */ 31 | public class NonDifferentialBuildTask extends Task { 32 | 33 | protected final UberallsClient uberallsClient; 34 | protected final CodeCoverageMetrics codeCoverageMetrics; 35 | protected final boolean uberallsEnabled; 36 | protected final String commitSha; 37 | 38 | /** 39 | * GenericBuildTask constructor. 40 | * @param logger The logger. 41 | * @param uberallsClient The uberalls client. 42 | * @param codeCoverageMetrics The coverage metrics. 43 | * @param uberallsEnabled Whether uberalls is enabled. 44 | * @param commitSha The commit sha. 45 | */ 46 | public NonDifferentialBuildTask(Logger logger, UberallsClient uberallsClient, 47 | CodeCoverageMetrics codeCoverageMetrics, boolean uberallsEnabled, 48 | String commitSha) { 49 | super(logger); 50 | this.uberallsClient = uberallsClient; 51 | this.codeCoverageMetrics = codeCoverageMetrics; 52 | this.uberallsEnabled = uberallsEnabled; 53 | this.commitSha = commitSha; 54 | } 55 | 56 | /** 57 | * {@inheritDoc} 58 | */ 59 | @Override 60 | protected String getTag() { 61 | return "non-differential"; 62 | } 63 | 64 | /** 65 | * {@inheritDoc} 66 | */ 67 | @Override 68 | protected void setup() { 69 | // Handle bad input. 70 | if (codeCoverageMetrics == null || !codeCoverageMetrics.isValid()) { 71 | info("Coverage result not found. Ignoring build."); 72 | result = Result.IGNORED; 73 | } else if (!uberallsEnabled || CommonUtils.isBlank(uberallsClient.getBaseURL())) { 74 | info("Uberalls not configured. Skipping build."); 75 | result = Result.SKIPPED; 76 | } 77 | } 78 | 79 | /** 80 | * {@inheritDoc} 81 | */ 82 | @Override 83 | protected void execute() { 84 | if (result == Result.UNKNOWN) { 85 | if (!CommonUtils.isBlank(commitSha)) { 86 | info(String.format("Sending coverage result for %s as %s", commitSha, 87 | codeCoverageMetrics.toString())); 88 | result = uberallsClient.recordCoverage(commitSha, codeCoverageMetrics) ? 89 | Result.SUCCESS : Result.FAILURE; 90 | } else { 91 | info("No line coverage found. Ignoring build."); 92 | result = Result.IGNORED; 93 | } 94 | } 95 | } 96 | 97 | /** 98 | * {@inheritDoc} 99 | */ 100 | @Override 101 | protected void tearDown() { 102 | // Do nothing. 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/tasks/NonDifferentialHarbormasterTask.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.tasks; 22 | 23 | import com.uber.jenkins.phabricator.conduit.ConduitAPIClient; 24 | import com.uber.jenkins.phabricator.conduit.ConduitAPIException; 25 | import com.uber.jenkins.phabricator.conduit.HarbormasterClient; 26 | import com.uber.jenkins.phabricator.utils.Logger; 27 | 28 | import java.io.IOException; 29 | 30 | public class NonDifferentialHarbormasterTask extends Task { 31 | private final String phid; 32 | private final ConduitAPIClient conduit; 33 | private final hudson.model.Result buildResult; 34 | private final String buildUrl; 35 | private final HarbormasterClient harbormaster; 36 | private final Logger logger; 37 | 38 | /** 39 | * Task constructor. 40 | * @param logger The logger where logs go to. 41 | * @param conduitClient 42 | * @param result 43 | * @param buildUrl 44 | */ 45 | public NonDifferentialHarbormasterTask(Logger logger, String phid, ConduitAPIClient conduitClient, hudson.model.Result result, String buildUrl) { 46 | super(logger); 47 | this.logger = logger; 48 | this.phid = phid; 49 | this.conduit = conduitClient; 50 | this.buildResult = result; 51 | this.buildUrl = buildUrl; 52 | 53 | this.harbormaster = new HarbormasterClient(conduit); 54 | } 55 | 56 | /** 57 | * {@inheritDoc} 58 | */ 59 | @Override 60 | protected String getTag() { 61 | return "non-differential-harbormaster"; 62 | } 63 | 64 | /** 65 | * {@inheritDoc} 66 | */ 67 | @Override 68 | protected void setup() { 69 | // Do nothing 70 | } 71 | 72 | /** 73 | * {@inheritDoc} 74 | */ 75 | @Override 76 | protected void execute() { 77 | final boolean pass = buildResult.isBetterOrEqualTo(hudson.model.Result.SUCCESS); 78 | info(String.format("Sending diffusion result as: %s", buildResult.toString())); 79 | 80 | try { 81 | harbormaster.sendHarbormasterUri(phid, buildUrl); 82 | // Only send pass/fail, since coverage and unit aren't viewable outside of differentials 83 | harbormaster.sendHarbormasterMessage(phid, pass, null, null, null); 84 | result = Result.SUCCESS; 85 | return; 86 | } catch (ConduitAPIException e) { 87 | e.printStackTrace(logger.getStream()); 88 | } catch (IOException e) { 89 | e.printStackTrace(logger.getStream()); 90 | } 91 | 92 | result = Result.FAILURE; 93 | } 94 | 95 | /** 96 | * {@inheritDoc} 97 | */ 98 | @Override 99 | protected void tearDown() { 100 | // Do nothing 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/tasks/PostCommentTask.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.tasks; 22 | 23 | import com.uber.jenkins.phabricator.conduit.ConduitAPIException; 24 | import com.uber.jenkins.phabricator.conduit.DifferentialClient; 25 | import com.uber.jenkins.phabricator.utils.Logger; 26 | import net.sf.json.JSONNull; 27 | import net.sf.json.JSONObject; 28 | 29 | import java.io.IOException; 30 | 31 | /** 32 | * Post comment task. 33 | */ 34 | public class PostCommentTask extends Task { 35 | 36 | private static final boolean SILENT = false; 37 | private static final String DEFAULT_COMMENT_ACTION = "none"; 38 | 39 | private final DifferentialClient differentialClient; 40 | private final String revisionID; 41 | private final String comment; 42 | private final String commentAction; 43 | 44 | /** 45 | * PostCommentTask constructor. 46 | * @param logger the logger 47 | * @param differentialClient the client for the differential 48 | * @param revisionID the revision identifier from harbormaster 49 | * @param comment the body of the comment 50 | * @param commentAction the name of the comment action 51 | */ 52 | public PostCommentTask(Logger logger, DifferentialClient differentialClient, 53 | String revisionID, String comment, String commentAction) { 54 | super(logger); 55 | 56 | this.differentialClient = differentialClient; 57 | this.revisionID = revisionID; 58 | this.comment = comment; 59 | this.commentAction = commentAction; 60 | } 61 | 62 | /** 63 | * {@inheritDoc} 64 | */ 65 | @Override 66 | protected String getTag() { 67 | return "post-comment"; 68 | } 69 | 70 | /** 71 | * {@inheritDoc} 72 | */ 73 | @Override 74 | protected void setup() { 75 | // Do nothing. 76 | } 77 | 78 | /** 79 | * {@inheritDoc} 80 | */ 81 | @Override 82 | protected void execute() { 83 | JSONObject postDifferentialCommentResult = postDifferentialComment(comment, SILENT, 84 | commentAction); 85 | if (postDifferentialCommentResult == null || 86 | !(postDifferentialCommentResult.get("error_info") instanceof JSONNull)) { 87 | if (postDifferentialCommentResult != null) { 88 | info(String.format("Got error %s with action %s", 89 | postDifferentialCommentResult.get("error_info"), commentAction)); 90 | } 91 | 92 | info("Re-trying with action 'none'"); 93 | postDifferentialComment(comment, SILENT, DEFAULT_COMMENT_ACTION); 94 | } 95 | } 96 | 97 | /** 98 | * {@inheritDoc} 99 | */ 100 | @Override 101 | protected void tearDown() { 102 | // Do nothing. 103 | } 104 | 105 | private JSONObject postDifferentialComment(String message, boolean silent, String action) { 106 | try { 107 | JSONObject postDifferentialCommentResult = differentialClient.postComment(revisionID, 108 | message, silent, action); 109 | result = Result.SUCCESS; 110 | return postDifferentialCommentResult; 111 | } catch (IOException e) { 112 | throw new RuntimeException(e); 113 | } catch (ConduitAPIException e) { 114 | info("unable to post comment"); 115 | } 116 | 117 | result = Result.FAILURE; 118 | return null; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/tasks/SendHarbormasterResultTask.java: -------------------------------------------------------------------------------- 1 | package com.uber.jenkins.phabricator.tasks; 2 | 3 | import com.uber.jenkins.phabricator.conduit.ConduitAPIException; 4 | import com.uber.jenkins.phabricator.conduit.DifferentialClient; 5 | import com.uber.jenkins.phabricator.lint.LintResults; 6 | import com.uber.jenkins.phabricator.unit.UnitResults; 7 | import com.uber.jenkins.phabricator.utils.Logger; 8 | import net.sf.json.JSONNull; 9 | import net.sf.json.JSONObject; 10 | 11 | import java.io.IOException; 12 | import java.util.Map; 13 | 14 | public class SendHarbormasterResultTask extends Task { 15 | 16 | private final DifferentialClient diffClient; 17 | private final String phid; 18 | private final boolean harbormasterSuccess; 19 | private UnitResults unitResults; 20 | private final Map coverage; 21 | private final LintResults lintResults; 22 | 23 | public SendHarbormasterResultTask(Logger logger, DifferentialClient diffClient, String phid, 24 | boolean harbormasterSuccess, UnitResults unitResults, 25 | Map harbormasterCoverage, 26 | LintResults lintResults) { 27 | super(logger); 28 | this.diffClient = diffClient; 29 | this.phid = phid; 30 | this.harbormasterSuccess = harbormasterSuccess; 31 | this.unitResults = unitResults; 32 | this.coverage = harbormasterCoverage; 33 | this.lintResults = lintResults; 34 | } 35 | 36 | /** 37 | * {@inheritDoc} 38 | */ 39 | @Override 40 | protected String getTag() { 41 | return "send-harbormaster-result"; 42 | } 43 | 44 | /** 45 | * {@inheritDoc} 46 | */ 47 | @Override 48 | protected void setup() { 49 | // Do nothing 50 | } 51 | 52 | /** 53 | * {@inheritDoc} 54 | */ 55 | @Override 56 | protected void execute() { 57 | try { 58 | if (!sendMessage(unitResults, coverage, lintResults)) { 59 | info("Error sending Harbormaster unit results, trying again without unit data (you may have an old Phabricator?)."); 60 | sendMessage(null, null, null); 61 | } 62 | } catch (ConduitAPIException e) { 63 | e.printStackTrace(); 64 | failTask(); 65 | } catch (IOException e) { 66 | e.printStackTrace(); 67 | failTask(); 68 | } 69 | } 70 | 71 | /** 72 | * Try to send a message to harbormaster 73 | * @param unitResults the unit testing results to send 74 | * @param coverage the coverage data to send 75 | * @return false if an error was encountered 76 | */ 77 | private boolean sendMessage(UnitResults unitResults, Map coverage, LintResults lintResults) throws IOException, ConduitAPIException { 78 | JSONObject result = diffClient.sendHarbormasterMessage(phid, harbormasterSuccess, unitResults, coverage, lintResults); 79 | 80 | if (result.containsKey("error_info") && !(result.get("error_info") instanceof JSONNull)) { 81 | info(String.format("Error from Harbormaster: %s", result.getString("error_info"))); 82 | failTask(); 83 | return false; 84 | } else { 85 | this.result = Result.SUCCESS; 86 | } 87 | return true; 88 | } 89 | 90 | private void failTask() { 91 | info("Unable to post to Harbormaster"); 92 | result = result.FAILURE; 93 | } 94 | 95 | /** 96 | * {@inheritDoc} 97 | */ 98 | @Override 99 | protected void tearDown() { 100 | // Do nothing 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/tasks/SendHarbormasterUriTask.java: -------------------------------------------------------------------------------- 1 | // Permission is hereby granted, free of charge, to any person obtaining a copy 2 | // of this software and associated documentation files (the "Software"), to deal 3 | // in the Software without restriction, including without limitation the rights 4 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 5 | // copies of the Software, and to permit persons to whom the Software is 6 | // furnished to do so, subject to the following conditions: 7 | // 8 | // The above copyright notice and this permission notice shall be included in 9 | // all copies or substantial portions of the Software. 10 | // 11 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 17 | // THE SOFTWARE. 18 | 19 | package com.uber.jenkins.phabricator.tasks; 20 | 21 | import com.uber.jenkins.phabricator.conduit.ConduitAPIException; 22 | import com.uber.jenkins.phabricator.conduit.DifferentialClient; 23 | import com.uber.jenkins.phabricator.utils.Logger; 24 | import net.sf.json.JSONNull; 25 | import net.sf.json.JSONObject; 26 | 27 | import java.io.IOException; 28 | 29 | public class SendHarbormasterUriTask extends Task { 30 | 31 | private final DifferentialClient diffClient; 32 | private final String phid; 33 | private final String buildUri; 34 | 35 | public SendHarbormasterUriTask(Logger logger, DifferentialClient diffClient, String phid, String buildUri) { 36 | super(logger); 37 | this.diffClient = diffClient; 38 | this.phid = phid; 39 | this.buildUri = buildUri; 40 | } 41 | 42 | @Override 43 | protected String getTag() { 44 | return "send-harbormaster-uri"; 45 | } 46 | 47 | @Override 48 | protected void setup() { 49 | // Do nothing 50 | } 51 | 52 | @Override 53 | protected void execute() { 54 | try { 55 | JSONObject result = diffClient.sendHarbormasterUri(phid, buildUri); 56 | if (result.containsKey("error_info") && !(result.get("error_info") instanceof JSONNull)) { 57 | info(String.format("Harbormaster declined URI artifact: %s", result.getString("error_info"))); 58 | this.result = Result.FAILURE; 59 | } else { 60 | this.result = Result.SUCCESS; 61 | } 62 | } catch (ConduitAPIException e) { 63 | e.printStackTrace(); 64 | this.result = Result.FAILURE; 65 | } catch (IOException e) { 66 | e.printStackTrace(); 67 | this.result = Result.FAILURE; 68 | } 69 | } 70 | 71 | @Override 72 | protected void tearDown() { 73 | // Do nothing 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/tasks/Task.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.tasks; 22 | 23 | import com.uber.jenkins.phabricator.utils.Logger; 24 | 25 | /** 26 | * Base task for all operations in the phabricator-jenkins plugin. 27 | */ 28 | public abstract class Task { 29 | 30 | /** 31 | * Task results. 32 | */ 33 | public enum Result { 34 | SUCCESS, 35 | FAILURE, 36 | IGNORED, // For incorrect input. 37 | SKIPPED, // For incorrect configuration. 38 | UNKNOWN 39 | } 40 | 41 | protected Result result = Result.UNKNOWN; 42 | private final Logger logger; 43 | 44 | /** 45 | * Task constructor. 46 | * @param logger The logger where logs go to. 47 | */ 48 | public Task(Logger logger) { 49 | this.logger = logger; 50 | } 51 | 52 | /** 53 | * Runs the task workflow. 54 | * @return the result of the task 55 | */ 56 | public Result run() { 57 | setup(); 58 | execute(); 59 | tearDown(); 60 | 61 | return result; 62 | } 63 | 64 | /** 65 | * Logs the message. 66 | * @param message The message to log. 67 | */ 68 | protected void info(String message) { 69 | logger.info(getTag(), message); 70 | } 71 | 72 | /** 73 | * Gets the task's tag. 74 | * @return A string representation of this task's tag. 75 | */ 76 | protected abstract String getTag(); 77 | 78 | /** 79 | * Sets up the environment before task execution. 80 | */ 81 | protected abstract void setup(); 82 | 83 | /** 84 | * Executes the task workflow. 85 | */ 86 | protected abstract void execute(); 87 | 88 | /** 89 | * Tears down after task execution. 90 | */ 91 | protected abstract void tearDown(); 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/unit/JUnitTestProvider.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.unit; 22 | 23 | import hudson.model.AbstractBuild; 24 | import hudson.tasks.junit.CaseResult; 25 | import hudson.tasks.junit.SuiteResult; 26 | import hudson.tasks.junit.TestResult; 27 | import hudson.tasks.junit.TestResultAction; 28 | 29 | /** 30 | * Provides jUnit test reports to report results on builds 31 | */ 32 | @SuppressWarnings("unused") 33 | public class JUnitTestProvider extends UnitTestProvider { 34 | /** 35 | * {@inheritDoc} 36 | */ 37 | @Override 38 | public boolean resultsAvailable() { 39 | return getJUnitResults() != null; 40 | } 41 | 42 | /** 43 | * {@inheritDoc} 44 | */ 45 | @Override 46 | public UnitResults getResults() { 47 | return convertJUnit(getJUnitResults()); 48 | } 49 | 50 | /** 51 | * Convert JUnit's TestResult representation into a generic UnitResults 52 | * @param jUnitResults The result of the JUnit run 53 | * @return The converted results 54 | */ 55 | public UnitResults convertJUnit(TestResult jUnitResults) { 56 | UnitResults results = new UnitResults(); 57 | if (jUnitResults == null) { 58 | return results; 59 | } 60 | for (SuiteResult sr : jUnitResults.getSuites()) { 61 | for (CaseResult cr : sr.getCases()) { 62 | UnitResult result = new UnitResult( 63 | cr.getClassName(), 64 | cr.getDisplayName(), 65 | cr.getErrorStackTrace(), 66 | cr.getDuration(), 67 | cr.getFailCount(), 68 | cr.getSkipCount(), 69 | cr.getPassCount() 70 | ); 71 | results.add(result); 72 | } 73 | } 74 | return results; 75 | } 76 | 77 | private TestResult getJUnitResults() { 78 | AbstractBuild build = getBuild(); 79 | 80 | TestResultAction jUnitAction = build.getAction(TestResultAction.class); 81 | if (jUnitAction == null) { 82 | return null; 83 | } 84 | return jUnitAction.getResult(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/unit/UnitResult.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.unit; 22 | 23 | import net.sf.json.JSONObject; 24 | 25 | public class UnitResult { 26 | private static final String FAILURE = "fail"; 27 | private static final String SKIP = "skip"; 28 | private static final String PASS = "pass"; 29 | private static final String UNSOUND = "unsound"; 30 | private static final String ENGINE_NAME = "Jenkins"; 31 | private final String className; 32 | private final String name; 33 | private final String stackTrace; 34 | private final float duration; 35 | private final int failCount; 36 | private final int skipCount; 37 | private final int passCount; 38 | 39 | public UnitResult(String className, String displayName, String stackTrace, float duration, int failCount, int skipCount, int passCount) { 40 | this.className = className; 41 | name = displayName; 42 | this.duration = duration; 43 | this.failCount = failCount; 44 | this.skipCount = skipCount; 45 | this.passCount = passCount; 46 | this.stackTrace = stackTrace; 47 | } 48 | 49 | public String getHarbormasterResult() { 50 | if (failCount > 0) { 51 | return FAILURE; 52 | } else if (skipCount > 0) { 53 | return SKIP; 54 | } else if (passCount > 0) { 55 | return PASS; 56 | } 57 | return UNSOUND; 58 | } 59 | 60 | public JSONObject toHarbormaster() { 61 | return new JSONObject() 62 | .element("name", name) 63 | .element("result", getHarbormasterResult()) 64 | .element("namespace", className) 65 | .element("details", stackTrace) 66 | .element("engine", ENGINE_NAME) 67 | .element("duration", duration); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/unit/UnitResults.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.unit; 22 | 23 | import net.sf.json.JSONObject; 24 | 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | /** 29 | * Represent a list of unit results 30 | */ 31 | public class UnitResults { 32 | private final List results; 33 | 34 | public UnitResults() { 35 | this.results = new ArrayList(); 36 | } 37 | 38 | public void add(UnitResult result) { 39 | results.add(result); 40 | } 41 | 42 | public List getResults() { 43 | return results; 44 | } 45 | 46 | /** 47 | * Convert a suite of unit results to Harbormaster JSON format 48 | * @return Harbormaster-formatted unit results 49 | */ 50 | public List toHarbormaster() { 51 | List harbormasterData = new ArrayList(); 52 | 53 | for (UnitResult result : results) { 54 | harbormasterData.add(result.toHarbormaster()); 55 | } 56 | 57 | return harbormasterData; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/unit/UnitTestProvider.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.unit; 22 | 23 | import hudson.model.AbstractBuild; 24 | 25 | /** 26 | * Provides an interface for plugins that have unit test results 27 | */ 28 | public abstract class UnitTestProvider { 29 | private AbstractBuild build; 30 | 31 | /** 32 | * Set the owning build for this provider 33 | * @param build The build that is associated with the current run 34 | */ 35 | public void setBuild(AbstractBuild build) { 36 | this.build = build; 37 | } 38 | 39 | protected AbstractBuild getBuild() { 40 | return build; 41 | } 42 | 43 | /** 44 | * Determine if the current provider has results available for the build 45 | * @return Whether results are available 46 | */ 47 | public abstract boolean resultsAvailable(); 48 | 49 | /** 50 | * Convert the provider's results to a standard format 51 | * @return The results of the unit tests 52 | */ 53 | public abstract UnitResults getResults(); 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/utils/CommonUtils.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.utils; 22 | 23 | public class CommonUtils { 24 | public static boolean isBlank(String str) { 25 | return str == null || str.trim().isEmpty(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/uber/jenkins/phabricator/utils/Logger.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.utils; 22 | 23 | import java.io.PrintStream; 24 | 25 | /** 26 | * Logger utility. 27 | */ 28 | public class Logger { 29 | private static final String LOG_FORMAT = "[phabricator:%s] %s"; 30 | 31 | private final PrintStream stream; 32 | 33 | /** 34 | * Logger constructor. 35 | * @param stream The stream. 36 | */ 37 | public Logger(PrintStream stream) { 38 | this.stream = stream; 39 | } 40 | 41 | /** 42 | * Gets the stream. 43 | * @return The stream where logs go to. 44 | */ 45 | public PrintStream getStream() { 46 | return stream; 47 | } 48 | 49 | /** 50 | * Logs the message to the stream. 51 | * @param tag The tag for the message. 52 | * @param message The message to log. 53 | */ 54 | public void info(String tag, String message) { 55 | stream.println(String.format(LOG_FORMAT, tag, message)); 56 | } 57 | 58 | /** 59 | * Logs the message to the stream as a warning. 60 | * @param tag The tag for the message. 61 | * @param message The message to log. 62 | */ 63 | public void warn(String tag, String message) { 64 | info(tag, message); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/resources/com/uber/jenkins/phabricator/PhabricatorBuildWrapper/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 9 | 10 | 11 | 13 | 14 | 15 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/main/resources/com/uber/jenkins/phabricator/PhabricatorBuildWrapper/global.jelly: -------------------------------------------------------------------------------- 1 | 2 | 6 | 18 | 19 | 20 | 22 | 23 | 24 | 25 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/main/resources/com/uber/jenkins/phabricator/PhabricatorNotifier/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 13 | 15 | 16 | 17 | 19 | 20 | 21 | 23 | 24 | 25 | 26 | 28 | 29 | 30 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/main/resources/com/uber/jenkins/phabricator/PhabricatorNotifier/global.jelly: -------------------------------------------------------------------------------- 1 | 2 | 6 | 18 | 19 | 20 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/main/resources/com/uber/jenkins/phabricator/PhabricatorNotifier/help-conduitURL.html: -------------------------------------------------------------------------------- 1 |

2 | This HTML fragment will be injected into the configuration screen 3 | when the user clicks the 'help' icon. See global.jelly for how the 4 | form decides which page to load. 5 | You can have any HTML fragment here. 6 |
7 | -------------------------------------------------------------------------------- /src/main/resources/com/uber/jenkins/phabricator/PhabricatorPostbuildAction/badge.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ${it.text} 5 | 6 | 7 | ${it.text} 8 | 9 | 10 | 11 | ${it.text} 12 | 13 | 14 | 15 | ${it.text} 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/main/resources/com/uber/jenkins/phabricator/PhabricatorPostbuildSummaryAction/summary.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | This was a build of ${it.revisionID} by ${it.authorName} 5 | 6 | 7 | (${it.authorEmail}) 8 | 9 | 10 | 11 |

12 |
${it.commitMessage}
13 |
14 |
15 |
16 | -------------------------------------------------------------------------------- /src/main/resources/com/uber/jenkins/phabricator/credentials/ConduitCredentialsImpl/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/main/resources/com/uber/jenkins/phabricator/credentials/ConduitCredentialsImpl/help-gateway.html: -------------------------------------------------------------------------------- 1 |
2 |

Gateway is an optional configuration that can be used to point where your Conduit APIs are routed. If this not not defined, the Conduit client defaults all API calls to the URL defined with the credentials instead.

3 |
-------------------------------------------------------------------------------- /src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 | This plugin integrates Phabricator and Harbormaster with Jenkins and Uberalls. 7 |
8 | -------------------------------------------------------------------------------- /src/main/webapp/images/phabricator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/phabricator-plugin/00e0e549f9456fef3ea9a737197a62265e8c336f/src/main/webapp/images/phabricator.png -------------------------------------------------------------------------------- /src/test/java/com/uber/jenkins/phabricator/FakeConduit.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator; 22 | 23 | import com.uber.jenkins.phabricator.utils.TestUtils; 24 | import net.sf.json.JSONObject; 25 | import org.apache.commons.httpclient.HttpStatus; 26 | import org.apache.http.localserver.LocalTestServer; 27 | 28 | import java.io.UnsupportedEncodingException; 29 | import java.util.ArrayList; 30 | import java.util.List; 31 | import java.util.Map; 32 | 33 | public class FakeConduit { 34 | private LocalTestServer server; 35 | private List requestBodies; 36 | 37 | public FakeConduit(Map responses) throws Exception { 38 | server = new LocalTestServer(null, null); 39 | this.requestBodies = new ArrayList(); 40 | for (Map.Entry entry : responses.entrySet()) { 41 | register(entry.getKey(), entry.getValue()); 42 | } 43 | server.start(); 44 | } 45 | 46 | public void stop() throws Exception { 47 | server.stop(); 48 | } 49 | 50 | public LocalTestServer getServer() { 51 | return server; 52 | } 53 | 54 | public List getRequestBodies() throws UnsupportedEncodingException { 55 | return requestBodies; 56 | } 57 | 58 | public String uri() { 59 | return TestUtils.getTestServerAddress(server); 60 | } 61 | 62 | public void register(String method, JSONObject response) { 63 | server.register( 64 | "/api/" + method, 65 | TestUtils.makeHttpHandler(HttpStatus.SC_OK, response.toString(2), requestBodies) 66 | ); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/test/java/com/uber/jenkins/phabricator/LauncherFactoryTest.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator; 22 | 23 | import com.uber.jenkins.phabricator.utils.TestUtils; 24 | import org.junit.Rule; 25 | import org.junit.Test; 26 | import org.jvnet.hudson.test.JenkinsRule; 27 | 28 | import java.io.ByteArrayOutputStream; 29 | import java.io.OutputStream; 30 | 31 | import static org.junit.Assert.assertEquals; 32 | 33 | public class LauncherFactoryTest { 34 | @Rule 35 | public JenkinsRule j = new JenkinsRule(); 36 | 37 | @Test 38 | public void testLauncherFactoryIsSane() throws Exception { 39 | LauncherFactory factory = TestUtils.createLauncherFactory(j); 40 | assertEquals(factory.getStderr(), System.err); 41 | 42 | OutputStream out = new ByteArrayOutputStream(); 43 | factory.launch().stdout(out).cmdAsSingleString("echo hello").join(); 44 | assertEquals(out.toString(), "hello\n"); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/com/uber/jenkins/phabricator/PhabricatorPostbuildActionTest.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator; 22 | 23 | import org.junit.Test; 24 | 25 | import static org.junit.Assert.*; 26 | 27 | public class PhabricatorPostbuildActionTest { 28 | private final PhabricatorPostbuildAction action = PhabricatorPostbuildAction.createShortText("text", "link"); 29 | 30 | @Test 31 | public void testGetUrlName() throws Exception { 32 | assertEquals("", action.getUrlName()); 33 | } 34 | 35 | @Test 36 | public void testGetDisplayName() throws Exception { 37 | assertEquals("", action.getDisplayName()); 38 | } 39 | 40 | @Test 41 | public void testGetIconFileName() throws Exception { 42 | assertNull(action.getIconFileName()); 43 | } 44 | 45 | @Test 46 | public void testIsTextOnly() throws Exception { 47 | assertTrue(action.isTextOnly()); 48 | } 49 | 50 | @Test 51 | public void testGetIconPath() throws Exception { 52 | assertNull(action.getIconPath()); 53 | } 54 | 55 | @Test 56 | public void testGetText() throws Exception { 57 | assertEquals("text", action.getText()); 58 | } 59 | 60 | @Test 61 | public void testGetColor() throws Exception { 62 | assertNotNull(action.getColor()); 63 | } 64 | 65 | @Test 66 | public void testGetBackground() throws Exception { 67 | assertNotNull(action.getBackground()); 68 | } 69 | 70 | @Test 71 | public void testGetBorder() throws Exception { 72 | assertEquals("0", action.getBorder()); 73 | } 74 | 75 | @Test 76 | public void testGetBorderColor() throws Exception { 77 | assertNotNull(action.getBorderColor()); 78 | } 79 | 80 | @Test 81 | public void testGetLink() throws Exception { 82 | assertEquals("link", action.getLink()); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/test/java/com/uber/jenkins/phabricator/RemoteFileFetcherTest.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator; 22 | 23 | import com.uber.jenkins.phabricator.utils.Logger; 24 | import com.uber.jenkins.phabricator.utils.TestUtils; 25 | import hudson.Launcher; 26 | import hudson.model.AbstractBuild; 27 | import hudson.model.BuildListener; 28 | import hudson.model.FreeStyleBuild; 29 | import hudson.model.FreeStyleProject; 30 | import hudson.tasks.Builder; 31 | import org.junit.Before; 32 | import org.junit.Rule; 33 | import org.junit.Test; 34 | import org.jvnet.hudson.test.JenkinsRule; 35 | import org.jvnet.hudson.test.TestBuilder; 36 | 37 | import java.io.IOException; 38 | import java.util.concurrent.ExecutionException; 39 | 40 | import static org.junit.Assert.assertEquals; 41 | import static org.junit.Assert.assertNull; 42 | 43 | public class RemoteFileFetcherTest { 44 | @Rule 45 | public JenkinsRule j = new JenkinsRule(); 46 | 47 | private final Logger logger = TestUtils.getDefaultLogger(); 48 | private FreeStyleProject project; 49 | 50 | @Before 51 | public void setUp() throws IOException { 52 | project = j.createFreeStyleProject(); 53 | } 54 | 55 | @Test 56 | public void testNoCommentConfigured() throws Exception { 57 | FreeStyleBuild build = getBuild(); 58 | RemoteFileFetcher fetcher = new RemoteFileFetcher( 59 | build.getWorkspace(), 60 | logger, 61 | "", 62 | "1000" 63 | ); 64 | 65 | assertNull(fetcher.getRemoteFile()); 66 | 67 | fetcher = new RemoteFileFetcher( 68 | build.getWorkspace(), 69 | logger, 70 | "non-existent", 71 | "1000" 72 | ); 73 | 74 | assertNull(fetcher.getRemoteFile()); 75 | } 76 | 77 | @Test 78 | public void testSingleFile() throws Exception { 79 | testWithContent("hello, world"); 80 | } 81 | 82 | @Test 83 | public void testUTF8File() throws Exception { 84 | testWithContent("こんにちは世界"); 85 | } 86 | 87 | private void testWithContent(String content) throws Exception { 88 | final String fileName = "just-a-test.txt"; 89 | project.getBuildersList().add(echoBuilder(fileName, content)); 90 | FreeStyleBuild build = getBuild(); 91 | 92 | RemoteFileFetcher fetcher = new RemoteFileFetcher( 93 | build.getWorkspace(), 94 | logger, 95 | fileName, 96 | "1000" 97 | ); 98 | 99 | assertEquals(content, fetcher.getRemoteFile()); 100 | 101 | fetcher = new RemoteFileFetcher( 102 | build.getWorkspace(), 103 | logger, 104 | "*.txt", 105 | "1000" 106 | ); 107 | 108 | assertEquals(content, fetcher.getRemoteFile()); 109 | } 110 | 111 | private Builder echoBuilder(final String fileName, final String content) { 112 | return new TestBuilder() { 113 | @Override 114 | public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { 115 | build.getWorkspace().child(fileName).write(content, "UTF-8"); 116 | return true; 117 | } 118 | }; 119 | } 120 | 121 | private FreeStyleBuild getBuild() throws ExecutionException, InterruptedException { 122 | return project.scheduleBuild2(0).get(); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/test/java/com/uber/jenkins/phabricator/conduit/ArcanistClientTest.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.conduit; 22 | 23 | import hudson.Launcher; 24 | import org.junit.Rule; 25 | import org.junit.Test; 26 | import org.jvnet.hudson.test.JenkinsRule; 27 | 28 | import static org.junit.Assert.assertEquals; 29 | 30 | public class ArcanistClientTest { 31 | @Rule 32 | public JenkinsRule j = new JenkinsRule(); 33 | 34 | @Test 35 | public void testEcho() throws Exception { 36 | ArcanistClient client = new ArcanistClient("echo", "hello", null); 37 | 38 | int result = client.callConduit(getLauncher().launch(), System.err); 39 | assertEquals(result, 0); 40 | } 41 | 42 | @Test 43 | public void testEchoWithToken() throws Exception { 44 | ArcanistClient client = new ArcanistClient("echo", "tokentest", "notarealtoken"); 45 | 46 | int result = client.callConduit(getLauncher().launch(), System.err); 47 | assertEquals(result, 0); 48 | } 49 | 50 | private Launcher getLauncher() { 51 | return j.createLocalLauncher(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/com/uber/jenkins/phabricator/conduit/ConduitAPIClientTest.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.conduit; 22 | 23 | import com.uber.jenkins.phabricator.utils.TestUtils; 24 | import net.sf.json.JSONObject; 25 | import org.apache.commons.httpclient.HttpStatus; 26 | import org.apache.http.localserver.LocalTestServer; 27 | import org.junit.After; 28 | import org.junit.Before; 29 | import org.junit.Test; 30 | 31 | import java.io.UnsupportedEncodingException; 32 | 33 | import static org.junit.Assert.assertEquals; 34 | 35 | public class ConduitAPIClientTest { 36 | private LocalTestServer server; 37 | private ConduitAPIClient client; 38 | private final JSONObject emptyParams = new JSONObject(); 39 | 40 | @Before 41 | public void setUp() throws Exception { 42 | server = new LocalTestServer(null, null); 43 | server.start(); 44 | } 45 | 46 | @After 47 | public void tearDown() throws Exception { 48 | server.stop(); 49 | } 50 | 51 | @Test(expected = ConduitAPIException.class) 52 | public void testInvalidURI() throws Exception { 53 | client = new ConduitAPIClient("gopher://foo", TestUtils.TEST_CONDUIT_TOKEN); 54 | client.perform("anything", emptyParams); 55 | } 56 | 57 | @Test 58 | public void testSuccessfullFetch() throws Exception { 59 | server.register("/api/valid", TestUtils.makeHttpHandler(HttpStatus.SC_OK, "{\"hello\": \"world\"}")); 60 | 61 | client = new ConduitAPIClient(getTestServerAddress(), TestUtils.TEST_CONDUIT_TOKEN); 62 | JSONObject response = client.perform("valid", emptyParams); 63 | assertEquals("world", response.getString("hello")); 64 | } 65 | 66 | @Test(expected = ConduitAPIException.class) 67 | public void testBadRequestErrorCode() throws Exception { 68 | server.register("/api/foo", TestUtils.makeHttpHandler(HttpStatus.SC_BAD_REQUEST, "nothing")); 69 | 70 | client = new ConduitAPIClient(getTestServerAddress(), TestUtils.TEST_CONDUIT_TOKEN); 71 | client.perform("foo", emptyParams); 72 | } 73 | 74 | @Test 75 | public void testWithParams() throws UnsupportedEncodingException, ConduitAPIException { 76 | client = new ConduitAPIClient("http://foo.bar", TestUtils.TEST_CONDUIT_TOKEN); 77 | JSONObject params = new JSONObject().element("hello", "world"); 78 | params.put("hello", "world"); 79 | client.createRequest("action", params); 80 | } 81 | 82 | @Test 83 | public void testWithUTF8() throws Exception { 84 | server.register("/api/utf8", TestUtils.makeHttpHandler(HttpStatus.SC_OK, "{}")); 85 | 86 | client = new ConduitAPIClient(getTestServerAddress(), TestUtils.TEST_CONDUIT_TOKEN); 87 | JSONObject utf8Params = new JSONObject().element("message", "こんにちは世界"); 88 | client.perform("utf8", utf8Params); 89 | } 90 | 91 | private String getTestServerAddress() { 92 | return TestUtils.getTestServerAddress(server); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/test/java/com/uber/jenkins/phabricator/conduit/DifferentialTest.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.conduit; 22 | 23 | import com.google.common.collect.Sets; 24 | import com.uber.jenkins.phabricator.PhabricatorPostbuildSummaryAction; 25 | import com.uber.jenkins.phabricator.utils.TestUtils; 26 | import hudson.EnvVars; 27 | import junit.framework.TestCase; 28 | import net.sf.json.JSONNull; 29 | import net.sf.json.JSONObject; 30 | import org.junit.Test; 31 | 32 | import java.io.IOException; 33 | 34 | public class DifferentialTest extends TestCase { 35 | private static final String FAKE_DIFF_ID = "not-a-real-id"; 36 | 37 | Differential differential; 38 | 39 | protected void setUp() throws IOException, ArcanistUsageException, InterruptedException { 40 | JSONObject response = TestUtils.getJSONFromFile(getClass(), "validDifferentialQueryResponse"); 41 | differential = new Differential(response); 42 | } 43 | 44 | @Test 45 | public void testFetchRevisionID() throws Exception { 46 | assertEquals(FAKE_DIFF_ID, differential.getRevisionID(false)); 47 | } 48 | 49 | @Test 50 | public void testGetPhabricatorLink() throws Exception { 51 | assertTrue(differential.getPhabricatorLink("http://example.com").contains(FAKE_DIFF_ID)); 52 | } 53 | 54 | @Test 55 | public void testGetPhabricatorLinkInvalidURL() throws Exception { 56 | // Try our best to join URLs, even when they are wrong 57 | assertTrue(differential.getPhabricatorLink("aoeu").contains("aoeu")); 58 | } 59 | 60 | @Test 61 | public void testGetBranch() { 62 | assertEquals("a-branch-name", differential.getBranch()); 63 | } 64 | 65 | @Test 66 | public void testGetBranchWithEmptyResponse() throws Exception { 67 | JSONObject empty = new JSONObject(); 68 | empty.put("branch", JSONNull.getInstance()); 69 | Differential diff = new Differential(empty); 70 | assertEquals("(none)", diff.getBranch()); 71 | } 72 | 73 | @Test 74 | public void testGetBranchWithInvalidResponse() throws Exception { 75 | JSONObject invalid = new JSONObject(); 76 | invalid.put("branch", true); 77 | Differential diff = new Differential(invalid); 78 | assertEquals("(unknown)", diff.getBranch()); 79 | } 80 | 81 | @Test 82 | public void testGetBaseCommit() throws Exception { 83 | assertEquals("aaaaaaaa", differential.getBaseCommit()); 84 | } 85 | 86 | @Test 87 | public void testGetSummaryMessage() throws Exception { 88 | PhabricatorPostbuildSummaryAction summary = differential.createSummary("http://example.com"); 89 | assertEquals("http://example.com/Dnot-a-real-id", summary.getUrl()); 90 | assertEquals("Dnot-a-real-id", summary.getRevisionID()); 91 | assertEquals("aiden", summary.getAuthorName()); 92 | assertEquals("ai@uber.com", summary.getAuthorEmail()); 93 | } 94 | 95 | @Test 96 | public void testGetMissingAuthorship() throws Exception { 97 | JSONObject response = TestUtils.getJSONFromFile(getClass(), "missingAuthorResponse"); 98 | differential = new Differential(response); 99 | PhabricatorPostbuildSummaryAction summary = differential.createSummary("http://example.com"); 100 | 101 | assertEquals("unknown", summary.getAuthorName()); 102 | assertEquals("unknown", summary.getAuthorEmail()); 103 | } 104 | 105 | @Test 106 | public void testFetchDiffResponseWithChanges() throws Exception { 107 | JSONObject response = TestUtils.getJSONFromFile(getClass(), "ResponseWithChanges"); 108 | differential = new Differential(response); 109 | 110 | assertEquals(Sets.newHashSet("file.go","file2.go"), differential.getChangedFiles()); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/test/java/com/uber/jenkins/phabricator/coverage/FakeCoverageProvider.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.coverage; 22 | 23 | import java.util.*; 24 | 25 | public class FakeCoverageProvider extends CoverageProvider { 26 | private final Map> coverage; 27 | 28 | public FakeCoverageProvider(Map> coverage) { 29 | this.coverage = coverage; 30 | } 31 | 32 | @Override 33 | public Map> readLineCoverage() { 34 | return coverage; 35 | } 36 | 37 | @Override 38 | public boolean hasCoverage() { 39 | return true; 40 | } 41 | 42 | @Override 43 | protected CodeCoverageMetrics getCoverageMetrics() { 44 | return null; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/com/uber/jenkins/phabricator/coverage/PathResolverTest.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Uber 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.coverage; 22 | 23 | import com.google.common.io.Files; 24 | import hudson.FilePath; 25 | import org.junit.After; 26 | import org.junit.Before; 27 | import org.junit.Test; 28 | import org.junit.runner.RunWith; 29 | import org.junit.runners.Parameterized; 30 | 31 | import java.io.File; 32 | import java.util.*; 33 | 34 | import static org.junit.Assert.*; 35 | 36 | @RunWith(Parameterized.class) 37 | public class PathResolverTest { 38 | @Parameterized.Parameter 39 | public List candidates; 40 | 41 | private Stack cleanupPaths; 42 | 43 | @Test 44 | public void testChoose() throws Exception { 45 | File tmpDir = Files.createTempDir(); 46 | cleanupPaths.push(tmpDir); 47 | List dirs = new ArrayList(); 48 | for (String path : candidates) { 49 | if (path.isEmpty()) { 50 | continue; 51 | } 52 | File file = new File(tmpDir, path); 53 | if (path.endsWith("/")) { 54 | file.mkdirs(); 55 | dirs.add(path); 56 | } else { 57 | file.createNewFile(); 58 | } 59 | cleanupPaths.push(file); 60 | } 61 | 62 | String chosen = new PathResolver(new FilePath(tmpDir), dirs).choose("dir/file"); 63 | 64 | if (candidates.isEmpty()) { 65 | assertNull(chosen); 66 | } else { 67 | assertEquals("workspace/", chosen); 68 | } 69 | } 70 | 71 | @Before 72 | public void setUp() { 73 | cleanupPaths = new Stack(); 74 | } 75 | 76 | @After 77 | public void tearDown() { 78 | for (File path : cleanupPaths) { 79 | path.delete(); 80 | } 81 | } 82 | 83 | @Parameterized.Parameters 84 | public static Collection> data() { 85 | return Arrays.asList( 86 | new ArrayList(), 87 | Arrays.asList("workspace/", "workspace/dir/", "workspace/dir/file"), 88 | Arrays.asList("workspace/", "workspace/dir/", "workspace/dir/dir/", "workspace/dir/file") 89 | ); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/test/java/com/uber/jenkins/phabricator/credentials/ConduitCredentialsImplTest.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 Uber 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.credentials; 22 | 23 | import com.uber.jenkins.phabricator.BuildIntegrationTest; 24 | import com.uber.jenkins.phabricator.utils.TestUtils; 25 | import org.junit.Test; 26 | 27 | import static org.junit.Assert.assertEquals; 28 | 29 | public class ConduitCredentialsImplTest extends BuildIntegrationTest { 30 | 31 | private static final String TEST_URL = "http://example.foobar"; 32 | private static final String TEST_GATEWAY = "http://example.weewar"; 33 | 34 | @Test 35 | public void gatewayNotDefined() { 36 | ConduitCredentials conduitCredentials = TestUtils.getConduitCredentials(TEST_URL, null); 37 | assertEquals(conduitCredentials.getUrl(), conduitCredentials.getGateway()); 38 | } 39 | 40 | @Test 41 | public void gatewayDefinedDifferentValues() { 42 | ConduitCredentials conduitCredentials = TestUtils.getConduitCredentials(TEST_URL, TEST_GATEWAY); 43 | assertEquals(TEST_URL, conduitCredentials.getUrl()); 44 | assertEquals(TEST_GATEWAY, conduitCredentials.getGateway()); 45 | } 46 | 47 | @Override 48 | protected void addBuildStep() { 49 | // Do nothing. 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/com/uber/jenkins/phabricator/provider/BaseProviderTest.java: -------------------------------------------------------------------------------- 1 | package com.uber.jenkins.phabricator.provider; 2 | 3 | import com.uber.jenkins.phabricator.PhabricatorNotifier; 4 | import com.uber.jenkins.phabricator.coverage.CoverageProvider; 5 | import com.uber.jenkins.phabricator.utils.TestUtils; 6 | import org.junit.Rule; 7 | import org.junit.Test; 8 | import org.jvnet.hudson.test.JenkinsRule; 9 | 10 | import static org.junit.Assert.assertNotNull; 11 | import static org.junit.Assert.assertNull; 12 | 13 | public class BaseProviderTest { 14 | @Rule 15 | public JenkinsRule j = new JenkinsRule(); 16 | 17 | @Test 18 | public void testGetInvalidProvider() { 19 | Provider provider = getProvider(); 20 | assertNull(provider.getInstance("nonexistent.classname")); 21 | } 22 | 23 | @Test 24 | public void testGetValidProvider() { 25 | Provider provider = getProvider(); 26 | assertNotNull(provider.getInstance(PhabricatorNotifier.COBERTURA_CLASS_NAME)); 27 | } 28 | 29 | private Provider getProvider() { 30 | return new BaseProvider( 31 | j.getInstance(), 32 | "cobertura", 33 | TestUtils.getDefaultLogger() 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/com/uber/jenkins/phabricator/provider/InstanceProviderTest.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.provider; 22 | 23 | import com.uber.jenkins.phabricator.unit.UnitTestProvider; 24 | import com.uber.jenkins.phabricator.utils.TestUtils; 25 | import org.junit.Rule; 26 | import org.junit.Test; 27 | import org.jvnet.hudson.test.JenkinsRule; 28 | 29 | import static org.junit.Assert.assertNull; 30 | 31 | public class InstanceProviderTest { 32 | @Rule 33 | public JenkinsRule j = new JenkinsRule(); 34 | 35 | @Test 36 | public void testUnavailablePlugin() { 37 | InstanceProvider provider = makeProvider("weird-plugin-name", "anything"); 38 | assertNull(provider.getInstance()); 39 | } 40 | 41 | @Test 42 | public void testUnavailablePluginValidClass() { 43 | InstanceProvider provider = makeProvider("weird-plugin-name", "com.uber.jenkins.phabricator.unit.JUnitTestProvider"); 44 | assertNull(provider.getInstance()); 45 | } 46 | 47 | @Test 48 | public void testBadClassName() { 49 | InstanceProvider provider = makeProvider("junit", "com.nonexistent.class"); 50 | assertNull(provider.getInstance()); 51 | } 52 | 53 | private InstanceProvider makeProvider(String pluginName, String className) { 54 | return new InstanceProvider( 55 | j.getInstance(), 56 | pluginName, 57 | className, 58 | TestUtils.getDefaultLogger() 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/com/uber/jenkins/phabricator/tasks/ApplyPatchTaskTest.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.tasks; 22 | 23 | import com.uber.jenkins.phabricator.utils.TestUtils; 24 | import org.junit.Rule; 25 | import org.junit.Test; 26 | import org.jvnet.hudson.test.JenkinsRule; 27 | 28 | import static org.junit.Assert.assertEquals; 29 | 30 | public class ApplyPatchTaskTest { 31 | @Rule 32 | public JenkinsRule j = new JenkinsRule(); 33 | 34 | @Test 35 | public void testApplyPatchWithValidArc() throws Exception { 36 | ApplyPatchTask task = getTask("echo", "true"); 37 | Task.Result result = task.run(); 38 | assertEquals(Task.Result.SUCCESS, result); 39 | } 40 | 41 | @Test 42 | public void testApplyPatchWithInvalidArc() throws Exception { 43 | ApplyPatchTask task = getTask("false", "echo"); 44 | Task.Result result = task.run(); 45 | assertEquals(Task.Result.FAILURE, result); 46 | } 47 | 48 | @Test 49 | public void testBothGitAndArcFailing() throws Exception { 50 | ApplyPatchTask task = getTask("false", "false"); 51 | assertEquals(Task.Result.FAILURE, task.run()); 52 | } 53 | 54 | private ApplyPatchTask getTask(String arcPath, String gitPath) throws Exception { 55 | return new ApplyPatchTask( 56 | TestUtils.getDefaultLogger(), 57 | TestUtils.createLauncherFactory(j), 58 | TestUtils.TEST_SHA, 59 | TestUtils.TEST_DIFFERENTIAL_ID, 60 | TestUtils.TEST_CONDUIT_TOKEN, 61 | arcPath, 62 | gitPath, // git path 63 | false, // createCommit 64 | false, // skipForcedClean 65 | false, // createBranch 66 | false // patchWithForceFlag 67 | ); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/test/java/com/uber/jenkins/phabricator/tasks/NonDifferentialHarbormasterTaskTest.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.tasks; 22 | 23 | import com.uber.jenkins.phabricator.conduit.ConduitAPIClient; 24 | import com.uber.jenkins.phabricator.conduit.ConduitAPIException; 25 | import com.uber.jenkins.phabricator.utils.TestUtils; 26 | import hudson.model.Result; 27 | import net.sf.json.JSONObject; 28 | import org.junit.Before; 29 | import org.junit.Test; 30 | 31 | import java.io.IOException; 32 | 33 | import static org.junit.Assert.assertEquals; 34 | import static org.mockito.Matchers.any; 35 | import static org.mockito.Matchers.anyString; 36 | import static org.mockito.Mockito.mock; 37 | import static org.mockito.Mockito.when; 38 | 39 | public class NonDifferentialHarbormasterTaskTest { 40 | private ConduitAPIClient conduitClient; 41 | 42 | @Before 43 | public void setUp() { 44 | conduitClient = mock(ConduitAPIClient.class); 45 | } 46 | 47 | @Test 48 | public void testHappyPath() { 49 | assertEquals(Task.Result.SUCCESS, getResult()); 50 | } 51 | 52 | @Test 53 | public void testConduitAPIException() throws Exception { 54 | when(conduitClient.perform(anyString(), any(JSONObject.class))).thenThrow(ConduitAPIException.class); 55 | 56 | assertEquals(Task.Result.FAILURE, getResult()); 57 | } 58 | 59 | @Test 60 | public void testIOException() throws Exception { 61 | when(conduitClient.perform(anyString(), any(JSONObject.class))).thenThrow(IOException.class); 62 | 63 | assertEquals(Task.Result.FAILURE, getResult()); 64 | } 65 | 66 | private Task.Result getResult() { 67 | return new NonDifferentialHarbormasterTask( 68 | TestUtils.getDefaultLogger(), 69 | TestUtils.TEST_PHID, 70 | conduitClient, 71 | Result.SUCCESS, 72 | TestUtils.TEST_BASE_URL 73 | ).run(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/test/java/com/uber/jenkins/phabricator/tasks/PostCommentTaskTest.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.tasks; 22 | 23 | import com.uber.jenkins.phabricator.conduit.ConduitAPIException; 24 | import com.uber.jenkins.phabricator.conduit.DifferentialClient; 25 | import com.uber.jenkins.phabricator.utils.Logger; 26 | import com.uber.jenkins.phabricator.utils.TestUtils; 27 | import net.sf.json.JSONObject; 28 | import org.junit.Before; 29 | import org.junit.Test; 30 | 31 | import static org.mockito.Matchers.anyBoolean; 32 | import static org.mockito.Matchers.anyString; 33 | import static org.mockito.Mockito.doReturn; 34 | import static org.mockito.Mockito.doThrow; 35 | 36 | public class PostCommentTaskTest { 37 | private Logger logger; 38 | private DifferentialClient differentialClient; 39 | 40 | private final String TEST_COMMENT = "They are selling like hotcakes!"; 41 | private final String TEST_COMMENT_ACTION = "none"; 42 | private final String TEST_REVISION_ID = "something"; 43 | 44 | @Before 45 | public void setup() { 46 | logger = TestUtils.getDefaultLogger(); 47 | differentialClient = TestUtils.getDefaultDifferentialClient(); 48 | } 49 | 50 | @Test 51 | public void testPostDifferentialFailed() throws Exception { 52 | doThrow(new ConduitAPIException("")).when(differentialClient).postComment( 53 | anyString(), 54 | anyString(), 55 | anyBoolean(), 56 | anyString() 57 | ); 58 | 59 | PostCommentTask postCommentTask = new PostCommentTask(logger, differentialClient, 60 | TEST_REVISION_ID, TEST_COMMENT, TEST_COMMENT_ACTION); 61 | Task.Result result = postCommentTask.run(); 62 | assert result == Task.Result.FAILURE; 63 | } 64 | 65 | @Test 66 | public void testPostDifferentialSuccess() throws Exception { 67 | doReturn(new JSONObject()).when(differentialClient).postComment( 68 | anyString(), 69 | anyString(), 70 | anyBoolean(), 71 | anyString() 72 | ); 73 | 74 | assert new PostCommentTask(logger, differentialClient, TEST_REVISION_ID, 75 | TEST_COMMENT, TEST_COMMENT_ACTION).run() == Task.Result.SUCCESS; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/test/java/com/uber/jenkins/phabricator/tasks/SendHarbormasterResultTaskTest.java: -------------------------------------------------------------------------------- 1 | package com.uber.jenkins.phabricator.tasks; 2 | 3 | import com.uber.jenkins.phabricator.conduit.ConduitAPIException; 4 | import com.uber.jenkins.phabricator.conduit.DifferentialClient; 5 | import com.uber.jenkins.phabricator.utils.TestUtils; 6 | import net.sf.json.JSONObject; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import java.io.IOException; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | import static org.junit.Assert.assertEquals; 15 | import static org.mockito.Mockito.mock; 16 | import static org.mockito.Mockito.when; 17 | 18 | public class SendHarbormasterResultTaskTest { 19 | private final JSONObject validResponse = new JSONObject(); 20 | private DifferentialClient diffClient; 21 | 22 | @Before 23 | public void setUp() { 24 | diffClient = mock(DifferentialClient.class); 25 | } 26 | 27 | @Test 28 | public void testSuccessfulHarbormaster() throws IOException, ConduitAPIException { 29 | when(diffClient.sendHarbormasterMessage(TestUtils.TEST_PHID, false, null, null, null)).thenReturn(validResponse); 30 | 31 | assertEquals(Task.Result.SUCCESS, getResult()); 32 | } 33 | 34 | @Test 35 | public void testErrorInfoResponse() throws IOException, ConduitAPIException { 36 | when(diffClient.sendHarbormasterMessage(TestUtils.TEST_PHID, false, null, null, null)).thenReturn(getErrorResponse()); 37 | 38 | assertEquals(Task.Result.FAILURE, getResult()); 39 | } 40 | 41 | @Test 42 | public void testRetryOnUnitError() throws Exception { 43 | Map coverage = new HashMap(); 44 | coverage.put("filename", "NNNUC"); 45 | when(diffClient.sendHarbormasterMessage(TestUtils.TEST_PHID, false, null, coverage, null)).thenReturn(getErrorResponse()); 46 | when(diffClient.sendHarbormasterMessage(TestUtils.TEST_PHID, false, null, null, null)).thenReturn(validResponse); 47 | 48 | assertEquals(Task.Result.SUCCESS, getResult(coverage)); 49 | } 50 | 51 | @Test 52 | public void testConduitAPIFailure() throws IOException, ConduitAPIException { 53 | when(diffClient.sendHarbormasterMessage(TestUtils.TEST_PHID, false, null, null, null)).thenThrow(ConduitAPIException.class); 54 | 55 | assertEquals(Task.Result.FAILURE, getResult()); 56 | } 57 | 58 | @Test 59 | public void testIOExceptionFailure() throws IOException, ConduitAPIException { 60 | when(diffClient.sendHarbormasterMessage(TestUtils.TEST_PHID, false, null, null, null)).thenThrow(IOException.class); 61 | 62 | assertEquals(Task.Result.FAILURE, getResult()); 63 | } 64 | 65 | private Task.Result getResult(Map coverage) { 66 | return new SendHarbormasterResultTask( 67 | TestUtils.getDefaultLogger(), 68 | diffClient, 69 | TestUtils.TEST_PHID, 70 | false, 71 | null, 72 | coverage, 73 | null 74 | ).run(); 75 | } 76 | 77 | private Task.Result getResult() { 78 | return getResult(null); 79 | } 80 | 81 | private JSONObject getErrorResponse() { 82 | return new JSONObject().element("error_info", "i'm having a bad day"); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/test/java/com/uber/jenkins/phabricator/tasks/SendHarbormasterUriTaskTest.java: -------------------------------------------------------------------------------- 1 | // Permission is hereby granted, free of charge, to any person obtaining a copy 2 | // of this software and associated documentation files (the "Software"), to deal 3 | // in the Software without restriction, including without limitation the rights 4 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 5 | // copies of the Software, and to permit persons to whom the Software is 6 | // furnished to do so, subject to the following conditions: 7 | // 8 | // The above copyright notice and this permission notice shall be included in 9 | // all copies or substantial portions of the Software. 10 | // 11 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 17 | // THE SOFTWARE. 18 | 19 | package com.uber.jenkins.phabricator.tasks; 20 | 21 | import com.uber.jenkins.phabricator.conduit.ConduitAPIException; 22 | import com.uber.jenkins.phabricator.conduit.DifferentialClient; 23 | import com.uber.jenkins.phabricator.utils.TestUtils; 24 | import net.sf.json.JSONObject; 25 | import org.junit.Before; 26 | import org.junit.Test; 27 | 28 | import java.io.IOException; 29 | 30 | import static org.junit.Assert.assertEquals; 31 | import static org.mockito.Mockito.mock; 32 | import static org.mockito.Mockito.when; 33 | 34 | public class SendHarbormasterUriTaskTest { 35 | private final String buildUrl = "http://jenkins.example.com/foo/123"; 36 | private final JSONObject validResponse = new JSONObject(); 37 | private DifferentialClient diffClient; 38 | 39 | @Before 40 | public void setUp() { 41 | diffClient = mock(DifferentialClient.class); 42 | } 43 | 44 | @Test 45 | public void testUrlHappyPath() throws IOException, ConduitAPIException { 46 | when(diffClient.sendHarbormasterUri(TestUtils.TEST_PHID, buildUrl)).thenReturn(validResponse); 47 | 48 | assertEquals(Task.Result.SUCCESS, getResult()); 49 | } 50 | 51 | @Test 52 | public void testErrorInfoResponse() throws IOException, ConduitAPIException { 53 | JSONObject errorResponse = new JSONObject(); 54 | errorResponse.put("error_info", "i'm having a bad day"); 55 | when(diffClient.sendHarbormasterUri(TestUtils.TEST_PHID, buildUrl)).thenReturn(errorResponse); 56 | 57 | assertEquals(Task.Result.FAILURE, getResult()); 58 | } 59 | 60 | @Test 61 | public void testConduitAPIFailure() throws IOException, ConduitAPIException { 62 | when(diffClient.sendHarbormasterUri(TestUtils.TEST_PHID, buildUrl)).thenThrow(ConduitAPIException.class); 63 | 64 | assertEquals(Task.Result.FAILURE, getResult()); 65 | } 66 | 67 | @Test 68 | public void testIOExceptionFailure() throws IOException, ConduitAPIException { 69 | when(diffClient.sendHarbormasterUri(TestUtils.TEST_PHID, buildUrl)).thenThrow(IOException.class); 70 | 71 | assertEquals(Task.Result.FAILURE, getResult()); 72 | } 73 | 74 | private Task.Result getResult() { 75 | return new SendHarbormasterUriTask( 76 | TestUtils.getDefaultLogger(), 77 | diffClient, 78 | TestUtils.TEST_PHID, 79 | buildUrl 80 | ).run(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/test/java/com/uber/jenkins/phabricator/unit/JUnitTestProviderTest.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.unit; 22 | 23 | import hudson.tasks.junit.TestResult; 24 | import hudson.util.IOUtils; 25 | import org.junit.Test; 26 | 27 | import java.io.File; 28 | import java.io.IOException; 29 | import java.io.InputStream; 30 | 31 | import static org.junit.Assert.assertEquals; 32 | import static org.junit.Assert.assertNotNull; 33 | 34 | public class JUnitTestProviderTest { 35 | @Test 36 | public void testConvertJUnit() throws Exception { 37 | JUnitTestProvider provider = new JUnitTestProvider(); 38 | UnitResults results = provider.convertJUnit(getTestResult()); 39 | 40 | assertNotNull(results); 41 | assertEquals(35, results.getResults().size()); 42 | for (UnitResult result : results.getResults()) { 43 | assertEquals("pass", result.getHarbormasterResult()); 44 | } 45 | } 46 | 47 | @Test 48 | public void testConvertNullProvider() { 49 | assertEquals(0, new JUnitTestProvider().convertJUnit(null).getResults().size()); 50 | } 51 | 52 | private TestResult getTestResult() throws IOException { 53 | File temp = File.createTempFile("anything", "xml"); 54 | temp.deleteOnExit(); 55 | InputStream junit = getClass().getResourceAsStream("go-torch-junit.xml"); 56 | 57 | IOUtils.copy(junit, temp); 58 | TestResult result = new TestResult(); 59 | result.parse(temp); 60 | return result; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/test/java/com/uber/jenkins/phabricator/unit/UnitResultTest.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.unit; 22 | 23 | import net.sf.json.JSONObject; 24 | import org.junit.Before; 25 | import org.junit.Test; 26 | 27 | import static org.junit.Assert.assertEquals; 28 | import static org.junit.Assert.assertFalse; 29 | import static org.junit.Assert.assertTrue; 30 | 31 | public class UnitResultTest { 32 | private UnitResult result; 33 | 34 | @Before 35 | public void setUp() { 36 | result = makeResult(0, 0, 1); 37 | } 38 | 39 | @Test 40 | public void testToHarbormaster() { 41 | JSONObject json = result.toHarbormaster(); 42 | 43 | assertTrue(json.keySet().contains("engine")); 44 | assertEquals("display-name", json.getString("name")); 45 | assertEquals("class-name", json.getString("namespace")); 46 | assertEquals("pass", json.getString("result")); 47 | assertEquals(1.2, json.getDouble("duration"), 0.01); 48 | assertFalse(json.keySet().contains("details")); 49 | } 50 | 51 | @Test 52 | public void testToHarbormasterWithTrace() { 53 | JSONObject json = makeResult(1, 0, 0, "trace").toHarbormaster(); 54 | 55 | assertTrue(json.keySet().contains("details")); 56 | assertEquals("trace", json.getString("details")); 57 | } 58 | 59 | @Test 60 | public void testGetHarbormasterResult() { 61 | assertEquals("fail", makeResult(1, 0, 0).getHarbormasterResult()); 62 | assertEquals("skip", makeResult(0, 1, 0).getHarbormasterResult()); 63 | assertEquals("pass", makeResult(0, 0, 1).getHarbormasterResult()); 64 | assertEquals("unsound", makeResult(0, 0, 0).getHarbormasterResult()); 65 | } 66 | 67 | private UnitResult makeResult(int fail, int skip, int pass) { 68 | return makeResult(fail, skip, pass, null); 69 | } 70 | 71 | private UnitResult makeResult(int fail, int skip, int pass, String trace) { 72 | return new UnitResult( 73 | "class-name", 74 | "display-name", 75 | trace, 76 | 1.2f, 77 | fail, 78 | skip, 79 | pass 80 | ); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/test/java/com/uber/jenkins/phabricator/unit/UnitResultsTest.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.unit; 22 | 23 | import com.uber.jenkins.phabricator.utils.TestUtils; 24 | import org.junit.Before; 25 | import org.junit.Test; 26 | 27 | import static org.junit.Assert.assertEquals; 28 | 29 | public class UnitResultsTest { 30 | private UnitResults results; 31 | 32 | @Before 33 | public void setUp() { 34 | results = new UnitResults(); 35 | } 36 | 37 | @Test 38 | public void testAdd() { 39 | results.add(TestUtils.getDefaultUnitResult()); 40 | assertEquals(1, results.getResults().size()); 41 | } 42 | 43 | @Test 44 | public void testToHarbormaster() { 45 | assertEquals(0, results.toHarbormaster().size()); 46 | 47 | results.add(TestUtils.getDefaultUnitResult()); 48 | assertEquals(1, results.toHarbormaster().size()); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/com/uber/jenkins/phabricator/utils/CommonUtilsTest.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.utils; 22 | 23 | import org.junit.Test; 24 | 25 | import static org.junit.Assert.assertFalse; 26 | import static org.junit.Assert.assertTrue; 27 | 28 | public class CommonUtilsTest { 29 | 30 | @Test 31 | public void testNullString() { 32 | assertTrue(CommonUtils.isBlank(null)); 33 | } 34 | 35 | @Test 36 | public void testEmptyString() { 37 | assertTrue(CommonUtils.isBlank("")); 38 | } 39 | 40 | @Test 41 | public void testBlankString() { 42 | assertTrue(CommonUtils.isBlank(" ")); 43 | } 44 | 45 | @Test 46 | public void testValidStrings() { 47 | assertFalse(CommonUtils.isBlank("There's some content here!")); 48 | assertFalse(CommonUtils.isBlank(" There's some content here!")); 49 | assertFalse(CommonUtils.isBlank("There's some content here! ")); 50 | assertFalse(CommonUtils.isBlank(" There's some content here! ")); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/test/java/com/uber/jenkins/phabricator/utils/LoggerTest.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package com.uber.jenkins.phabricator.utils; 22 | 23 | import org.junit.Before; 24 | import org.junit.Test; 25 | 26 | import java.io.ByteArrayOutputStream; 27 | import java.io.PrintStream; 28 | 29 | import static org.junit.Assert.assertEquals; 30 | 31 | public class LoggerTest { 32 | 33 | private ByteArrayOutputStream byteArrayOutputStream; 34 | private PrintStream stream; 35 | private Logger logger; 36 | 37 | @Before 38 | public void setup() { 39 | byteArrayOutputStream = new ByteArrayOutputStream(); 40 | stream = new PrintStream(byteArrayOutputStream); 41 | logger = new Logger(stream); 42 | } 43 | 44 | @Test 45 | public void testInfo() { 46 | String tag = "phabricator-jenkins"; 47 | String message = "This is a great plugin!"; 48 | 49 | logger.info(tag, message); 50 | assertEquals("[phabricator:phabricator-jenkins] This is a great plugin!\n", byteArrayOutputStream.toString()); 51 | } 52 | 53 | @Test 54 | public void testWarn() { 55 | String tag = "a-softer-world"; 56 | String message = "This is a great comic"; 57 | 58 | logger.info(tag, message); 59 | assertEquals("[phabricator:a-softer-world] This is a great comic\n", byteArrayOutputStream.toString()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/resources/com/uber/jenkins/phabricator/conduit/ResponseWithChanges.json: -------------------------------------------------------------------------------- 1 | { 2 | "revisionID": "42", 3 | "sourceControlBaseRevision": "4b825dc642cb6eb9a060e54bf8d69288fbee4904", 4 | "hello": "world", 5 | "authorName": "aiden", 6 | "authorEmail": "sc@ndella.com", 7 | "changes": [ 8 | { 9 | "currentPath": "file.go" 10 | }, 11 | { 12 | "currentPath": "file2.go" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /src/test/resources/com/uber/jenkins/phabricator/conduit/fetchDiffResponseMissingDiff.json: -------------------------------------------------------------------------------- 1 | { 2 | "result": { 3 | "not-my-diff": { 4 | "garbaj": true 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/test/resources/com/uber/jenkins/phabricator/conduit/fetchDiffWithResponseArray.json: -------------------------------------------------------------------------------- 1 | { 2 | "result": [] 3 | } 4 | -------------------------------------------------------------------------------- /src/test/resources/com/uber/jenkins/phabricator/conduit/missingAuthorResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "result": { 3 | "123": { 4 | "revisionID": "42", 5 | "sourceControlBaseRevision": "4b825dc642cb6eb9a060e54bf8d69288fbee4904" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/test/resources/com/uber/jenkins/phabricator/conduit/unitResultWithFailureRequest.json: -------------------------------------------------------------------------------- 1 | { 2 | "type":"fail", 3 | "buildTargetPHID":"PHID-not-real", 4 | "unit":[ 5 | { 6 | "name":"TestCreateFile", 7 | "result":"pass", 8 | "namespace":"visualization", 9 | "engine":"Jenkins", 10 | "duration":0 11 | }, 12 | { 13 | "name":"TestCreateFileOverwriteExisting", 14 | "result":"pass", 15 | "namespace":"visualization", 16 | "engine":"Jenkins", 17 | "duration":0 18 | }, 19 | { 20 | "name":"TestGenerateFlameGraph", 21 | "result":"pass", 22 | "namespace":"visualization", 23 | "engine":"Jenkins", 24 | "duration":0 25 | }, 26 | { 27 | "name":"TestGenerateFlameGraphPrintsToStdout", 28 | "result":"pass", 29 | "namespace":"visualization", 30 | "engine":"Jenkins", 31 | "duration":0 32 | }, 33 | { 34 | "name":"TestGenerateFlameGraphExecError", 35 | "result":"pass", 36 | "namespace":"visualization", 37 | "engine":"Jenkins", 38 | "duration":0 39 | }, 40 | { 41 | "name":"TestRunPerlScriptDoesExist", 42 | "result":"pass", 43 | "namespace":"visualization", 44 | "engine":"Jenkins", 45 | "duration":0 46 | }, 47 | { 48 | "name":"TestRunPerlScriptDoesNotExist", 49 | "result":"pass", 50 | "namespace":"visualization", 51 | "engine":"Jenkins", 52 | "duration":0 53 | }, 54 | { 55 | "name":"TestNewVisualizer", 56 | "result":"fail", 57 | "namespace":"visualization", 58 | "details":"1. It fails ", 59 | "engine":"Jenkins", 60 | "duration":0 61 | } 62 | ], 63 | "__conduit__":{ 64 | "token":"notarealtoken" 65 | } 66 | } -------------------------------------------------------------------------------- /src/test/resources/com/uber/jenkins/phabricator/conduit/validDifferentialQueryResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "revisionID": "not-a-real-id", 3 | "branch": "a-branch-name", 4 | "sourceControlBaseRevision": "aaaaaaaa", 5 | "authorName": "aiden", 6 | "authorEmail": "ai@uber.com" 7 | } -------------------------------------------------------------------------------- /src/test/resources/com/uber/jenkins/phabricator/conduit/validFetchDiffResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "result": { 3 | "123": { 4 | "revisionID": "42", 5 | "sourceControlBaseRevision": "4b825dc642cb6eb9a060e54bf8d69288fbee4904", 6 | "hello": "world", 7 | "authorName": "aiden", 8 | "authorEmail": "sc@ndella.com", 9 | "changes": [ 10 | { 11 | "currentPath": "github.com/uber/go-torch/visualization/visualization.go" 12 | }, 13 | { 14 | "currentPath": "github.com/uber/go-torch/main.go" 15 | }, 16 | { 17 | "currentPath": "github.com/uber/go-torch/graph/graph.go" 18 | } 19 | ] 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/resources/com/uber/jenkins/phabricator/coverage/go-torch-coverage_overwrite.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | /usr/local/Cellar/go/1.5/libexec/src 6 | /Users/aiden/src/gocode/src 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/test/resources/com/uber/jenkins/phabricator/uberalls/validCoverage.json: -------------------------------------------------------------------------------- 1 | { 2 | "sha": "deadbeef", 3 | "lineCoverage": 42, 4 | "filesCoverage": 99.99, 5 | "packageCoverage": 100, 6 | "classesCoverage": 100, 7 | "methodCoverage": 42, 8 | "conditionalCoverage": 0 9 | } 10 | -------------------------------------------------------------------------------- /src/test/resources/com/uber/jenkins/phabricator/unit/go-torch-junit-fail.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 1. It fails 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/test/resources/com/uber/jenkins/phabricator/unit/go-torch-junit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 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 | --------------------------------------------------------------------------------