├── .editorconfig ├── .gitignore ├── .project ├── .travis.yml ├── CHANGES ├── LICENSE ├── README.md ├── pom.xml └── src ├── main ├── java │ ├── META-INF │ │ └── MANIFEST.MF │ └── fr │ │ └── techad │ │ └── sonar │ │ ├── GerritConfiguration.java │ │ ├── GerritConstants.java │ │ ├── GerritInitializer.java │ │ ├── GerritPlugin.java │ │ ├── GerritPluginException.java │ │ ├── GerritPostJob.java │ │ ├── GerritProjectBuilder.java │ │ ├── PropertyKey.java │ │ ├── ReviewHolder.java │ │ ├── gerrit │ │ ├── GerritConnector.java │ │ ├── GerritFacade.java │ │ ├── factory │ │ │ ├── GerritConnectorFactory.java │ │ │ └── GerritFacadeFactory.java │ │ ├── network │ │ │ ├── rest │ │ │ │ ├── GerritRestConnector.java │ │ │ │ └── GerritRestFacade.java │ │ │ └── ssh │ │ │ │ ├── GerritSshConnector.java │ │ │ │ └── GerritSshFacade.java │ │ ├── review │ │ │ ├── ReviewFileComment.java │ │ │ ├── ReviewInput.java │ │ │ └── ReviewLineComment.java │ │ └── utils │ │ │ └── ReviewUtils.java │ │ └── utils │ │ └── MessageUtils.java └── resources │ └── org │ └── sonar │ └── l10n │ ├── gerrit.properties │ └── gerrit_fr.properties └── test └── java └── fr └── techad └── sonar ├── GerritConfigurationTest.java ├── GerritInitializerTest.java ├── GerritPostJobTest.java ├── gerrit ├── GerritFacadeTest.java ├── factory │ ├── GerritConnectorFactoryTest.java │ └── GerritFacadeFactoryTest.java ├── network │ ├── rest │ │ ├── GerritRestConnectorTest.java │ │ └── GerritRestFacadeTest.java │ └── ssh │ │ └── GerritSshFacadeTest.java ├── review │ ├── ReviewFileCommentTest.java │ ├── ReviewInputTest.java │ └── ReviewLineCommentTest.java └── utils │ └── ReviewUtilsTest.java ├── mockito └── MockitoExtension.java └── utils └── MessageUtilsTest.java /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | # Change these settings to your own preference 10 | indent_style = space 11 | indent_size = 4 12 | 13 | # We recommend you to keep these unchanged 14 | end_of_line = lf 15 | charset = utf-8 16 | trim_trailing_whitespace = true 17 | insert_final_newline = true 18 | 19 | [*.md] 20 | trim_trailing_whitespace = false 21 | 22 | [{package,bower}.json] 23 | indent_style = space 24 | indent_size = 2 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | *.bak 3 | target/ 4 | bin/ 5 | .settings/ 6 | .externalToolBuilders/ 7 | .classpath 8 | .project 9 | 10 | # Package Files # 11 | *.jar 12 | *.war 13 | *.ear 14 | 15 | # IDEA 16 | .idea/ 17 | *.iml 18 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | sonar-gerrit-plugin 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.m2e.core.maven2Builder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.m2e.core.maven2Nature 21 | org.eclipse.jdt.core.javanature 22 | 23 | 24 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | sudo: false 3 | install: true 4 | addons: 5 | sonarcloud: 6 | organization: "tech-advantage" 7 | token: 8 | secure: "RLkcMGMkbP8w9vExYbaaGLcXd2cdK82EsAywOHn2xPEBs7SE6KVcGsWUpb4Tgry3/usyriFUovQyu7BACnomRf2AinbzIu+LMChTe5Ridme9iQ2fUlqriSxXWUKH+SSGQddrumupud1ActcEIWqgSonkYsfozCkqHcG7G9zsVm0=" 9 | jdk: 10 | - oraclejdk8 11 | script: 12 | - mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar 13 | cache: 14 | directories: 15 | - '$HOME/.m2/repository' 16 | - '$HOME/.sonar/cache' 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | Changes with version 2.2 : 2 | * Rewrite plugin to use injection. Compiled for SonarQube 4.5.1+ LTS. 3 | 4 | Changes with version 2.1 : 5 | * Allow anonymous access 6 | 7 | Changes with version 2.0 : 8 | * Add authentication scheme selection 9 | * Add l10n for the setting pages 10 | * Add a threshold to vote -1/+1 (global/project) 11 | * Add to enable/disable on Sonar side (global/project) 12 | * Add logs 13 | * Add tests 14 | * Clean-up sonar issues 15 | * Message can contain dynamic values retrived from settings 16 | * Refactor settings view (split server/review settings) 17 | 18 | Changes with version 1.0 (1f9567ae16756a202f4631c9b2cbd18adb305960): 19 | * Initial version from TouK https://github.com/TouK/sonar-gerrit-plugin.git 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Travis status : [![Build Status](https://travis-ci.org/tech-advantage/sonar-gerrit-plugin.svg?branch=master)](https://travis-ci.org/tech-advantage/sonar-gerrit-plugin) 2 | SonarQube quality : [![SonarQube Quality](https://sonarcloud.io/api/project_badges/measure?project=fr.techad%3Asonar-gerrit-plugin&metric=alert_status)](https://sonarcloud.io/dashboard?id=fr.techad%3Asonar-gerrit-plugin) 3 | 4 | Gerrit Plugin for SonarQube™ 5 | ============================ 6 | 7 | For every Jenkins build, this plugin reports SonarQube™ issues on your patchsets to your Gerrit server. 8 | SonarQube™ analyses full project, but only files included in patchset are commented on Gerrit. 9 | Plugin reports -1 or +1 for Code-Review (default) based on severity threshold (default:INFO). 10 | 11 | #Read the [wiki](https://github.com/tech-advantage/sonar-gerrit-plugin/wiki) for more details ! 12 | 13 | License 14 | ------- 15 | 16 | This project is licenced under Apache License. 17 | 18 | ---- 19 | This project is based on original source on https://github.com/TouK/ which was abandoned. 20 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | fr.techad 6 | sonar-gerrit-plugin 7 | 2.4.0 8 | sonar-plugin 9 | Sonar Gerrit Plugin 10 | Sonar will rate your gerrit patch set and comment on found alerts. 11 | https://github.com/tech-advantage/sonar-gerrit-plugin 12 | 13 | TECH'advantage 14 | http://www.techad.fr 15 | 16 | 17 | 18 | Apache License 19 | 20 | 21 | 22 | scm:git:https://github.com/tech-advantage/sonar-gerrit-plugin.git 23 | scm:git:git@github.com:tech-advantage/sonar-gerrit-plugin.git 24 | http:/github.com/tech-advantage/sonar-gerrit-plugin.git 25 | 26 | 27 | github 28 | https://github.com/tech-advantage/sonar-gerrit-plugin/issues 29 | 30 | 31 | UTF-8 32 | 1.8 33 | 3.5.0 34 | 35 | 7.0 36 | 1.2 37 | 3.7 38 | 1.10 39 | 1.4 40 | 2.19.1 41 | 5.2.0 42 | 2.8.9 43 | 1.0.2 44 | 4.5.13 45 | 2.2.1 46 | 16.0.2 47 | 5.4.1 48 | 49 | 1.18.0.372 50 | 3.7.0 51 | 3.0.0-M2 52 | 3.0.0 53 | 2.22.0 54 | 0.8.1 55 | 2.0.1 56 | 3.4.1.1168 57 | 2.8.0 58 | 59 | 60 | 61 | org.sonarsource.sonarqube 62 | sonar-plugin-api 63 | ${sonar.buildVersion} 64 | provided 65 | 66 | 67 | commons-logging 68 | commons-logging 69 | ${commons-logging.version} 70 | provided 71 | 72 | 73 | org.easytesting 74 | fest-assert 75 | ${fest-assert.version} 76 | test 77 | 78 | 79 | org.mockito 80 | mockito-core 81 | ${mockito.version} 82 | test 83 | 84 | 85 | org.junit.jupiter 86 | junit-jupiter-engine 87 | ${junit.version} 88 | test 89 | 90 | 91 | org.junit.platform 92 | junit-platform-runner 93 | 1.2.0 94 | test 95 | 96 | 97 | org.junit.vintage 98 | junit-vintage-engine 99 | ${junit.version} 100 | test 101 | 102 | 103 | org.mock-server 104 | mockserver-netty 105 | ${mockserver-netty.version} 106 | test 107 | 108 | 109 | com.google.code.gson 110 | gson 111 | ${gson.version} 112 | 113 | 114 | fi.jpalomaki.ssh 115 | simple-ssh-client 116 | ${simple-ssh-client} 117 | 118 | 119 | org.apache.httpcomponents 120 | httpclient 121 | ${httpclient.version} 122 | 123 | 124 | org.apache.commons 125 | commons-lang3 126 | ${commons-lang3.version} 127 | 128 | 129 | commons-codec 130 | commons-codec 131 | ${commons-codec.version} 132 | 133 | 134 | org.apache.maven 135 | maven-project 136 | ${maven-project.version} 137 | 138 | 139 | org.jetbrains 140 | annotations 141 | ${annotations.version} 142 | 143 | 144 | 145 | 146 | SonarSnapShot 147 | Sonar Snapshot 148 | http://repository-sonarplugins.forge.cloudbees.com/snapshot/ 149 | 150 | 151 | 152 | ${project.artifactId}-${project.version}-sq-${sonar.buildVersion} 153 | 154 | 155 | 156 | org.apache.maven.plugins 157 | maven-enforcer-plugin 158 | ${plugin.maven-enforcer-plugin.version} 159 | 160 | 161 | org.sonarsource.sonar-packaging-maven-plugin 162 | sonar-packaging-maven-plugin 163 | ${plugin.sonar-packaging.version} 164 | 165 | 166 | org.apache.maven.plugins 167 | maven-compiler-plugin 168 | ${plugin.maven-compiler-plugin.version} 169 | 170 | 171 | 173 | org.codehaus.mojo 174 | native2ascii-maven-plugin 175 | ${plugin.native2ascii-maven-plugin.version} 176 | 177 | 178 | com.github.ekryd.sortpom 179 | sortpom-maven-plugin 180 | ${plugin.sortpom-maven-plugin.version} 181 | 182 | 183 | org.jacoco 184 | jacoco-maven-plugin 185 | ${plugin.jacoco-maven-plugin.version} 186 | 187 | 188 | org.sonarsource.scanner.maven 189 | sonar-maven-plugin 190 | ${plugin.sonar-maven-plugin.version} 191 | 192 | 193 | org.apache.maven.plugins 194 | maven-surefire-report-plugin 195 | ${plugin.maven-surefire-report-plugin.version} 196 | 197 | 198 | org.apache.maven.plugins 199 | maven-project-info-reports-plugin 200 | ${plugin.maven-project-info-reports-plugin.version} 201 | 202 | 203 | 204 | 205 | 206 | org.sonarsource.sonar-packaging-maven-plugin 207 | sonar-packaging-maven-plugin 208 | true 209 | 210 | gerrit 211 | Gerrit Reviewer 212 | fr.techad.sonar.GerritPlugin 213 | 214 | 215 | 216 | org.apache.maven.plugins 217 | maven-enforcer-plugin 218 | 219 | 220 | enforce-prerequisites 221 | 222 | enforce 223 | 224 | 225 | 226 | 227 | ${jdk.min.version} 228 | 229 | 230 | ${maven.min.version} 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | org.apache.maven.plugins 239 | maven-compiler-plugin 240 | 241 | ${jdk.min.version} 242 | ${jdk.min.version} 243 | 244 | 245 | 246 | 248 | org.codehaus.mojo 249 | native2ascii-maven-plugin 250 | 251 | 252 | utf8-to-latin1 253 | 254 | resources 255 | 256 | 257 | 258 | 259 | 260 | 261 | com.github.ekryd.sortpom 262 | sortpom-maven-plugin 263 | 264 | 265 | verify 266 | 267 | sort 268 | 269 | 270 | 271 | 272 | 273 | org.sonarsource.scanner.maven 274 | sonar-maven-plugin 275 | 276 | 277 | org.jacoco 278 | jacoco-maven-plugin 279 | 280 | 281 | 282 | prepare-agent 283 | 284 | 285 | 286 | report 287 | prepare-package 288 | 289 | report 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | org.apache.maven.plugins 300 | maven-project-info-reports-plugin 301 | 302 | false 303 | 304 | 305 | 306 | 307 | org.apache.maven.plugins 308 | maven-surefire-report-plugin 309 | 310 | 311 | org.jacoco 312 | jacoco-maven-plugin 313 | 314 | 315 | 316 | report 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | -------------------------------------------------------------------------------- /src/main/java/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Created-By: Apache Maven 3 | Built-By: TECH advantage 4 | Build-Jdk: 1.8 5 | Plugin-Class: fr.techad.sonar.GerritPlugin 6 | -------------------------------------------------------------------------------- /src/main/java/fr/techad/sonar/GerritConfiguration.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.sonar.api.batch.InstantiationStrategy; 5 | import org.sonar.api.batch.ScannerSide; 6 | import org.sonar.api.config.Settings; 7 | import org.sonar.api.utils.log.Logger; 8 | import org.sonar.api.utils.log.Loggers; 9 | 10 | @ScannerSide 11 | @InstantiationStrategy(InstantiationStrategy.PER_BATCH) 12 | public class GerritConfiguration { 13 | private static final Logger LOG = Loggers.get(GerritConfiguration.class); 14 | 15 | private boolean enabled; 16 | private boolean valid; 17 | private boolean anonymous; 18 | private boolean commentNewIssuesOnly; 19 | private boolean strictHostkey; 20 | 21 | private String host; 22 | 23 | private String scheme; 24 | private Integer port; 25 | private String username; 26 | private String password; 27 | private String authScheme; 28 | private String basePath; 29 | 30 | private String sshKeyPath; 31 | 32 | private String label; 33 | private String message; 34 | private String issueComment; 35 | private String threshold; 36 | private int voteNoIssue; 37 | private int voteBelowThreshold; 38 | private int voteAboveThreshold; 39 | 40 | private String projectName; 41 | private String branchName; 42 | private String changeId; 43 | private String revisionId; 44 | 45 | public GerritConfiguration(Settings settings) { 46 | LOG.debug("[GERRIT PLUGIN] Instanciating GerritConfiguration"); 47 | 48 | this.enable(settings.getBoolean(PropertyKey.GERRIT_ENABLED)); 49 | this.commentNewIssuesOnly(settings.getBoolean(PropertyKey.GERRIT_COMMENT_NEW_ISSUES_ONLY)); 50 | this.strictlyCheckHostkey(settings.getBoolean(PropertyKey.GERRIT_STRICT_HOSTKEY)); 51 | 52 | this.setScheme(settings.getString(PropertyKey.GERRIT_SCHEME)); 53 | this.setHost(settings.getString(PropertyKey.GERRIT_HOST)); 54 | this.setPort(settings.getInt(PropertyKey.GERRIT_PORT)); 55 | 56 | this.setUsername(settings.getString(PropertyKey.GERRIT_USERNAME)); 57 | this.setPassword(settings.getString(PropertyKey.GERRIT_PASSWORD)); 58 | this.setHttpAuthScheme(settings.getString(PropertyKey.GERRIT_HTTP_AUTH_SCHEME)); 59 | this.setBasePath(settings.getString(PropertyKey.GERRIT_BASE_PATH)); 60 | 61 | this.setSshKeyPath(settings.getString(PropertyKey.GERRIT_SSH_KEY_PATH)); 62 | 63 | this.setLabel(settings.getString(PropertyKey.GERRIT_LABEL)); 64 | this.setMessage(settings.getString(PropertyKey.GERRIT_MESSAGE)); 65 | this.setIssueComment(settings.getString(PropertyKey.GERRIT_ISSUE_COMMENT)); 66 | this.setThreshold(settings.getString(PropertyKey.GERRIT_THRESHOLD)); 67 | this.setVoteNoIssue(settings.getInt(PropertyKey.GERRIT_VOTE_NO_ISSUE)); 68 | this.setVoteBelowThreshold(settings.getInt(PropertyKey.GERRIT_VOTE_ISSUE_BELOW_THRESHOLD)); 69 | this.setVoteAboveThreshold(settings.getInt(PropertyKey.GERRIT_VOTE_ISSUE_ABOVE_THRESHOLD)); 70 | 71 | this.setProjectName(settings.getString(PropertyKey.GERRIT_PROJECT)); 72 | this.setBranchName(settings.getString(PropertyKey.GERRIT_BRANCH)); 73 | this.setChangeId(settings.getString(PropertyKey.GERRIT_CHANGE_ID)); 74 | this.setRevisionId(settings.getString(PropertyKey.GERRIT_REVISION_ID)); 75 | 76 | this.assertGerritConfiguration(); 77 | } 78 | 79 | public boolean isValid() { 80 | assertGerritConfiguration(); 81 | return valid; 82 | } 83 | 84 | public GerritConfiguration enable(boolean serverEnabled) { 85 | enabled = serverEnabled; 86 | return this; 87 | } 88 | 89 | public boolean isEnabled() { 90 | boolean ret = enabled; 91 | if (StringUtils.isEmpty(changeId) || StringUtils.isEmpty(revisionId)) { 92 | LOG.info( 93 | "[GERRIT PLUGIN] changeId or revisionId is empty. Not called from Gerrit ? Soft-disabling myself."); 94 | ret = false; 95 | } 96 | return ret; 97 | } 98 | 99 | public boolean isAnonymous() { 100 | return anonymous; 101 | } 102 | 103 | public GerritConfiguration commentNewIssuesOnly(boolean newIssuesOnly) { 104 | commentNewIssuesOnly = newIssuesOnly; 105 | return this; 106 | } 107 | 108 | public boolean shouldCommentNewIssuesOnly() { 109 | return commentNewIssuesOnly; 110 | } 111 | 112 | public GerritConfiguration strictlyCheckHostkey(boolean strictHostkey) { 113 | this.strictHostkey = strictHostkey; 114 | return this; 115 | } 116 | 117 | public boolean shouldStrictlyCheckHostKey() { 118 | return strictHostkey; 119 | } 120 | 121 | public String getScheme() { 122 | return scheme; 123 | } 124 | 125 | public GerritConfiguration setScheme(String scheme) { 126 | this.scheme = scheme; 127 | return this; 128 | } 129 | 130 | public String getHost() { 131 | return host; 132 | } 133 | 134 | public GerritConfiguration setHost(String host) { 135 | this.host = host; 136 | return this; 137 | } 138 | 139 | public Integer getPort() { 140 | return port; 141 | } 142 | 143 | public GerritConfiguration setPort(Integer port) { 144 | this.port = port; 145 | return this; 146 | } 147 | 148 | public String getUsername() { 149 | return username; 150 | } 151 | 152 | public GerritConfiguration setUsername(String username) { 153 | this.username = username; 154 | if (StringUtils.isBlank(username)) { 155 | anonymous = true; 156 | } 157 | return this; 158 | } 159 | 160 | public String getPassword() { 161 | return password; 162 | } 163 | 164 | public GerritConfiguration setPassword(String password) { 165 | this.password = password; 166 | return this; 167 | } 168 | 169 | public String getHttpAuthScheme() { 170 | return authScheme; 171 | } 172 | 173 | public GerritConfiguration setHttpAuthScheme(String authScheme) { 174 | this.authScheme = authScheme; 175 | return this; 176 | } 177 | 178 | public String getBasePath() { 179 | return basePath; 180 | } 181 | 182 | public GerritConfiguration setBasePath(String basePath) { 183 | String newBasePath = basePath; 184 | 185 | if (StringUtils.isBlank(newBasePath)) { 186 | newBasePath = "/"; 187 | } 188 | 189 | if (newBasePath.charAt(0) != '/') { 190 | newBasePath = "/" + newBasePath; 191 | } 192 | 193 | while (newBasePath.startsWith("/", 1) && !newBasePath.isEmpty()) { 194 | newBasePath = newBasePath.substring(1, newBasePath.length()); 195 | } 196 | 197 | while (newBasePath.endsWith("/") && 1 < newBasePath.length()) { 198 | newBasePath = newBasePath.substring(0, newBasePath.length() - 1); 199 | } 200 | 201 | this.basePath = newBasePath; 202 | 203 | return this; 204 | } 205 | 206 | public String getSshKeyPath() { 207 | return sshKeyPath; 208 | } 209 | 210 | public GerritConfiguration setSshKeyPath(String sshKey) { 211 | this.sshKeyPath = sshKey; 212 | return this; 213 | } 214 | 215 | public String getLabel() { 216 | return label; 217 | } 218 | 219 | public GerritConfiguration setLabel(String label) { 220 | this.label = label; 221 | return this; 222 | } 223 | 224 | public String getMessage() { 225 | return message; 226 | } 227 | 228 | public GerritConfiguration setMessage(String message) { 229 | this.message = message; 230 | return this; 231 | } 232 | 233 | public String getIssueComment() { 234 | return issueComment; 235 | } 236 | 237 | public void setIssueComment(String issueComment) { 238 | this.issueComment = issueComment; 239 | } 240 | 241 | public String getThreshold() { 242 | return threshold; 243 | } 244 | 245 | public GerritConfiguration setThreshold(String threshold) { 246 | this.threshold = threshold; 247 | return this; 248 | } 249 | 250 | public int getVoteNoIssue() { 251 | return voteNoIssue; 252 | } 253 | 254 | public GerritConfiguration setVoteNoIssue(int voteNoIssue) { 255 | this.voteNoIssue = voteNoIssue; 256 | return this; 257 | } 258 | 259 | public int getVoteBelowThreshold() { 260 | return voteBelowThreshold; 261 | } 262 | 263 | public GerritConfiguration setVoteBelowThreshold(int voteBelowThreshold) { 264 | this.voteBelowThreshold = voteBelowThreshold; 265 | return this; 266 | } 267 | 268 | public int getVoteAboveThreshold() { 269 | return voteAboveThreshold; 270 | } 271 | 272 | public GerritConfiguration setVoteAboveThreshold(int voteAboveThreshold) { 273 | this.voteAboveThreshold = voteAboveThreshold; 274 | return this; 275 | } 276 | 277 | public String getProjectName() { 278 | return projectName; 279 | } 280 | 281 | public GerritConfiguration setProjectName(String projectName) { 282 | this.projectName = projectName; 283 | return this; 284 | } 285 | 286 | public String getBranchName() { 287 | return branchName; 288 | } 289 | 290 | public GerritConfiguration setBranchName(String branchName) { 291 | this.branchName = branchName; 292 | return this; 293 | } 294 | 295 | public String getChangeId() { 296 | return changeId; 297 | } 298 | 299 | public GerritConfiguration setChangeId(String changeId) { 300 | this.changeId = changeId; 301 | return this; 302 | } 303 | 304 | public String getRevisionId() { 305 | return revisionId; 306 | } 307 | 308 | public GerritConfiguration setRevisionId(String revisionId) { 309 | this.revisionId = revisionId; 310 | return this; 311 | } 312 | 313 | void assertGerritConfiguration() { 314 | LOG.debug("[GERRIT PLUGIN] Verifying configuration settings …\n{}", this.toString()); 315 | 316 | if (StringUtils.isBlank(host) || null == port) { 317 | valid = false; 318 | if (isEnabled() || LOG.isDebugEnabled()) { 319 | LOG.error("[GERRIT PLUGIN] ServerConfiguration is not valid : {}", this.toString()); 320 | } 321 | } else { 322 | valid = true; 323 | } 324 | 325 | if (GerritConstants.SCHEME_SSH.equals(scheme) && StringUtils.isBlank(username)) { 326 | valid = false; 327 | if (isEnabled() || LOG.isDebugEnabled()) { 328 | LOG.error("[GERRIT PLUGIN] Scheme is ssh but username is blank : {}", this.toString()); 329 | } 330 | } 331 | 332 | if (GerritConstants.SCHEME_SSH.equals(scheme) && StringUtils.isBlank(sshKeyPath)) { 333 | valid = false; 334 | if (isEnabled() || LOG.isDebugEnabled()) { 335 | LOG.error("[GERRIT PLUGIN] Scheme is ssh but keypath is blank : {}", this.toString()); 336 | } 337 | } 338 | 339 | if (StringUtils.isBlank(label) || StringUtils.isBlank(projectName) || StringUtils.isBlank(branchName) 340 | || StringUtils.isBlank(changeId) || StringUtils.isBlank(revisionId)) { 341 | valid = false; 342 | if (isEnabled() || LOG.isDebugEnabled()) { 343 | LOG.error("[GERRIT PLUGIN] ReviewConfiguration is not valid : {}", this.toString()); 344 | } 345 | } else { 346 | valid &= true; 347 | } 348 | } 349 | 350 | @Override 351 | public String toString() { 352 | return "GerritConfiguration [valid=" + valid + ", enabled=" + enabled + ", scheme=" + scheme + ", host=" + host 353 | + ", port=" + port + ", anonymous=" + anonymous + ", username=" + username + ", password=" 354 | + (StringUtils.isBlank(password) ? "blank" : "*obfuscated*") + ", authScheme=" + authScheme 355 | + ", basePath=" + basePath + ", sshKeyPath=" + sshKeyPath + ", label=" + label + ", message=" + message 356 | + ", issueComment=" + issueComment + ", threshold=" + threshold + ", voteNoIssue=" + voteNoIssue 357 | + ",voteBelowThreshold=" + voteBelowThreshold + ",voteAboveThreshold=" + voteAboveThreshold 358 | + ",commentNewIssuesOnly=" + commentNewIssuesOnly + ", projectName=" + projectName + ", branchName=" 359 | + branchName + ", changeId=" + changeId + ", revisionId=" + revisionId + "]"; 360 | } 361 | } 362 | -------------------------------------------------------------------------------- /src/main/java/fr/techad/sonar/GerritConstants.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar; 2 | 3 | public final class GerritConstants { 4 | 5 | public static final String GERRIT_CATEGORY = "Gerrit"; 6 | public static final String GERRIT_SUBCATEGORY_SERVER = "Server"; 7 | public static final String GERRIT_SUBCATEGORY_REVIEW = "Review"; 8 | public static final String GERRIT_ENABLED_DEFAULT = "true"; 9 | public static final String GERRIT_FORCE_BRANCH_DEFAULT = "false"; 10 | public static final String SCHEME_HTTP = "http"; 11 | public static final String SCHEME_HTTPS = "https"; 12 | public static final String SCHEME_SSH = "ssh"; 13 | public static final String AUTH_BASIC = "basic"; 14 | public static final String AUTH_DIGEST = "digest"; 15 | public static final String GERRIT_COMMENT_NEW_ISSUES_ONLY = "false"; 16 | public static final String GERRIT_STRICT_HOSTKEY_DEFAULT = "true"; 17 | public static final String GERRIT_VOTE_NO_ISSUE_DEFAULT = "+1"; 18 | public static final String GERRIT_VOTE_ISSUE_BELOW_THRESHOLD_DEFAULT = "+1"; 19 | public static final String GERRIT_VOTE_ISSUE_ABOVE_THRESHOLD_DEFAULT = "-1"; 20 | 21 | private GerritConstants() { 22 | throw new IllegalAccessError("Utility class"); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/fr/techad/sonar/GerritInitializer.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar; 2 | 3 | import fr.techad.sonar.gerrit.GerritFacade; 4 | import fr.techad.sonar.gerrit.factory.GerritFacadeFactory; 5 | import org.sonar.api.batch.Initializer; 6 | import org.sonar.api.utils.log.Logger; 7 | import org.sonar.api.utils.log.Loggers; 8 | 9 | public class GerritInitializer extends Initializer { 10 | private static final Logger LOG = Loggers.get(GerritInitializer.class); 11 | private final GerritConfiguration gerritConfiguration; 12 | private GerritFacade gerritFacade; 13 | 14 | public GerritInitializer(GerritConfiguration gerritConfiguration, GerritFacadeFactory gerritFacadeFactory) { 15 | LOG.debug("[GERRIT PLUGIN] Instanciating GerritInitializer"); 16 | this.gerritConfiguration = gerritConfiguration; 17 | this.gerritFacade = gerritFacadeFactory.getFacade(); 18 | } 19 | 20 | @Override 21 | public void execute() { 22 | if (!gerritConfiguration.isEnabled()) { 23 | LOG.info("[GERRIT PLUGIN] Initializer : will NOT execute plugin."); 24 | return; 25 | } 26 | 27 | if (!gerritConfiguration.isValid()) { 28 | LOG.info("[GERRIT PLUGIN] Initializer : Configuration is not valid, will not execute."); 29 | return; 30 | } 31 | 32 | try { 33 | gerritFacade.listFiles(); 34 | } catch (GerritPluginException e) { 35 | LOG.error("[GERRIT PLUGIN] Error getting Gerrit datas", e); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/fr/techad/sonar/GerritPlugin.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar; 2 | 3 | import fr.techad.sonar.gerrit.factory.GerritConnectorFactory; 4 | import fr.techad.sonar.gerrit.factory.GerritFacadeFactory; 5 | import org.sonar.api.Plugin; 6 | import org.sonar.api.PropertyType; 7 | import org.sonar.api.batch.rule.Severity; 8 | import org.sonar.api.config.PropertyDefinition; 9 | import org.sonar.api.resources.Qualifiers; 10 | 11 | import java.util.Arrays; 12 | 13 | public final class GerritPlugin implements Plugin { 14 | 15 | private int serverBaseIndex; 16 | private int reviewBaseIndex; 17 | 18 | @Override 19 | public void define(Context context) { 20 | PropertyDefinition enabled = PropertyDefinition.builder(PropertyKey.GERRIT_ENABLED) 21 | .category(GerritConstants.GERRIT_CATEGORY).subCategory(GerritConstants.GERRIT_SUBCATEGORY_SERVER) 22 | .type(PropertyType.BOOLEAN).defaultValue(GerritConstants.GERRIT_ENABLED_DEFAULT) 23 | .onQualifiers(Arrays.asList(Qualifiers.PROJECT)).index(serverBaseIndex++).build(); 24 | 25 | PropertyDefinition scheme = PropertyDefinition.builder(PropertyKey.GERRIT_SCHEME) 26 | .category(GerritConstants.GERRIT_CATEGORY).subCategory(GerritConstants.GERRIT_SUBCATEGORY_SERVER) 27 | .type(PropertyType.SINGLE_SELECT_LIST) 28 | .options(GerritConstants.SCHEME_HTTP, GerritConstants.SCHEME_HTTPS, GerritConstants.SCHEME_SSH) 29 | .defaultValue(GerritConstants.SCHEME_HTTP).index(serverBaseIndex++).build(); 30 | 31 | PropertyDefinition host = PropertyDefinition.builder(PropertyKey.GERRIT_HOST) 32 | .category(GerritConstants.GERRIT_CATEGORY).subCategory(GerritConstants.GERRIT_SUBCATEGORY_SERVER) 33 | .index(serverBaseIndex++).build(); 34 | 35 | PropertyDefinition port = PropertyDefinition.builder(PropertyKey.GERRIT_PORT) 36 | .category(GerritConstants.GERRIT_CATEGORY).subCategory(GerritConstants.GERRIT_SUBCATEGORY_SERVER) 37 | .type(PropertyType.INTEGER).defaultValue("80").index(serverBaseIndex++).build(); 38 | 39 | PropertyDefinition username = PropertyDefinition.builder(PropertyKey.GERRIT_USERNAME) 40 | .category(GerritConstants.GERRIT_CATEGORY).subCategory(GerritConstants.GERRIT_SUBCATEGORY_SERVER) 41 | .index(serverBaseIndex++).build(); 42 | 43 | PropertyDefinition password = PropertyDefinition.builder(PropertyKey.GERRIT_PASSWORD) 44 | .category(GerritConstants.GERRIT_CATEGORY).subCategory(GerritConstants.GERRIT_SUBCATEGORY_SERVER) 45 | .type(PropertyType.PASSWORD).index(serverBaseIndex++).build(); 46 | 47 | PropertyDefinition sshKeyPath = PropertyDefinition.builder(PropertyKey.GERRIT_SSH_KEY_PATH) 48 | .category(GerritConstants.GERRIT_CATEGORY).subCategory(GerritConstants.GERRIT_SUBCATEGORY_SERVER) 49 | .type(PropertyType.STRING).index(serverBaseIndex++).build(); 50 | 51 | PropertyDefinition strictHostkey = PropertyDefinition.builder(PropertyKey.GERRIT_STRICT_HOSTKEY) 52 | .category(GerritConstants.GERRIT_CATEGORY).subCategory(GerritConstants.GERRIT_SUBCATEGORY_SERVER) 53 | .type(PropertyType.BOOLEAN).defaultValue(GerritConstants.GERRIT_STRICT_HOSTKEY_DEFAULT) 54 | .index(serverBaseIndex++).build(); 55 | 56 | PropertyDefinition authScheme = PropertyDefinition.builder(PropertyKey.GERRIT_HTTP_AUTH_SCHEME) 57 | .category(GerritConstants.GERRIT_CATEGORY).subCategory(GerritConstants.GERRIT_SUBCATEGORY_SERVER) 58 | .type(PropertyType.SINGLE_SELECT_LIST).options(GerritConstants.AUTH_BASIC, GerritConstants.AUTH_DIGEST) 59 | .defaultValue(GerritConstants.AUTH_DIGEST).index(serverBaseIndex++).build(); 60 | 61 | PropertyDefinition basePath = PropertyDefinition.builder(PropertyKey.GERRIT_BASE_PATH) 62 | .category(GerritConstants.GERRIT_CATEGORY).subCategory(GerritConstants.GERRIT_SUBCATEGORY_SERVER) 63 | .defaultValue("/").index(serverBaseIndex++).build(); 64 | 65 | PropertyDefinition label = PropertyDefinition.builder(PropertyKey.GERRIT_LABEL) 66 | .category(GerritConstants.GERRIT_CATEGORY).subCategory(GerritConstants.GERRIT_SUBCATEGORY_REVIEW) 67 | .defaultValue("Code-Review").index(reviewBaseIndex++).build(); 68 | 69 | PropertyDefinition message = PropertyDefinition.builder(PropertyKey.GERRIT_MESSAGE) 70 | .category(GerritConstants.GERRIT_CATEGORY).subCategory(GerritConstants.GERRIT_SUBCATEGORY_REVIEW) 71 | .defaultValue("Sonar review at ${sonar.host.url}").index(reviewBaseIndex++).build(); 72 | 73 | PropertyDefinition newIssuesOnly = PropertyDefinition.builder(PropertyKey.GERRIT_COMMENT_NEW_ISSUES_ONLY) 74 | .category(GerritConstants.GERRIT_CATEGORY).subCategory(GerritConstants.GERRIT_SUBCATEGORY_REVIEW) 75 | .type(PropertyType.BOOLEAN).defaultValue(GerritConstants.GERRIT_COMMENT_NEW_ISSUES_ONLY) 76 | .onQualifiers(Arrays.asList(Qualifiers.PROJECT)).index(reviewBaseIndex++).build(); 77 | 78 | PropertyDefinition threshold = PropertyDefinition.builder(PropertyKey.GERRIT_THRESHOLD) 79 | .category(GerritConstants.GERRIT_CATEGORY).subCategory(GerritConstants.GERRIT_SUBCATEGORY_REVIEW) 80 | .type(PropertyType.SINGLE_SELECT_LIST) 81 | .options(Severity.INFO.toString(), Severity.MINOR.toString(), Severity.MAJOR.toString(), 82 | Severity.CRITICAL.toString(), Severity.BLOCKER.toString()) 83 | .defaultValue(Severity.INFO.toString()).onQualifiers(Arrays.asList(Qualifiers.PROJECT)) 84 | .index(reviewBaseIndex++).build(); 85 | 86 | PropertyDefinition voteNoIssue = PropertyDefinition.builder(PropertyKey.GERRIT_VOTE_NO_ISSUE) 87 | .category(GerritConstants.GERRIT_CATEGORY).subCategory(GerritConstants.GERRIT_SUBCATEGORY_REVIEW) 88 | .type(PropertyType.SINGLE_SELECT_LIST).options("+1", "+2") 89 | .defaultValue(GerritConstants.GERRIT_VOTE_NO_ISSUE_DEFAULT) 90 | .onQualifiers(Arrays.asList(Qualifiers.PROJECT)).index(reviewBaseIndex++).build(); 91 | 92 | PropertyDefinition voteIssueBelowThreshold = PropertyDefinition 93 | .builder(PropertyKey.GERRIT_VOTE_ISSUE_BELOW_THRESHOLD).category(GerritConstants.GERRIT_CATEGORY) 94 | .subCategory(GerritConstants.GERRIT_SUBCATEGORY_REVIEW).type(PropertyType.SINGLE_SELECT_LIST) 95 | .options("-2", "-1", "0", "+1", "+2") 96 | .defaultValue(GerritConstants.GERRIT_VOTE_ISSUE_BELOW_THRESHOLD_DEFAULT) 97 | .onQualifiers(Arrays.asList(Qualifiers.PROJECT)).index(reviewBaseIndex++).build(); 98 | 99 | PropertyDefinition voteIssueAboveThreshold = PropertyDefinition 100 | .builder(PropertyKey.GERRIT_VOTE_ISSUE_ABOVE_THRESHOLD).category(GerritConstants.GERRIT_CATEGORY) 101 | .subCategory(GerritConstants.GERRIT_SUBCATEGORY_REVIEW).type(PropertyType.SINGLE_SELECT_LIST) 102 | .options("-2", "-1", "0").defaultValue(GerritConstants.GERRIT_VOTE_ISSUE_ABOVE_THRESHOLD_DEFAULT) 103 | .onQualifiers(Arrays.asList(Qualifiers.PROJECT)).index(reviewBaseIndex++).build(); 104 | 105 | PropertyDefinition issueComment = PropertyDefinition.builder(PropertyKey.GERRIT_ISSUE_COMMENT) 106 | .category(GerritConstants.GERRIT_CATEGORY).subCategory(GerritConstants.GERRIT_SUBCATEGORY_REVIEW) 107 | .defaultValue( 108 | "[${issue.isNew}] New: ${issue.ruleKey} Severity: ${issue.severity}, Message: ${issue.message}") 109 | .index(reviewBaseIndex++).build(); 110 | 111 | context.addExtensions(Arrays.asList(GerritConfiguration.class, GerritConnectorFactory.class, 112 | GerritFacadeFactory.class, GerritInitializer.class, GerritProjectBuilder.class, GerritPostJob.class, 113 | enabled, scheme, host, port, username, password, authScheme, 114 | basePath, sshKeyPath, strictHostkey, label, message, newIssuesOnly, threshold, voteNoIssue, 115 | voteIssueBelowThreshold, voteIssueAboveThreshold, issueComment)); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/fr/techad/sonar/GerritPluginException.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar; 2 | 3 | public class GerritPluginException extends Exception { 4 | private static final long serialVersionUID = 3158628966283370707L; 5 | 6 | public GerritPluginException() { 7 | super(); 8 | } 9 | 10 | public GerritPluginException(String message) { 11 | super(message); 12 | } 13 | 14 | public GerritPluginException(String message, Throwable cause) { 15 | super(message, cause); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/fr/techad/sonar/GerritPostJob.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar; 2 | 3 | import fr.techad.sonar.gerrit.GerritFacade; 4 | import fr.techad.sonar.gerrit.factory.GerritFacadeFactory; 5 | import fr.techad.sonar.gerrit.review.ReviewFileComment; 6 | import fr.techad.sonar.gerrit.review.ReviewInput; 7 | import fr.techad.sonar.gerrit.review.ReviewLineComment; 8 | import fr.techad.sonar.gerrit.utils.ReviewUtils; 9 | import fr.techad.sonar.utils.MessageUtils; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.sonar.api.batch.fs.InputComponent; 12 | import org.sonar.api.batch.fs.InputPath; 13 | import org.sonar.api.batch.postjob.PostJob; 14 | import org.sonar.api.batch.postjob.PostJobContext; 15 | import org.sonar.api.batch.postjob.PostJobDescriptor; 16 | import org.sonar.api.batch.postjob.issue.PostJobIssue; 17 | import org.sonar.api.config.Settings; 18 | import org.sonar.api.utils.log.Logger; 19 | import org.sonar.api.utils.log.Loggers; 20 | 21 | import java.util.ArrayList; 22 | import java.util.Collection; 23 | import java.util.HashMap; 24 | import java.util.List; 25 | import java.util.Map; 26 | 27 | public class GerritPostJob implements PostJob { 28 | private static final Logger LOG = Loggers.get(GerritPostJob.class); 29 | private final Settings settings; 30 | private final GerritConfiguration gerritConfiguration; 31 | private List gerritModifiedFiles; 32 | private GerritFacade gerritFacade; 33 | private ReviewInput reviewInput = ReviewHolder.getReviewInput(); 34 | 35 | public GerritPostJob(Settings settings, GerritConfiguration gerritConfiguration, 36 | GerritFacadeFactory gerritFacadeFactory) { 37 | LOG.debug("[GERRIT PLUGIN] Instanciating GerritPostJob"); 38 | this.settings = settings; 39 | this.gerritFacade = gerritFacadeFactory.getFacade(); 40 | this.gerritConfiguration = gerritConfiguration; 41 | } 42 | 43 | @Override 44 | public void describe(PostJobDescriptor descriptor) { 45 | descriptor.name("GERRIT PLUGIN"); 46 | descriptor.requireProperty(PropertyKey.GERRIT_CHANGE_ID); 47 | } 48 | 49 | @Override 50 | public void execute(PostJobContext postJobContext) { 51 | if (!gerritConfiguration.isEnabled()) { 52 | LOG.info("[GERRIT PLUGIN] PostJob : analysis has finished. Plugin is disabled. No actions taken."); 53 | return; 54 | } 55 | 56 | Map> issueMap = new HashMap<>(); 57 | for (PostJobIssue i : postJobContext.issues()) { 58 | InputComponent inputComponent = i.inputComponent(); 59 | if (inputComponent instanceof InputPath) { 60 | InputPath inputPath = (InputPath) inputComponent; 61 | List l = issueMap.get(inputPath); 62 | if (l == null) { 63 | l = new ArrayList<>(); 64 | issueMap.put(inputPath, l); 65 | } 66 | l.add(i); 67 | } 68 | } 69 | 70 | for (Map.Entry> e : issueMap.entrySet()) { 71 | decorate(e.getKey(), postJobContext, e.getValue()); 72 | } 73 | 74 | try { 75 | LOG.info("[GERRIT PLUGIN] Analysis has finished. Sending results to Gerrit."); 76 | reviewInput.setMessage(MessageUtils.createMessage(gerritConfiguration.getMessage(), settings)); 77 | 78 | LOG.debug("[GERRIT PLUGIN] Define message : {}", reviewInput.getMessage()); 79 | LOG.debug("[GERRIT PLUGIN] Number of comments : {}", reviewInput.size()); 80 | 81 | int maxLevel = reviewInput.maxLevelSeverity(); 82 | LOG.debug("[GERRIT PLUGIN] Configured threshold {}, max review level {}", 83 | gerritConfiguration.getThreshold(), ReviewUtils.valueToThreshold(maxLevel)); 84 | 85 | if (reviewInput.isEmpty()) { 86 | LOG.debug("[GERRIT PLUGIN] No issues ! Vote {} for the label : {}", 87 | gerritConfiguration.getVoteNoIssue(), gerritConfiguration.getLabel()); 88 | reviewInput.setValueAndLabel(gerritConfiguration.getVoteNoIssue(), gerritConfiguration.getLabel()); 89 | } else if (maxLevel < ReviewUtils.thresholdToValue(gerritConfiguration.getThreshold())) { 90 | LOG.debug("[GERRIT PLUGIN] Issues below threshold. Vote {} for the label : {}", 91 | gerritConfiguration.getVoteBelowThreshold(), gerritConfiguration.getLabel()); 92 | reviewInput.setValueAndLabel(gerritConfiguration.getVoteBelowThreshold(), 93 | gerritConfiguration.getLabel()); 94 | } else { 95 | LOG.debug("[GERRIT PLUGIN] Issues above threshold. Vote {} for the label : {}", 96 | gerritConfiguration.getVoteAboveThreshold(), gerritConfiguration.getLabel()); 97 | reviewInput.setValueAndLabel(gerritConfiguration.getVoteAboveThreshold(), 98 | gerritConfiguration.getLabel()); 99 | } 100 | 101 | LOG.debug("[GERRIT PLUGIN] Send review for ChangeId={}, RevisionId={}", gerritConfiguration.getChangeId(), 102 | gerritConfiguration.getRevisionId()); 103 | 104 | gerritFacade.setReview(reviewInput); 105 | 106 | } catch (GerritPluginException e) { 107 | LOG.error("[GERRIT PLUGIN] Error sending review to Gerrit", e); 108 | } 109 | } 110 | 111 | protected void decorate(InputPath resource, PostJobContext context, Collection issues) { 112 | LOG.debug("[GERRIT PLUGIN] Decorate: {}", resource.relativePath()); 113 | if (!resource.file().isFile()) { 114 | LOG.debug("[GERRIT PLUGIN] {} is not a file", resource.relativePath()); 115 | return; 116 | } 117 | 118 | try { 119 | LOG.debug("[GERRIT PLUGIN] Start Sonar decoration for Gerrit"); 120 | assertOrFetchGerritModifiedFiles(); 121 | } catch (GerritPluginException e) { 122 | LOG.error("[GERRIT PLUGIN] Error getting Gerrit datas", e); 123 | return; 124 | } 125 | 126 | LOG.debug("[GERRIT PLUGIN] Look for in Gerrit if the file was under review, resource={}", resource); 127 | LOG.debug("[GERRIT PLUGIN] Look for in Gerrit if the file was under review, name={}", resource.relativePath()); 128 | LOG.debug("[GERRIT PLUGIN] Look for in Gerrit if the file was under review, key={}", resource.key()); 129 | 130 | String filename = getFileNameFromInputPath(resource); 131 | if (filename != null) { 132 | LOG.info("[GERRIT PLUGIN] Found a match between Sonar and Gerrit for {}: ", resource.relativePath(), 133 | filename); 134 | processFileResource(filename, issues); 135 | } 136 | } 137 | 138 | protected void assertOrFetchGerritModifiedFiles() throws GerritPluginException { 139 | if (gerritModifiedFiles != null) { 140 | return; 141 | } 142 | gerritModifiedFiles = gerritFacade.listFiles(); 143 | LOG.debug("[GERRIT PLUGIN] Modified files in gerrit : {}", gerritModifiedFiles); 144 | } 145 | 146 | protected ReviewLineComment issueToComment(PostJobIssue issue) { 147 | ReviewLineComment result = new ReviewLineComment(); 148 | 149 | result.setLine(issue.line()); 150 | result.setSeverity(ReviewUtils.thresholdToValue(issue.severity().toString())); 151 | 152 | result.setMessage(MessageUtils.createIssueMessage(gerritConfiguration.getIssueComment(), settings, issue)); 153 | LOG.debug("[GERRIT PLUGIN] issueToComment {}", result.toString()); 154 | return result; 155 | } 156 | 157 | protected void processFileResource(@NotNull String file, @NotNull Collection issuable) { 158 | List comments = new ArrayList<>(); 159 | commentIssues(issuable, comments); 160 | if (!comments.isEmpty()) { 161 | reviewInput.addComments(file, comments); 162 | } 163 | } 164 | 165 | private void commentIssues(Collection issues, List comments) { 166 | LOG.info("[GERRIT PLUGIN] Found {} issues", issues.size()); 167 | 168 | for (PostJobIssue issue : issues) { 169 | if (gerritConfiguration.shouldCommentNewIssuesOnly() && !issue.isNew()) { 170 | LOG.info( 171 | "[GERRIT PLUGIN] Issue is not new and only new one should be commented. Will not push back to Gerrit. Issue: {}", issue); 172 | } else { 173 | comments.add(issueToComment(issue)); 174 | } 175 | } 176 | } 177 | 178 | private String getFileNameFromInputPath(InputPath resource) { 179 | String filename = null; 180 | if (gerritModifiedFiles.contains(resource.relativePath())) { 181 | LOG.info("[GERRIT PLUGIN] Found a match between Sonar and Gerrit for {}", resource.relativePath()); 182 | filename = resource.relativePath(); 183 | } else if (gerritModifiedFiles.contains(gerritFacade.parseFileName(resource.relativePath()))) { 184 | LOG.info("[GERRIT PLUGIN] Found a match between Sonar and Gerrit for {}", 185 | gerritFacade.parseFileName(resource.relativePath())); 186 | filename = gerritFacade.parseFileName(resource.relativePath()); 187 | } else { 188 | LOG.debug("[GERRIT PLUGIN] Parse the Gerrit List to look for the resource: {}", resource.relativePath()); 189 | // Loop on each item 190 | for (String fileGerrit : gerritModifiedFiles) { 191 | if (gerritFacade.parseFileName(fileGerrit).equals(resource.relativePath())) { 192 | filename = fileGerrit; 193 | break; 194 | } 195 | } 196 | } 197 | if (filename == null) { 198 | LOG.debug("[GERRIT PLUGIN] File '{}' was not found in the review list)", resource.relativePath()); 199 | LOG.debug("[GERRIT PLUGIN] Try to find with: '{}', '{}' and '{}'", resource.relativePath(), 200 | gerritFacade.parseFileName(resource.relativePath())); 201 | } 202 | return filename; 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /src/main/java/fr/techad/sonar/GerritProjectBuilder.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar; 2 | 3 | import fr.techad.sonar.gerrit.GerritFacade; 4 | import fr.techad.sonar.gerrit.factory.GerritFacadeFactory; 5 | import fr.techad.sonar.gerrit.review.ReviewInput; 6 | import org.sonar.api.batch.bootstrap.ProjectBuilder; 7 | import org.sonar.api.utils.log.Logger; 8 | import org.sonar.api.utils.log.Loggers; 9 | 10 | public class GerritProjectBuilder extends ProjectBuilder { 11 | private static final Logger LOG = Loggers.get(GerritProjectBuilder.class); 12 | private final GerritConfiguration gerritConfiguration; 13 | private final GerritFacade gerritFacade; 14 | 15 | public GerritProjectBuilder(GerritConfiguration gerritConfiguration, GerritFacadeFactory gerritFacadeFactory) { 16 | LOG.debug("[GERRIT PLUGIN] Instanciating GerritProjectBuilder"); 17 | this.gerritConfiguration = gerritConfiguration; 18 | this.gerritFacade = gerritFacadeFactory.getFacade(); 19 | } 20 | 21 | @Override 22 | public void build(Context context) { 23 | if (!gerritConfiguration.isEnabled()) { 24 | LOG.error("[GERRIT PLUGIN] Plugin is disabled. Wont send."); 25 | return; 26 | } 27 | 28 | if (!gerritConfiguration.isValid()) { 29 | LOG.error("[GERRIT PLUGIN] Configuration is invalid. Wont send."); 30 | return; 31 | } 32 | 33 | ReviewInput ri = new ReviewInput(); 34 | ri.setValueAndLabel(0, gerritConfiguration.getLabel()); 35 | ri.setMessage("Sonar review in progress …"); 36 | 37 | try { 38 | gerritFacade.setReview(ri); 39 | } catch (GerritPluginException e) { 40 | LOG.error("[GERRIT PLUGIN] Sending initial status failed", e); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/fr/techad/sonar/PropertyKey.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar; 2 | 3 | public final class PropertyKey { 4 | public static final String GERRIT_ENABLED = "GERRIT_ENABLED"; 5 | public static final String GERRIT_SCHEME = "GERRIT_SCHEME"; 6 | public static final String GERRIT_HOST = "GERRIT_HOST"; 7 | public static final String GERRIT_PORT = "GERRIT_PORT"; 8 | public static final String GERRIT_PROJECT = "GERRIT_PROJECT"; 9 | public static final String GERRIT_BRANCH = "GERRIT_BRANCH"; 10 | public static final String GERRIT_CHANGE_ID = "GERRIT_CHANGE_ID"; 11 | public static final String GERRIT_REVISION_ID = "GERRIT_PATCHSET_REVISION"; 12 | public static final String GERRIT_USERNAME = "GERRIT_USERNAME"; 13 | public static final String GERRIT_PASSWORD = "GERRIT_PASSWORD"; // NOSONAR 14 | public static final String GERRIT_SSH_KEY_PATH = "GERRIT_SSH_KEY_PATH"; 15 | public static final String GERRIT_HTTP_AUTH_SCHEME = "GERRIT_HTTP_AUTH_SCHEME"; 16 | public static final String GERRIT_LABEL = "GERRIT_LABEL"; 17 | public static final String GERRIT_MESSAGE = "GERRIT_MESSAGE"; 18 | public static final String GERRIT_BASE_PATH = "GERRIT_BASE_PATH"; 19 | public static final String GERRIT_THRESHOLD = "GERRIT_THRESHOLD"; 20 | public static final String GERRIT_FORCE_BRANCH = "GERRIT_FORCE_BRANCH"; 21 | public static final String GERRIT_COMMENT_NEW_ISSUES_ONLY = "GERRIT_COMMENT_NEW_ISSUES_ONLY"; 22 | public static final String GERRIT_VOTE_NO_ISSUE = "GERRIT_VOTE_NO_ISSUE"; 23 | public static final String GERRIT_VOTE_ISSUE_BELOW_THRESHOLD = "GERRIT_VOTE_ISSUE_BELOW_THRESHOLD"; 24 | public static final String GERRIT_VOTE_ISSUE_ABOVE_THRESHOLD = "GERRIT_VOTE_ISSUE_ABOVE_THRESHOLD"; 25 | public static final String GERRIT_ISSUE_COMMENT = "GERRIT_ISSUE_COMMENT"; 26 | public static final String GERRIT_STRICT_HOSTKEY = "GERRIT_STRICT_HOSTKEY"; 27 | 28 | private PropertyKey() { 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/fr/techad/sonar/ReviewHolder.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar; 2 | 3 | import fr.techad.sonar.gerrit.review.ReviewInput; 4 | 5 | public final class ReviewHolder { 6 | private static ReviewInput reviewInput = new ReviewInput(); 7 | 8 | private ReviewHolder() { 9 | } 10 | 11 | public static ReviewInput getReviewInput() { 12 | return reviewInput; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/fr/techad/sonar/gerrit/GerritConnector.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.gerrit; 2 | 3 | import java.io.IOException; 4 | 5 | public interface GerritConnector { 6 | public String listFiles() throws IOException; 7 | 8 | public String setReview(String reviewInputAsJson) throws IOException; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/fr/techad/sonar/gerrit/GerritFacade.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.gerrit; 2 | 3 | import com.google.gson.stream.JsonWriter; 4 | import fr.techad.sonar.GerritPluginException; 5 | import fr.techad.sonar.gerrit.review.ReviewFileComment; 6 | import fr.techad.sonar.gerrit.review.ReviewInput; 7 | import fr.techad.sonar.gerrit.review.ReviewLineComment; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.sonar.api.utils.log.Logger; 10 | import org.sonar.api.utils.log.Loggers; 11 | 12 | import java.io.IOException; 13 | import java.io.StringWriter; 14 | import java.util.ArrayList; 15 | import java.util.Collections; 16 | import java.util.List; 17 | 18 | public abstract class GerritFacade { 19 | private static final Logger LOG = Loggers.get(GerritFacade.class); 20 | private static final String MAVEN_ENTRY_REGEX = ".*?/?src/"; 21 | private static final String ERROR_FORMAT = "Error formatting review"; 22 | private static final String ERROR_SETTING = "Error setting review"; 23 | private static final String COMMIT_MSG = "/COMMIT_MSG"; 24 | 25 | private final GerritConnector gerritConnector; 26 | private List gerritFileList = new ArrayList<>(); 27 | 28 | public GerritFacade(GerritConnector gerritConnector) { 29 | LOG.debug("[GERRIT PLUGIN] Instanciating GerritFacade"); 30 | this.gerritConnector = gerritConnector; 31 | } 32 | 33 | @NotNull 34 | public List listFiles() throws GerritPluginException { 35 | if (!gerritFileList.isEmpty()) { 36 | LOG.debug("[GERRIT PLUGIN] File list already filled. Not calling Gerrit."); 37 | } else { 38 | fillListFilesFromGerrit(); 39 | } 40 | return Collections.unmodifiableList(gerritFileList); 41 | } 42 | 43 | public void setReview(@NotNull ReviewInput reviewInput) throws GerritPluginException { 44 | try { 45 | gerritConnector.setReview(formatReview(reviewInput)); 46 | } catch (IOException e) { 47 | throw new GerritPluginException(ERROR_SETTING, e); 48 | } 49 | } 50 | 51 | public String parseFileName(@NotNull String fileName) { 52 | LOG.debug("[GERRIT PLUGIN] parse filename: {}.", fileName); 53 | return fileName.replaceFirst(MAVEN_ENTRY_REGEX, "src/"); 54 | } 55 | 56 | protected GerritConnector getGerritConnector() { 57 | return this.gerritConnector; 58 | } 59 | 60 | protected void addFile(String fileName) { 61 | if (COMMIT_MSG.equals(fileName)) { 62 | LOG.debug("[GERRIT PLUGIN] File is commit message, not adding"); 63 | } else { 64 | gerritFileList.add(fileName); 65 | } 66 | } 67 | 68 | protected abstract void fillListFilesFromGerrit() throws GerritPluginException; 69 | 70 | @NotNull 71 | private String formatReview(ReviewInput reviewInput) throws GerritPluginException { 72 | StringWriter stringWriter = new StringWriter(); 73 | JsonWriter jsonWriter = new JsonWriter(stringWriter); 74 | 75 | try { 76 | jsonWriter.beginObject(); 77 | jsonWriter.name("message").value(reviewInput.getMessage()); 78 | 79 | if (!reviewInput.getLabels().isEmpty()) { 80 | jsonWriter.name("labels").beginObject(); 81 | for (String label : reviewInput.getLabels().keySet()) { 82 | jsonWriter.name(label).value(reviewInput.getLabels().get(label)); 83 | } 84 | jsonWriter.endObject(); 85 | } 86 | 87 | if (!reviewInput.getComments().isEmpty()) { 88 | jsonWriter.name("comments").beginObject(); 89 | for (String fileName : reviewInput.getComments().keySet()) { 90 | if (!reviewInput.getComments().isEmpty()) { 91 | jsonWriter.name(fileName).beginArray(); 92 | for (ReviewFileComment rfc : reviewInput.getComments().get(fileName)) { 93 | jsonWriter.beginObject(); 94 | jsonWriter.name("line").value(((ReviewLineComment) rfc).getLine()); 95 | jsonWriter.name("message").value(rfc.getMessage()); 96 | jsonWriter.endObject(); 97 | } 98 | jsonWriter.endArray(); 99 | } 100 | } 101 | jsonWriter.endObject(); 102 | } 103 | jsonWriter.endObject(); 104 | jsonWriter.close(); 105 | } catch (IOException e) { 106 | throw new GerritPluginException(ERROR_FORMAT, e); 107 | } 108 | 109 | return stringWriter.toString(); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/fr/techad/sonar/gerrit/factory/GerritConnectorFactory.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.gerrit.factory; 2 | 3 | import fr.techad.sonar.GerritConfiguration; 4 | import fr.techad.sonar.GerritConstants; 5 | import fr.techad.sonar.gerrit.GerritConnector; 6 | import fr.techad.sonar.gerrit.network.rest.GerritRestConnector; 7 | import fr.techad.sonar.gerrit.network.ssh.GerritSshConnector; 8 | import org.sonar.api.batch.InstantiationStrategy; 9 | import org.sonar.api.batch.ScannerSide; 10 | import org.sonar.api.utils.log.Logger; 11 | import org.sonar.api.utils.log.Loggers; 12 | 13 | @ScannerSide 14 | @InstantiationStrategy(InstantiationStrategy.PER_BATCH) 15 | public class GerritConnectorFactory { 16 | private static final Logger LOG = Loggers.get(GerritConnectorFactory.class); 17 | 18 | GerritConfiguration gerritConfiguration; 19 | GerritConnector gerritConnector; 20 | 21 | public GerritConnectorFactory(GerritConfiguration gerritConfiguration) { 22 | this.gerritConfiguration = gerritConfiguration; 23 | 24 | if (gerritConfiguration.getScheme().startsWith(GerritConstants.SCHEME_HTTP)) { 25 | LOG.debug("[GERRIT PLUGIN] Using REST connector."); 26 | gerritConnector = new GerritRestConnector(gerritConfiguration); 27 | } else if (gerritConfiguration.getScheme().equals(GerritConstants.SCHEME_SSH)) { 28 | LOG.debug("[GERRIT PLUGIN] Using SSH connector."); 29 | gerritConnector = new GerritSshConnector(gerritConfiguration); 30 | } else { 31 | LOG.error("[GERRIT PLUGIN] Unknown scheme."); 32 | } 33 | } 34 | 35 | public GerritConnector getConnector() { 36 | return gerritConnector; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/fr/techad/sonar/gerrit/factory/GerritFacadeFactory.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.gerrit.factory; 2 | 3 | import fr.techad.sonar.gerrit.GerritConnector; 4 | import fr.techad.sonar.gerrit.GerritFacade; 5 | import fr.techad.sonar.gerrit.network.rest.GerritRestConnector; 6 | import fr.techad.sonar.gerrit.network.rest.GerritRestFacade; 7 | import fr.techad.sonar.gerrit.network.ssh.GerritSshConnector; 8 | import fr.techad.sonar.gerrit.network.ssh.GerritSshFacade; 9 | import org.sonar.api.batch.InstantiationStrategy; 10 | import org.sonar.api.batch.ScannerSide; 11 | import org.sonar.api.utils.log.Logger; 12 | import org.sonar.api.utils.log.Loggers; 13 | 14 | @ScannerSide 15 | @InstantiationStrategy(InstantiationStrategy.PER_BATCH) 16 | public class GerritFacadeFactory { 17 | private static final Logger LOG = Loggers.get(GerritFacadeFactory.class); 18 | 19 | private GerritFacade gerritFacade; 20 | 21 | public GerritFacadeFactory(GerritConnectorFactory gerritConnectorFactory) { 22 | GerritConnector gerritConnector = gerritConnectorFactory.getConnector(); 23 | if (gerritConnector instanceof GerritRestConnector) { 24 | LOG.debug("[GERRIT PLUGIN] Using REST connector."); 25 | gerritFacade = new GerritRestFacade(gerritConnector); 26 | } else if (gerritConnector instanceof GerritSshConnector) { 27 | LOG.debug("[GERRIT PLUGIN] Using SSH facade."); 28 | gerritFacade = new GerritSshFacade(gerritConnector); 29 | } else { 30 | LOG.error("[GERRIT PLUGIN] Unknown type of connector. Cannot assign facade."); 31 | } 32 | } 33 | 34 | public GerritFacade getFacade() { 35 | return gerritFacade; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/fr/techad/sonar/gerrit/network/rest/GerritRestConnector.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.gerrit.network.rest; 2 | 3 | import fr.techad.sonar.GerritConfiguration; 4 | import fr.techad.sonar.GerritConstants; 5 | import fr.techad.sonar.gerrit.GerritConnector; 6 | import org.apache.commons.lang3.StringUtils; 7 | import org.apache.http.HttpHost; 8 | import org.apache.http.auth.AuthScheme; 9 | import org.apache.http.auth.AuthScope; 10 | import org.apache.http.auth.UsernamePasswordCredentials; 11 | import org.apache.http.client.CredentialsProvider; 12 | import org.apache.http.client.methods.CloseableHttpResponse; 13 | import org.apache.http.client.methods.HttpGet; 14 | import org.apache.http.client.methods.HttpPost; 15 | import org.apache.http.client.methods.HttpRequestBase; 16 | import org.apache.http.client.protocol.HttpClientContext; 17 | import org.apache.http.entity.ContentType; 18 | import org.apache.http.entity.StringEntity; 19 | import org.apache.http.impl.auth.BasicScheme; 20 | import org.apache.http.impl.auth.DigestScheme; 21 | import org.apache.http.impl.client.BasicAuthCache; 22 | import org.apache.http.impl.client.BasicCredentialsProvider; 23 | import org.apache.http.impl.client.CloseableHttpClient; 24 | import org.apache.http.impl.client.HttpClients; 25 | import org.apache.http.util.EntityUtils; 26 | import org.jetbrains.annotations.NotNull; 27 | import org.sonar.api.utils.log.Logger; 28 | import org.sonar.api.utils.log.Loggers; 29 | 30 | import java.io.IOException; 31 | import java.io.UnsupportedEncodingException; 32 | import java.net.URLEncoder; 33 | 34 | public class GerritRestConnector implements GerritConnector { 35 | private static final Logger LOG = Loggers.get(GerritRestConnector.class); 36 | private static final String URI_AUTH_PREFIX = "/a"; 37 | private static final String URI_CHANGES = "/changes/%s~%s~%s"; 38 | private static final String URI_REVISIONS = "/revisions/%s"; 39 | private static final String URI_LIST_FILES_SUFFIX = "/files/"; 40 | private static final String URI_SET_REVIEW = "/review"; 41 | private final GerritConfiguration gerritConfiguration; 42 | private HttpHost httpHost; 43 | private CloseableHttpClient httpClient; 44 | private HttpClientContext httpClientContext; 45 | 46 | public GerritRestConnector(GerritConfiguration gerritConfiguration) { 47 | LOG.debug("[GERRIT PLUGIN] Instanciating GerritConnector"); 48 | this.gerritConfiguration = gerritConfiguration; 49 | } 50 | 51 | @NotNull 52 | @Override 53 | public String listFiles() throws IOException { 54 | String getUri = rootUriBuilder(); 55 | getUri = getUri.concat(URI_LIST_FILES_SUFFIX); 56 | 57 | LOG.info("[GERRIT PLUGIN] Listing files from {}", getUri); 58 | 59 | HttpGet httpGet = new HttpGet(getUri); 60 | httpGet.addHeader("Accept", "application/json"); 61 | CloseableHttpResponse httpResponse = logAndExecute(httpGet); 62 | return consumeAndLogEntity(httpResponse); 63 | } 64 | 65 | @NotNull 66 | @Override 67 | public String setReview(String reviewInputAsJson) throws IOException { 68 | LOG.info("[GERRIT PLUGIN] Setting review {}", reviewInputAsJson); 69 | 70 | String postUri = rootUriBuilder(); 71 | postUri = postUri.concat(URI_SET_REVIEW); 72 | 73 | LOG.info("[GERRIT PLUGIN] Setting review at {}", postUri); 74 | 75 | HttpPost httpPost = new HttpPost(postUri); 76 | httpPost.setEntity(new StringEntity(reviewInputAsJson, ContentType.APPLICATION_JSON)); 77 | 78 | CloseableHttpResponse httpResponse = logAndExecute(httpPost); 79 | return consumeAndLogEntity(httpResponse); 80 | } 81 | 82 | // Example 83 | // http://hc.apache.org/httpcomponents-client-ga/httpclient/examples/org/apache/http/examples/client/ClientPreemptiveDigestAuthentication.java 84 | private void createHttpContext() { 85 | httpHost = new HttpHost(gerritConfiguration.getHost(), gerritConfiguration.getPort(), 86 | gerritConfiguration.getScheme()); 87 | httpClientContext = HttpClientContext.create(); 88 | 89 | if (gerritConfiguration.isAnonymous()) { 90 | httpClient = HttpClients.createDefault(); 91 | } else { 92 | CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); 93 | credentialsProvider.setCredentials( 94 | new AuthScope(gerritConfiguration.getHost(), gerritConfiguration.getPort()), 95 | new UsernamePasswordCredentials(gerritConfiguration.getUsername(), 96 | gerritConfiguration.getPassword())); 97 | httpClient = HttpClients.custom().setDefaultCredentialsProvider(credentialsProvider).build(); 98 | 99 | BasicAuthCache basicAuthCache = new BasicAuthCache(); 100 | AuthScheme authScheme = null; 101 | 102 | if (GerritConstants.AUTH_BASIC.equalsIgnoreCase(gerritConfiguration.getHttpAuthScheme())) { 103 | authScheme = new BasicScheme(); 104 | } else if (GerritConstants.AUTH_DIGEST.equalsIgnoreCase(gerritConfiguration.getHttpAuthScheme())) { 105 | authScheme = new DigestScheme(); 106 | 107 | } else { 108 | LOG.error("[GERRIT PLUGIN] createHttpContext called with AUTH_SCHEME {} instead of digest or basic", 109 | gerritConfiguration.getHttpAuthScheme()); 110 | } 111 | basicAuthCache.put(httpHost, authScheme); 112 | httpClientContext.setAuthCache(basicAuthCache); 113 | } 114 | } 115 | 116 | @NotNull 117 | private CloseableHttpResponse logAndExecute(@NotNull HttpRequestBase request) throws IOException { 118 | if (null == httpClient || null == httpClientContext || null == httpHost) { 119 | createHttpContext(); 120 | } 121 | 122 | LOG.info("[GERRIT PLUGIN] Request {} to {}", request.getMethod(), request.getURI().toString()); 123 | CloseableHttpResponse httpResponse = httpClient.execute(httpHost, request, httpClientContext); 124 | LOG.info("[GERRIT PLUGIN] Response {}", httpResponse.getStatusLine().toString()); 125 | return httpResponse; 126 | } 127 | 128 | @NotNull 129 | private String consumeAndLogEntity(@NotNull CloseableHttpResponse response) throws IOException { 130 | if (response.getEntity() == null) { 131 | LOG.debug("[GERRIT PLUGIN] Entity : no entity"); 132 | return StringUtils.EMPTY; 133 | } 134 | String content = EntityUtils.toString(response.getEntity()); 135 | LOG.info("[GERRIT PLUGIN] Entity : {}", content); 136 | return content; 137 | } 138 | 139 | @NotNull 140 | private String encode(String content) { 141 | String result = ""; 142 | try { 143 | result = URLEncoder.encode(content, "UTF-8"); 144 | } catch (UnsupportedEncodingException e) { 145 | LOG.error("[GERRIT PLUGIN] Error during encodage", e); 146 | } catch (NullPointerException npe) { 147 | LOG.warn("[GERRIT PLUGIN] Could not encode. Is content empty ?"); 148 | } 149 | return result; 150 | } 151 | 152 | @NotNull 153 | public String rootUriBuilder() { 154 | String basePath = gerritConfiguration.getBasePath(); 155 | if ("/".compareTo(basePath) == 0) { 156 | basePath = ""; 157 | } 158 | 159 | String uri = basePath; 160 | if (!gerritConfiguration.isAnonymous()) { 161 | uri = uri.concat(URI_AUTH_PREFIX); 162 | } 163 | uri = uri.concat(String.format(URI_CHANGES, encode(gerritConfiguration.getProjectName()), 164 | encode(gerritConfiguration.getBranchName()), encode(gerritConfiguration.getChangeId()))); 165 | uri = uri.concat(String.format(URI_REVISIONS, encode(gerritConfiguration.getRevisionId()))); 166 | 167 | LOG.debug("[GERRIT PLUGIN] Built URI : {}", uri); 168 | 169 | return uri; 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /src/main/java/fr/techad/sonar/gerrit/network/rest/GerritRestFacade.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.gerrit.network.rest; 2 | 3 | import com.google.gson.JsonElement; 4 | import com.google.gson.JsonObject; 5 | import com.google.gson.JsonParser; 6 | import fr.techad.sonar.GerritPluginException; 7 | import fr.techad.sonar.gerrit.GerritConnector; 8 | import fr.techad.sonar.gerrit.GerritFacade; 9 | import org.apache.commons.lang3.StringUtils; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.sonar.api.utils.log.Logger; 12 | import org.sonar.api.utils.log.Loggers; 13 | 14 | import java.io.IOException; 15 | import java.util.Map.Entry; 16 | 17 | public class GerritRestFacade extends GerritFacade { 18 | private static final Logger LOG = Loggers.get(GerritRestFacade.class); 19 | private static final String JSON_RESPONSE_PREFIX = ")]}'"; 20 | private static final String ERROR_LISTING = "Error listing files"; 21 | 22 | public GerritRestFacade(GerritConnector gerritConnector) { 23 | super(gerritConnector); 24 | LOG.debug("[GERRIT PLUGIN] Instanciating GerritRestFacade"); 25 | } 26 | 27 | @Override 28 | protected void fillListFilesFromGerrit() throws GerritPluginException { 29 | try { 30 | String rawJsonString = getGerritConnector().listFiles(); 31 | String jsonString = trimResponse(rawJsonString); 32 | JsonElement rootJsonElement = new JsonParser().parse(jsonString); 33 | for (Entry fileList : rootJsonElement.getAsJsonObject().entrySet()) { 34 | JsonObject jsonObject = fileList.getValue().getAsJsonObject(); 35 | if (jsonObject.has("status") && isMarkAsDeleted(jsonObject)) { 36 | LOG.debug("[GERRIT PLUGIN] File is marked as deleted, won't comment."); 37 | continue; 38 | } 39 | 40 | addFile(fileList.getKey()); 41 | } 42 | } catch (IOException e) { 43 | throw new GerritPluginException(ERROR_LISTING, e); 44 | } 45 | } 46 | 47 | @NotNull 48 | private String trimResponse(@NotNull String response) { 49 | return StringUtils.replaceOnce(response, JSON_RESPONSE_PREFIX, ""); 50 | } 51 | 52 | private boolean isMarkAsDeleted(JsonObject jsonObject) { 53 | return jsonObject.get("status").getAsCharacter() == 'D'; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/fr/techad/sonar/gerrit/network/ssh/GerritSshConnector.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.gerrit.network.ssh; 2 | 3 | import fi.jpalomaki.ssh.Result; 4 | import fi.jpalomaki.ssh.SshClient; 5 | import fi.jpalomaki.ssh.UserAtHost; 6 | import fi.jpalomaki.ssh.jsch.JschSshClient; 7 | import fi.jpalomaki.ssh.jsch.JschSshClient.Options; 8 | import fr.techad.sonar.GerritConfiguration; 9 | import fr.techad.sonar.gerrit.GerritConnector; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.sonar.api.utils.log.Logger; 12 | import org.sonar.api.utils.log.Loggers; 13 | 14 | import java.io.File; 15 | import java.io.IOException; 16 | import java.nio.ByteBuffer; 17 | import java.nio.file.Files; 18 | import java.nio.file.LinkOption; 19 | import java.nio.file.Paths; 20 | 21 | public class GerritSshConnector implements GerritConnector { 22 | private static final Logger LOG = Loggers.get(GerritSshConnector.class); 23 | private static final String CMD_LIST_FILES = "gerrit query --format=JSON --files --current-patch-set status:open change:%s limit:1"; 24 | private static final String CMD_SET_REVIEW = "gerrit review %s -j"; 25 | private static final String SSH_KNWON_HOSTS = ".ssh/known_hosts"; 26 | private static final String SSH_STRICT_NO = "StrictHostKeyChecking=no"; 27 | 28 | private final GerritConfiguration gerritConfiguration; 29 | private final UserAtHost userAtHost; 30 | 31 | public GerritSshConnector(GerritConfiguration gerritConfiguration) { 32 | LOG.debug("[GERRIT PLUGIN] Instanciating GerritSshConnector"); 33 | this.gerritConfiguration = gerritConfiguration; 34 | userAtHost = new UserAtHost(gerritConfiguration.getUsername(), gerritConfiguration.getHost(), 35 | gerritConfiguration.getPort()); 36 | } 37 | 38 | @NotNull 39 | @Override 40 | public String listFiles() throws IOException { 41 | SshClient sshClient = getSshClient(); 42 | 43 | LOG.debug("[GERRIT PLUGIN] Execute command SSH {}", 44 | String.format(CMD_LIST_FILES, gerritConfiguration.getChangeId())); 45 | 46 | Result cmdResult = sshClient.executeCommand(String.format(CMD_LIST_FILES, gerritConfiguration.getChangeId()), 47 | userAtHost); 48 | 49 | return cmdResult.stdoutAsText("UTF-8"); 50 | } 51 | 52 | @NotNull 53 | @Override 54 | public String setReview(String reviewInputAsJson) throws IOException { 55 | LOG.info("[GERRIT PLUGIN] Setting review {}", reviewInputAsJson); 56 | 57 | ByteBuffer stdin = ByteBuffer.wrap(reviewInputAsJson.getBytes("UTF-8")); 58 | SshClient sshClient = getSshClient(); 59 | LOG.debug("[GERRIT PLUGIN] Execute command SSH {}", 60 | String.format(CMD_SET_REVIEW, gerritConfiguration.getRevisionId())); 61 | 62 | Result cmdResult = sshClient.executeCommand(String.format(CMD_SET_REVIEW, gerritConfiguration.getRevisionId()), 63 | stdin, userAtHost); 64 | 65 | return cmdResult.stdoutAsText(); 66 | } 67 | 68 | private SshClient getSshClient() { 69 | SshClient sc = null; 70 | 71 | if (gerritConfiguration.shouldStrictlyCheckHostKey()) { 72 | LOG.debug("[GERRIT PLUGIN] SSH will check host key."); 73 | sc = new JschSshClient(gerritConfiguration.getSshKeyPath(), gerritConfiguration.getPassword()); 74 | } else { 75 | LOG.debug("[GERRIT PLUGIN] SSH will not check host key."); 76 | String userKnownHosts = System.getProperty("user.home") + File.separator + SSH_KNWON_HOSTS; 77 | Boolean knownHostsExists = Files.exists(Paths.get(userKnownHosts), LinkOption.NOFOLLOW_LINKS); 78 | 79 | if (!knownHostsExists) { 80 | LOG.debug("[GERRIT PLUGIN] {} does not exist. Creating.", userKnownHosts); 81 | // known_hosts DOES NOT exists => create it 82 | try { 83 | Files.createFile(Paths.get(userKnownHosts)); 84 | } catch (IOException e) { 85 | LOG.warn("[GERRIT PLUGIN] Could not create known_hosts", e); 86 | } 87 | LOG.debug("[GERRIT PLUGIN] {} created.", userKnownHosts); 88 | } 89 | 90 | sc = new JschSshClient(gerritConfiguration.getSshKeyPath(), gerritConfiguration.getPassword(), 91 | userKnownHosts, new Options("5s", "0s", "1M", "1M", SSH_STRICT_NO, false)); 92 | } 93 | 94 | return sc; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/fr/techad/sonar/gerrit/network/ssh/GerritSshFacade.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.gerrit.network.ssh; 2 | 3 | import com.google.gson.JsonArray; 4 | import com.google.gson.JsonElement; 5 | import com.google.gson.JsonObject; 6 | import com.google.gson.JsonParser; 7 | import fr.techad.sonar.GerritPluginException; 8 | import fr.techad.sonar.gerrit.GerritConnector; 9 | import fr.techad.sonar.gerrit.GerritFacade; 10 | import org.sonar.api.utils.log.Logger; 11 | import org.sonar.api.utils.log.Loggers; 12 | 13 | import java.io.IOException; 14 | 15 | public class GerritSshFacade extends GerritFacade { 16 | private static final Logger LOG = Loggers.get(GerritSshFacade.class); 17 | private static final String ERROR_LISTING = "Error listing files"; 18 | 19 | public GerritSshFacade(GerritConnector gerritConnector) { 20 | super(gerritConnector); 21 | LOG.debug("[GERRIT PLUGIN] Instanciating GerritSshFacade"); 22 | } 23 | 24 | @Override 25 | protected void fillListFilesFromGerrit() throws GerritPluginException { 26 | try { 27 | String rawJsonString = getGerritConnector().listFiles(); 28 | JsonArray files = new JsonParser().parse(rawJsonString.split("\r?\n")[0]).getAsJsonObject() 29 | .getAsJsonObject("currentPatchSet").getAsJsonArray("files"); 30 | 31 | for (JsonElement jsonElement : files) { 32 | JsonObject jsonObject = jsonElement.getAsJsonObject(); 33 | 34 | if (jsonObject.has("type") && isMarkAsDeleted(jsonObject)) { 35 | LOG.debug("[GERRIT PLUGIN] File is marked as deleted, won't comment."); 36 | continue; 37 | } 38 | 39 | addFile(jsonObject.get("file").getAsString()); 40 | } 41 | } catch (IOException e) { 42 | throw new GerritPluginException(ERROR_LISTING, e); 43 | } 44 | } 45 | 46 | private boolean isMarkAsDeleted(JsonObject jsonObject) { 47 | return "DELETED".equals(jsonObject.get("type").getAsString()); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/fr/techad/sonar/gerrit/review/ReviewFileComment.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.gerrit.review; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.sonar.api.utils.log.Logger; 5 | import org.sonar.api.utils.log.Loggers; 6 | 7 | import java.util.Objects; 8 | 9 | /** 10 | * Gerrit comment used with request for review input. Used with JSON marshaller 11 | * only. 12 | */ 13 | public class ReviewFileComment { 14 | private static final Logger LOG = Loggers.get(ReviewFileComment.class); 15 | 16 | private String message; 17 | private int severity; 18 | 19 | public String getMessage() { 20 | return message; 21 | } 22 | 23 | public void setMessage(String message) { 24 | LOG.debug("[GERRIT PLUGIN] ReviewFileComment setMessage {}", message); 25 | this.message = message; 26 | if (Objects.isNull(this.message)) 27 | this.message = StringUtils.EMPTY; 28 | } 29 | 30 | public int getSeverity() { 31 | return severity; 32 | } 33 | 34 | public void setSeverity(int severity) { 35 | this.severity = severity; 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return "ReviewFileComment [" + "message:" + message + ", " + "severity: " + severity + "]"; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/fr/techad/sonar/gerrit/review/ReviewInput.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.gerrit.review; 2 | 3 | import fr.techad.sonar.gerrit.utils.ReviewUtils; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.sonar.api.utils.log.Logger; 6 | import org.sonar.api.utils.log.Loggers; 7 | 8 | import java.util.ArrayList; 9 | import java.util.Iterator; 10 | import java.util.List; 11 | import java.util.Map; 12 | import java.util.concurrent.ConcurrentHashMap; 13 | 14 | /** 15 | * Gerrit request for review input. Used with JSON marshaller only. 16 | *

17 | * Example JSON: 18 | *

19 | * { "message": "Some nits need to be fixed.", "labels": { "Code-Review": -1 }, 20 | * "comments": { 21 | * "gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java" 22 | * : [ { "line": 23, "message": "[nit] trailing whitespace" }, { "line": 49, 23 | * "message": "[nit] s/conrtol/control" } ] } } 24 | */ 25 | public class ReviewInput { 26 | private static final Logger LOG = Loggers.get(ReviewInput.class); 27 | private String message = "Looks good to me."; 28 | private Map labels = new ConcurrentHashMap<>(); 29 | private Map> comments = new ConcurrentHashMap<>(); 30 | 31 | public void setValueAndLabel(@NotNull int value, @NotNull String label) { 32 | labels.put(label, value); 33 | } 34 | 35 | public void setLabelToPlusOne(@NotNull String label) { 36 | this.setValueAndLabel(1, label); 37 | } 38 | 39 | public void setLabelToMinusOne(@NotNull String label) { 40 | this.setValueAndLabel(-1, label); 41 | } 42 | 43 | public String getMessage() { 44 | return message; 45 | } 46 | 47 | public void setMessage(@NotNull String message) { 48 | this.message = message; 49 | } 50 | 51 | public void addComments(String key, List reviewFileComments) { 52 | comments.put(key, new ArrayList(reviewFileComments)); 53 | } 54 | 55 | public int size() { 56 | return comments.size(); 57 | } 58 | 59 | public void emptyComments() { 60 | comments.clear(); 61 | } 62 | 63 | public Map getLabels() { 64 | return labels; 65 | } 66 | 67 | public Map> getComments() { 68 | return comments; 69 | } 70 | 71 | public boolean isEmpty() { 72 | return comments.isEmpty(); 73 | } 74 | 75 | public int maxLevelSeverity() { 76 | int lvl = ReviewUtils.UNKNOWN_VALUE; 77 | 78 | for (Iterator> i = comments.values().iterator(); i.hasNext(); ) { 79 | List lrfc = i.next(); 80 | for (ReviewFileComment review : lrfc) { 81 | lvl = Math.max(review.getSeverity(), lvl); 82 | } 83 | } 84 | LOG.debug("[GERRIT PLUGIN] The max level severity is {}", lvl); 85 | 86 | return lvl; 87 | } 88 | 89 | @Override 90 | public String toString() { 91 | return "ReviewInput [message=" + message + ", labels=" + labels + ", comments=" + comments + "]"; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/fr/techad/sonar/gerrit/review/ReviewLineComment.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.gerrit.review; 2 | 3 | import org.sonar.api.utils.log.Logger; 4 | import org.sonar.api.utils.log.Loggers; 5 | 6 | public class ReviewLineComment extends ReviewFileComment { 7 | private static final Logger LOG = Loggers.get(ReviewLineComment.class); 8 | private Integer line = 0; 9 | 10 | public Integer getLine() { 11 | return line; 12 | } 13 | 14 | public void setLine(Integer setLine) { 15 | Integer tmpLine = 0; 16 | 17 | if (null == setLine) { 18 | LOG.debug("[GERRIT PLUGIN] ReviewLineComment line is null, forcing to 0"); 19 | } else if (1 > setLine) { 20 | LOG.debug("[GERRIT PLUGIN] ReviewLineComment line < 0, forcing to 0"); 21 | } else { 22 | LOG.debug("[GERRIT PLUGIN] ReviewLineComment setLine {}", setLine); 23 | tmpLine = setLine; 24 | } 25 | 26 | this.line = tmpLine; 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return "ReviewLineComment [line=" + line + ", message=" + getMessage() + "]"; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/fr/techad/sonar/gerrit/utils/ReviewUtils.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.gerrit.utils; 2 | 3 | import org.sonar.api.batch.rule.Severity; 4 | import org.sonar.api.utils.log.Logger; 5 | import org.sonar.api.utils.log.Loggers; 6 | 7 | public final class ReviewUtils { 8 | public static final String UNKNOWN = "UNKNOWN"; 9 | public static final int UNKNOWN_VALUE = -1; 10 | private static final Logger LOG = Loggers.get(ReviewUtils.class); 11 | 12 | private ReviewUtils() { 13 | super(); 14 | } 15 | 16 | public static int thresholdToValue(String threshold) { 17 | int thresholdValue = UNKNOWN_VALUE; 18 | 19 | try { 20 | thresholdValue = Severity.valueOf(threshold).ordinal(); 21 | } catch (Exception e) { 22 | LOG.warn("[GERRIT PLUGIN] Cannot convert threshold String {} to int. Using UNKNOWN.", threshold); 23 | thresholdValue = UNKNOWN_VALUE; 24 | } 25 | 26 | LOG.debug("[GERRIT PLUGIN] {} is converted to {}", threshold, thresholdValue); 27 | 28 | return thresholdValue; 29 | } 30 | 31 | public static String valueToThreshold(int value) { 32 | String threshold = UNKNOWN; 33 | 34 | try { 35 | threshold = Severity.values()[value].toString(); 36 | } catch (Exception e) { 37 | LOG.warn("[GERRIT PLUGIN] Cannot convert threshold int {} to String. Using UNKNOWN.", value); 38 | } 39 | 40 | LOG.debug("[GERRIT PLUGIN] {} is converted to {}", value, threshold); 41 | 42 | return threshold; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/fr/techad/sonar/utils/MessageUtils.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.utils; 2 | 3 | import org.apache.commons.lang3.text.StrSubstitutor; 4 | import org.sonar.api.batch.postjob.issue.PostJobIssue; 5 | import org.sonar.api.config.Settings; 6 | 7 | import java.util.Collections; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | public class MessageUtils { 12 | 13 | private static final String ISSUE_PREFIX = "issue"; 14 | private static final String ISSUE_IS_NEW = "isNew"; 15 | private static final String ISSUE_RULE_KEY = "ruleKey"; 16 | private static final String ISSUE_SEVERITY = "severity"; 17 | private static final String ISSUE_MESSAGE = "message"; 18 | private static final String ISSUE_SEPARATOR = "."; 19 | 20 | private MessageUtils() { 21 | super(); 22 | } 23 | 24 | /** 25 | * Create the issue message. The variables contained in the original message 26 | * are replaced by the settings values and the issue data. 27 | * 28 | * @param originalMessage the original message 29 | * @param settings the settings 30 | * @param issue the issue 31 | * @return a new message with the replaced variables by data. 32 | */ 33 | public static String createIssueMessage(String originalMessage, Settings settings, PostJobIssue issue) { 34 | HashMap valueMap = new HashMap<>(); 35 | valueMap.put(prefixKey(ISSUE_PREFIX, ISSUE_IS_NEW), issue.isNew()); 36 | valueMap.put(prefixKey(ISSUE_PREFIX, ISSUE_RULE_KEY), issue.ruleKey()); 37 | valueMap.put(prefixKey(ISSUE_PREFIX, ISSUE_SEVERITY), issue.severity()); 38 | valueMap.put(prefixKey(ISSUE_PREFIX, ISSUE_MESSAGE), issue.message()); 39 | return substituteProperties(originalMessage, settings, valueMap); 40 | } 41 | 42 | /** 43 | * Create the message from originalMessage and Settings. The variables 44 | * contained in the originalMessage are replaced by the Settings value 45 | * 46 | * @param originalMessage the original message which contains variables 47 | * @param settings the settings 48 | * @return a new string with substituted variables. 49 | */ 50 | public static String createMessage(String originalMessage, Settings settings) { 51 | return substituteProperties(originalMessage, settings, Collections.emptyMap()); 52 | } 53 | 54 | /** 55 | * Build a string based on an original string and the replacement by 56 | * settings and map values 57 | * 58 | * @param originalMessage the original string 59 | * @param settings the settings 60 | * @param additionalProperties the additional values 61 | * @return the built message 62 | */ 63 | private static String substituteProperties(String originalMessage, Settings settings, 64 | Map additionalProperties) { 65 | if (additionalProperties.isEmpty()) { 66 | return StrSubstitutor.replace(originalMessage, settings.getProperties()); 67 | } 68 | additionalProperties.putAll(settings.getProperties()); 69 | return StrSubstitutor.replace(originalMessage, additionalProperties); 70 | } 71 | 72 | /** 73 | * Create the key 74 | * 75 | * @param prefix the prefix key 76 | * @param key the key 77 | * @return the key 78 | */ 79 | private static String prefixKey(String prefix, String key) { 80 | return new StringBuffer(prefix).append(ISSUE_SEPARATOR).append(key).toString(); 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/resources/org/sonar/l10n/gerrit.properties: -------------------------------------------------------------------------------- 1 | property.category.Gerrit=Gerrit 2 | property.category.Gerrit.description=Properties of the Gerrit plugin 3 | property.category.Gerrit.Server=Server 4 | property.category.Gerrit.Server.description=Server settings 5 | property.category.Gerrit.Review=Review 6 | property.category.Gerrit.Review.description=Review settings 7 | property.GERRIT_ENABLED.name=Enable plugin 8 | property.GERRIT_ENABLED.description=Enable or disable plugin 9 | property.GERRIT_SCHEME.name=Server scheme 10 | property.GERRIT_SCHEME.description=Define the server connection scheme 11 | property.GERRIT_HOST.name=Server host 12 | property.GERRIT_HOST.description=Define the gerrit host 13 | property.GERRIT_PORT.name=Server port 14 | property.GERRIT_PORT.description=Define the gerrit port 15 | property.GERRIT_USERNAME.name=Username 16 | property.GERRIT_USERNAME.description=Define the username to login with. Blank for anonymous over http. 17 | property.GERRIT_PASSWORD.name=Password 18 | property.GERRIT_PASSWORD.description=Define the password for the username (REST) or the private key (SSH) 19 | property.GERRIT_HTTP_AUTH_SCHEME.name=Server authentication scheme 20 | property.GERRIT_HTTP_AUTH_SCHEME.description=Define the server authentication scheme 21 | property.GERRIT_BASE_PATH.name=Base path 22 | property.GERRIT_BASE_PATH.description=Define an alternate server base path 23 | property.GERRIT_SSH_KEY_PATH.name=SSH private key path 24 | property.GERRIT_SSH_KEY_PATH.description=Path to the SSH private key to use when connection scheme is ssh. 25 | property.GERRIT_LABEL.name=Review label 26 | property.GERRIT_LABEL.description=Define the label which the vote will change 27 | property.GERRIT_MESSAGE.name=Review message 28 | property.GERRIT_MESSAGE.description=Define the message which will be added in comment 29 | property.GERRIT_ISSUE_COMMENT.name=Issue comment 30 | property.GERRIT_ISSUE_COMMENT.description=Define the message which will be used to comment issues 31 | property.GERRIT_CHANGE_ID.name=Change ID 32 | property.GERRIT_CHANGE_ID.description=Leave blank to delegate the definition by gerrit 33 | property.GERRIT_REVISION_ID.name=Patchset Revision ID 34 | property.GERRIT_REVISION_ID.description=Leave blank to delegate the definition by gerrit 35 | property.GERRIT_THRESHOLD.name=Alert threshold 36 | property.GERRIT_THRESHOLD.description=Sonar will vote -1 above this threshold 37 | property.GERRIT_VOTE_NO_ISSUE.name=Vote when no issues 38 | property.GERRIT_VOTE_NO_ISSUE.description=What to vote when no issues are detected 39 | property.GERRIT_VOTE_ISSUE_BELOW_THRESHOLD.name=Vote \u003c threshold 40 | property.GERRIT_VOTE_ISSUE_BELOW_THRESHOLD.description=What to vote when issues below threshold are detected 41 | property.GERRIT_VOTE_ISSUE_ABOVE_THRESHOLD.name=Vote \u2265 threshold 42 | property.GERRIT_VOTE_ISSUE_ABOVE_THRESHOLD.description=What to vote when issues above threshold are detected 43 | property.GERRIT_FORCE_BRANCH.name=Force branch 44 | property.GERRIT_FORCE_BRANCH.description=Set to true to force branch creation in SQ and override its name with Gerrit's branch name. 45 | property.GERRIT_COMMENT_NEW_ISSUES_ONLY.name=Comment new issues only 46 | property.GERRIT_COMMENT_NEW_ISSUES_ONLY.description=Sonar comment only newly created issues. Existing issues will not be reported. 47 | property.GERRIT_STRICT_HOSTKEY.name=SSH StrictHostKeyChecking 48 | property.GERRIT_STRICT_HOSTKEY.description=Enable or disable StrictHostKeyChecking when connection scheme is ssh. 49 | -------------------------------------------------------------------------------- /src/main/resources/org/sonar/l10n/gerrit_fr.properties: -------------------------------------------------------------------------------- 1 | property.category.Gerrit=Gerrit 2 | property.category.Gerrit.description=Configuration du plugin Gerrit 3 | property.category.Gerrit.Server=Serveur 4 | property.category.Gerrit.Server.description=R\u00e9glages du serveur 5 | property.category.Gerrit.Review=R\u00e9vision 6 | property.category.Gerrit.Review.description=R\u00e9glages de r\u00e9vision 7 | property.GERRIT_ENABLED.name=Plugin actif 8 | property.GERRIT_ENABLED.description=Active ou d\u00e9sactive le plugin 9 | property.GERRIT_SCHEME.name=Sch\u00e9ma d'URL 10 | property.GERRIT_SCHEME.description=D\u00e9fini le sch\u00e9ma d'URL \u00e0 utiliser 11 | property.GERRIT_HOST.name=Serveur 12 | property.GERRIT_HOST.description=D\u00e9fini le serveur Gerrit 13 | property.GERRIT_PORT.name=Port du serveur 14 | property.GERRIT_PORT.description=D\u00e9fini le port du serveur Gerrit 15 | property.GERRIT_USERNAME.name=Nom d'utilisateur 16 | property.GERRIT_USERNAME.description=D\u00e9fini le nom d'utilisateur \u00e0 utiliser. Vide pour une connection anonyme avec http. 17 | property.GERRIT_PASSWORD.name=Mot de passe 18 | property.GERRIT_PASSWORD.description=D\u00e9fini le mot de passe \u00e0 utiliser pour la connection ou la clef priv\u00e9e. 19 | property.GERRIT_HTTP_AUTH_SCHEME.name=Sch\u00e9ma d'authentification 20 | property.GERRIT_HTTP_AUTH_SCHEME.description=D\u00e9fini le sch\u00e9ma d'authentification du serveur 21 | property.GERRIT_BASE_PATH.name=Chemin de base 22 | property.GERRIT_BASE_PATH.description=D\u00e9fini un chemin de base alternatif 23 | property.GERRIT_SSH_KEY_PATH.name=Chemin de la clef priv\u00e9e SSH 24 | property.GERRIT_SSH_KEY_PATH.description=Chemin de la clef priv\u00e9e SSH \u00e0 utiliser lorsque le sch\u00e9ma d'URI est ssh. 25 | property.GERRIT_LABEL.name=\u00c9tiquette de r\u00e9vision 26 | property.GERRIT_LABEL.description=D\u00e9fini l'\u00e9tiquette \u00e0 laquelle Sonar votera 27 | property.GERRIT_MESSAGE.name=Message de r\u00e9vision 28 | property.GERRIT_MESSAGE.description=D\u00e9fini le message qui sera ajout\u00e9 en commentaire de la r\u00e9vision 29 | property.GERRIT_ISSUE_COMMENT.name=Commentaire des d\u00e9fauts 30 | property.GERRIT_ISSUE_COMMENT.description=D\u00e9fini le message qui sera ajout\u00e9 en commentaire des d\u00e9fauts 31 | property.GERRIT_CHANGE_ID.name=ID du changement 32 | property.GERRIT_CHANGE_ID.description=Ne rien renseigner pour laisser Gerrit g\u00e9rer 33 | property.GERRIT_REVISION_ID.name=ID de la r\u00e9vision 34 | property.GERRIT_REVISION_ID.description=Ne rien renseigner pour laisser Gerrit g\u00e9rer 35 | property.GERRIT_THRESHOLD.name=Seuil des alertes 36 | property.GERRIT_THRESHOLD.description=Seuil au dela duquel Sonar votera -1 37 | property.GERRIT_VOTE_NO_ISSUE.name=Vote sans d\u00e9faut 38 | property.GERRIT_VOTE_NO_ISSUE.description=Valeur du vote lorsque aucun d\u00e9faut n'est d\u00e9t\u00e9ct\u00e9 39 | property.GERRIT_VOTE_ISSUE_BELOW_THRESHOLD.name=Vote \u003c seuil 40 | property.GERRIT_VOTE_ISSUE_BELOW_THRESHOLD.description=Valeur du vote si les d\u00e9fauts sont tous inf\u00e8rieurs au seuil 41 | property.GERRIT_VOTE_ISSUE_ABOVE_THRESHOLD.name=Vote \u2265 seuil 42 | property.GERRIT_VOTE_ISSUE_ABOVE_THRESHOLD.description=Valeur du vote si les d\u00e9fauts sont sup\u00e8rieurs au seuil 43 | property.GERRIT_FORCE_BRANCH.name=Forcer la branche 44 | property.GERRIT_FORCE_BRANCH.description=Mettre \u00e0 true pour surcharger et cr\u00e9er automatiquement une nouvelle branche dans SonarQube avec le nom de la branche Gerrit. 45 | property.GERRIT_COMMENT_NEW_ISSUES_ONLY.name=Commenter seulement les nouveaux d\u00e9fauts 46 | property.GERRIT_COMMENT_NEW_ISSUES_ONLY.description=Sonar ne commentera que les nouveaux d\u00e9fauts. Les d\u00e9fauts existants ne seront pas remont\u00e9s. 47 | property.GERRIT_STRICT_HOSTKEY.name=SSH StrictHostKeyChecking 48 | property.GERRIT_STRICT_HOSTKEY.description=Active ou d\u00e9sactive StrictHostKeyChecking lorsque le sch\u00e9ma d'URI est ssh. 49 | -------------------------------------------------------------------------------- /src/test/java/fr/techad/sonar/GerritConfigurationTest.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.BeforeEach; 5 | import org.junit.jupiter.api.Test; 6 | import org.sonar.api.config.internal.MapSettings; 7 | 8 | import static org.fest.assertions.Assertions.assertThat; 9 | 10 | public class GerritConfigurationTest { 11 | private final String SCHEME = "http"; 12 | private final String HOST = "localhost"; 13 | private final Integer PORT = 8080; 14 | private final String USERNAME = "username"; 15 | private final String PASSWORD = "sonar"; 16 | private final String LABEL = "Code-Review"; 17 | private final String PROJECT = "example"; 18 | private final String BRANCH = "example"; 19 | private final String CHANGE_ID = "I8473b95934b5732ac55d26311a706c9c2bde9940"; 20 | private final String REVISION_ID = "674ac754f91e64a0efb8087e59a176484bd534d1"; 21 | private GerritConfiguration gerritConfiguration; 22 | 23 | @BeforeEach 24 | public void setUp() { 25 | MapSettings settings = new MapSettings(); 26 | settings.setProperty(PropertyKey.GERRIT_SCHEME, SCHEME).setProperty(PropertyKey.GERRIT_HOST, HOST) 27 | .setProperty(PropertyKey.GERRIT_PORT, PORT.toString()).setProperty(PropertyKey.GERRIT_USERNAME, USERNAME) 28 | .setProperty(PropertyKey.GERRIT_PASSWORD, PASSWORD).setProperty(PropertyKey.GERRIT_BASE_PATH, "") 29 | .setProperty(PropertyKey.GERRIT_PROJECT, PROJECT).setProperty(PropertyKey.GERRIT_BRANCH, BRANCH) 30 | .setProperty(PropertyKey.GERRIT_CHANGE_ID, CHANGE_ID) 31 | .setProperty(PropertyKey.GERRIT_REVISION_ID, REVISION_ID) 32 | .setProperty(PropertyKey.GERRIT_LABEL, LABEL); 33 | gerritConfiguration = new GerritConfiguration(settings); 34 | } 35 | 36 | @Test 37 | public void shouldValidateWithDefaults() throws GerritPluginException { 38 | // given 39 | // when 40 | gerritConfiguration.assertGerritConfiguration(); 41 | // then 42 | assertThat(gerritConfiguration.isValid()).isTrue(); 43 | } 44 | 45 | @Test 46 | public void shouldNotValidateIfHostIsBlank() throws GerritPluginException { 47 | // given 48 | gerritConfiguration.setHost(""); 49 | // when 50 | gerritConfiguration.assertGerritConfiguration(); 51 | // then 52 | assertThat(gerritConfiguration.isValid()).isFalse(); 53 | } 54 | 55 | @Test 56 | public void shouldNotValidateIfPortIsBlank() throws GerritPluginException { 57 | // given 58 | gerritConfiguration.setPort(null); 59 | // when 60 | gerritConfiguration.assertGerritConfiguration(); 61 | // then 62 | assertThat(gerritConfiguration.isValid()).isFalse(); 63 | } 64 | 65 | @Test 66 | public void shouldNotValidateIfLabelIsBlank() throws GerritPluginException { 67 | // given 68 | gerritConfiguration.setLabel(""); 69 | // when 70 | gerritConfiguration.assertGerritConfiguration(); 71 | // then 72 | assertThat(gerritConfiguration.isValid()).isFalse(); 73 | } 74 | 75 | @Test 76 | public void shouldNotValidateIfProjectNameIsBlank() throws GerritPluginException { 77 | // given 78 | gerritConfiguration.setProjectName(""); 79 | // when 80 | gerritConfiguration.assertGerritConfiguration(); 81 | // then 82 | assertThat(gerritConfiguration.isValid()).isFalse(); 83 | } 84 | 85 | @Test 86 | public void shouldNotValidateIfBranchNameIsBlank() throws GerritPluginException { 87 | // given 88 | gerritConfiguration.setProjectName(""); 89 | // when 90 | gerritConfiguration.assertGerritConfiguration(); 91 | // then 92 | assertThat(gerritConfiguration.isValid()).isFalse(); 93 | } 94 | 95 | @Test 96 | public void shouldNotValidateIfChangeIdIsBlank() throws GerritPluginException { 97 | // given 98 | gerritConfiguration.setChangeId(""); 99 | // when 100 | gerritConfiguration.assertGerritConfiguration(); 101 | // then 102 | assertThat(gerritConfiguration.isValid()).isFalse(); 103 | } 104 | 105 | @Test 106 | public void shouldNotValidateIfRevisionIdIsBlank() throws GerritPluginException { 107 | // given 108 | gerritConfiguration.setRevisionId(""); 109 | // when 110 | gerritConfiguration.assertGerritConfiguration(); 111 | // then 112 | assertThat(gerritConfiguration.isValid()).isFalse(); 113 | } 114 | 115 | @Test 116 | public void shouldHandleNullBasePath() throws GerritPluginException { 117 | // given 118 | gerritConfiguration.setBasePath(null); 119 | // when 120 | gerritConfiguration.assertGerritConfiguration(); 121 | // then 122 | assertThat(gerritConfiguration.getBasePath()).isEqualTo("/"); 123 | } 124 | 125 | @Test 126 | public void shouldHandleEmptyBasePath() throws GerritPluginException { 127 | // given 128 | gerritConfiguration.setBasePath(""); 129 | // when 130 | gerritConfiguration.assertGerritConfiguration(); 131 | // then 132 | assertThat(gerritConfiguration.getBasePath()).isEqualTo("/"); 133 | } 134 | 135 | @Test 136 | public void shouldFixBasePathWithoutSlash() throws GerritPluginException { 137 | // given 138 | gerritConfiguration.setBasePath("gerrit"); 139 | // when 140 | gerritConfiguration.assertGerritConfiguration(); 141 | // then 142 | assertThat(gerritConfiguration.getBasePath()).isEqualTo("/gerrit"); 143 | } 144 | 145 | @Test 146 | public void shouldNotFixBasePathWithSlash() throws GerritPluginException { 147 | // given 148 | gerritConfiguration.setBasePath("/gerrit"); 149 | // when 150 | gerritConfiguration.assertGerritConfiguration(); 151 | // then 152 | assertThat(gerritConfiguration.getBasePath()).isEqualTo("/gerrit"); 153 | } 154 | 155 | @Test 156 | public void shouldFixBasePathWithSingleTrailingSlash() throws GerritPluginException { 157 | // given 158 | gerritConfiguration.setBasePath("/gerrit/"); 159 | // when 160 | gerritConfiguration.assertGerritConfiguration(); 161 | // then 162 | assertThat(gerritConfiguration.getBasePath()).isEqualTo("/gerrit"); 163 | } 164 | 165 | @Test 166 | public void shouldFixBasePathWithMultiTrailingSlashs() throws GerritPluginException { 167 | // given 168 | gerritConfiguration.setBasePath("/gerrit///"); 169 | // when 170 | gerritConfiguration.assertGerritConfiguration(); 171 | // then 172 | assertThat(gerritConfiguration.getBasePath()).isEqualTo("/gerrit"); 173 | } 174 | 175 | @Test 176 | public void shouldFixBasePathWithMultiHeadingSlashs() throws GerritPluginException { 177 | // given 178 | gerritConfiguration.setBasePath("///gerrit"); 179 | // when 180 | gerritConfiguration.assertGerritConfiguration(); 181 | // then 182 | assertThat(gerritConfiguration.getBasePath()).isEqualTo("/gerrit"); 183 | } 184 | 185 | @Test 186 | public void shouldFixBasePathWithMulitHeadingAndTrailingSlashs() throws GerritPluginException { 187 | // given 188 | gerritConfiguration.setBasePath("///gerrit///"); 189 | // when 190 | gerritConfiguration.assertGerritConfiguration(); 191 | // then 192 | assertThat(gerritConfiguration.getBasePath()).isEqualTo("/gerrit"); 193 | } 194 | 195 | @Test 196 | public void shouldFixBasePathWithMultiSlashsOnly() throws GerritPluginException { 197 | // given 198 | gerritConfiguration.setBasePath("////"); 199 | // when 200 | gerritConfiguration.assertGerritConfiguration(); 201 | // then 202 | assertThat(gerritConfiguration.getBasePath()).isEqualTo("/"); 203 | } 204 | 205 | @Test 206 | public void shouldBeAnonymous() { 207 | gerritConfiguration.setUsername(""); 208 | Assertions.assertTrue(gerritConfiguration.isAnonymous()); 209 | } 210 | 211 | @Test 212 | public void shouldNotBeAnonymous() { 213 | gerritConfiguration.setUsername(USERNAME); 214 | Assertions.assertFalse(gerritConfiguration.isAnonymous()); 215 | } 216 | 217 | @Test 218 | public void shouldBeAnonymousWithBlankUserName() { 219 | gerritConfiguration.setUsername(""); 220 | Assertions.assertTrue(gerritConfiguration.isAnonymous()); 221 | gerritConfiguration.setUsername(null); 222 | Assertions.assertTrue(gerritConfiguration.isAnonymous()); 223 | } 224 | 225 | @Test 226 | public void shouldCommentNewIssuesOnly() { 227 | gerritConfiguration.commentNewIssuesOnly(true); 228 | Assertions.assertTrue(gerritConfiguration.shouldCommentNewIssuesOnly()); 229 | } 230 | 231 | @Test 232 | public void shouldNotCommentNewIssuesOnly() { 233 | gerritConfiguration.commentNewIssuesOnly(false); 234 | Assertions.assertFalse(gerritConfiguration.shouldCommentNewIssuesOnly()); 235 | } 236 | 237 | @Test 238 | public void shouldStrictlyCheckHostKey() { 239 | gerritConfiguration.strictlyCheckHostkey(true); 240 | Assertions.assertTrue(gerritConfiguration.shouldStrictlyCheckHostKey()); 241 | } 242 | 243 | @Test 244 | public void shouldNotStrictlyCheckHostKey() { 245 | gerritConfiguration.strictlyCheckHostkey(false); 246 | Assertions.assertFalse(gerritConfiguration.shouldStrictlyCheckHostKey()); 247 | } 248 | 249 | @Test 250 | public void shouldGetUsername() { 251 | Assertions.assertEquals(USERNAME, this.gerritConfiguration.getUsername()); 252 | } 253 | 254 | @Test 255 | public void shouldGetPassword() { 256 | Assertions.assertEquals(PASSWORD, this.gerritConfiguration.getPassword()); 257 | } 258 | 259 | @Test 260 | public void shouldGetHttpAuthScheme() { 261 | String httpAuthScheme = "DIGEST"; 262 | this.gerritConfiguration.setHttpAuthScheme(httpAuthScheme); 263 | Assertions.assertEquals(httpAuthScheme, this.gerritConfiguration.getHttpAuthScheme()); 264 | } 265 | 266 | @Test 267 | public void shouldGetScheme() { 268 | Assertions.assertEquals(SCHEME, this.gerritConfiguration.getScheme()); 269 | } 270 | 271 | @Test 272 | public void shouldGetHost() { 273 | Assertions.assertEquals(HOST, this.gerritConfiguration.getHost()); 274 | } 275 | 276 | @Test 277 | public void shouldGetPort() { 278 | Assertions.assertEquals(PORT, this.gerritConfiguration.getPort()); 279 | } 280 | 281 | @Test 282 | public void shouldGetSshKeyPath() { 283 | String sshKeyPath = "/user/sonar"; 284 | this.gerritConfiguration.setSshKeyPath(sshKeyPath); 285 | Assertions.assertEquals(sshKeyPath, this.gerritConfiguration.getSshKeyPath()); 286 | } 287 | 288 | @Test 289 | public void shouldGetLabel() { 290 | Assertions.assertEquals(LABEL, this.gerritConfiguration.getLabel()); 291 | String label = "Quality-Code"; 292 | this.gerritConfiguration.setLabel(label); 293 | Assertions.assertEquals(label, this.gerritConfiguration.getLabel()); 294 | } 295 | 296 | @Test 297 | public void shouldGetMessage() { 298 | String msg = "Message ${Replace}"; 299 | this.gerritConfiguration.setMessage(msg); 300 | Assertions.assertEquals(msg, this.gerritConfiguration.getMessage()); 301 | } 302 | 303 | @Test 304 | public void shouldGetIssueComment() { 305 | String msg = "Issue Comment"; 306 | this.gerritConfiguration.setIssueComment(msg); 307 | Assertions.assertEquals(msg, this.gerritConfiguration.getIssueComment()); 308 | } 309 | 310 | @Test 311 | public void shouldGetThreshold() { 312 | String threshold = "INFO"; 313 | this.gerritConfiguration.setThreshold(threshold); 314 | Assertions.assertEquals(threshold, this.gerritConfiguration.getThreshold()); 315 | } 316 | 317 | @Test 318 | public void shouldGetVoteNoIssue() { 319 | int vote = 2; 320 | this.gerritConfiguration.setVoteNoIssue(vote); 321 | Assertions.assertEquals(vote, this.gerritConfiguration.getVoteNoIssue()); 322 | } 323 | 324 | @Test 325 | public void shouldGetVoteAboveThreshold() { 326 | int vote = 1; 327 | this.gerritConfiguration.setVoteAboveThreshold(vote); 328 | Assertions.assertEquals(vote, this.gerritConfiguration.getVoteAboveThreshold()); 329 | } 330 | 331 | @Test 332 | public void shouldGetVoteBelowThreshold() { 333 | int vote = -11; 334 | this.gerritConfiguration.setVoteBelowThreshold(vote); 335 | Assertions.assertEquals(vote, this.gerritConfiguration.getVoteBelowThreshold()); 336 | } 337 | 338 | @Test 339 | public void shouldGetProjectName() { 340 | Assertions.assertEquals(PROJECT, this.gerritConfiguration.getProjectName()); 341 | } 342 | 343 | @Test 344 | public void shouldGetBranchName() { 345 | Assertions.assertEquals(BRANCH, this.gerritConfiguration.getBranchName()); 346 | } 347 | 348 | @Test 349 | public void shouldGetChangeId() { 350 | Assertions.assertEquals(CHANGE_ID, this.gerritConfiguration.getChangeId()); 351 | } 352 | 353 | @Test 354 | public void shouldGetRevisionId() { 355 | Assertions.assertEquals(REVISION_ID, this.gerritConfiguration.getRevisionId()); 356 | } 357 | 358 | @Test 359 | public void shouldInvalidateConfigurationNoUserNameInSsh() { 360 | gerritConfiguration.setScheme(GerritConstants.SCHEME_SSH); 361 | gerritConfiguration.setUsername(""); 362 | gerritConfiguration.assertGerritConfiguration(); 363 | Assertions.assertFalse(gerritConfiguration.isValid()); 364 | } 365 | 366 | @Test 367 | public void shouldInvalidateConfigurationNoSshKeyPathInSsh() { 368 | gerritConfiguration.setScheme(GerritConstants.SCHEME_SSH); 369 | gerritConfiguration.setSshKeyPath(""); 370 | gerritConfiguration.assertGerritConfiguration(); 371 | Assertions.assertFalse(gerritConfiguration.isValid()); 372 | } 373 | 374 | @Test 375 | public void shouldInvalidateConfigurationWithBlankLabel() { 376 | gerritConfiguration.setLabel(""); 377 | gerritConfiguration.assertGerritConfiguration(); 378 | Assertions.assertFalse(gerritConfiguration.isValid()); 379 | } 380 | 381 | @Test 382 | public void shouldInvalidateConfigurationWithBlankProjectName() { 383 | gerritConfiguration.setProjectName(""); 384 | gerritConfiguration.assertGerritConfiguration(); 385 | Assertions.assertFalse(gerritConfiguration.isValid()); 386 | } 387 | 388 | @Test 389 | public void shouldInvalidateConfigurationWithBlankBranchName() { 390 | gerritConfiguration.setBranchName(""); 391 | gerritConfiguration.assertGerritConfiguration(); 392 | Assertions.assertFalse(gerritConfiguration.isValid()); 393 | } 394 | 395 | @Test 396 | public void shouldInvalidateConfigurationWithBlankChangeId() { 397 | gerritConfiguration.setChangeId(""); 398 | gerritConfiguration.assertGerritConfiguration(); 399 | Assertions.assertFalse(gerritConfiguration.isValid()); 400 | } 401 | 402 | @Test 403 | public void shouldInvalidateConfigurationWithBlankRevisionId() { 404 | gerritConfiguration.setRevisionId(""); 405 | gerritConfiguration.assertGerritConfiguration(); 406 | Assertions.assertFalse(gerritConfiguration.isValid()); 407 | } 408 | } 409 | -------------------------------------------------------------------------------- /src/test/java/fr/techad/sonar/GerritInitializerTest.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar; 2 | 3 | import fr.techad.sonar.gerrit.GerritFacade; 4 | import fr.techad.sonar.gerrit.factory.GerritFacadeFactory; 5 | import fr.techad.sonar.mockito.MockitoExtension; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.api.extension.ExtendWith; 8 | import org.junit.platform.runner.JUnitPlatform; 9 | import org.junit.runner.RunWith; 10 | import org.mockito.Mock; 11 | 12 | import static org.mockito.Mockito.never; 13 | import static org.mockito.Mockito.times; 14 | import static org.mockito.Mockito.verify; 15 | import static org.mockito.Mockito.when; 16 | 17 | /** 18 | * TECH ADVANTAGE 19 | * All right reserved 20 | * Created by cochon on 22/07/2018. 21 | */ 22 | @ExtendWith(MockitoExtension.class) 23 | @RunWith(JUnitPlatform.class) 24 | class GerritInitializerTest { 25 | 26 | @Mock 27 | private GerritConfiguration gerritConfiguration; 28 | 29 | @Mock 30 | private GerritFacadeFactory gerritFacadeFactory; 31 | 32 | @Mock 33 | private GerritFacade gerritFacade; 34 | 35 | @Test 36 | public void shouldListFiles() throws GerritPluginException { 37 | when(gerritConfiguration.isEnabled()).thenReturn(true); 38 | when(gerritConfiguration.isValid()).thenReturn(true); 39 | when(gerritFacadeFactory.getFacade()).thenReturn(gerritFacade); 40 | 41 | GerritInitializer gerritInitializer = new GerritInitializer(gerritConfiguration, gerritFacadeFactory); 42 | gerritInitializer.execute(); 43 | verify(gerritFacade, times(1)).listFiles(); 44 | } 45 | 46 | @Test 47 | public void shouldNotListFilesWhenDisables() throws GerritPluginException { 48 | when(gerritConfiguration.isEnabled()).thenReturn(false); 49 | when(gerritConfiguration.isValid()).thenReturn(true); 50 | when(gerritFacadeFactory.getFacade()).thenReturn(gerritFacade); 51 | 52 | GerritInitializer gerritInitializer = new GerritInitializer(gerritConfiguration, gerritFacadeFactory); 53 | gerritInitializer.execute(); 54 | verify(gerritFacade, never()).listFiles(); 55 | } 56 | 57 | @Test 58 | public void shouldNotListFilesWhenInvalid() throws GerritPluginException { 59 | when(gerritConfiguration.isEnabled()).thenReturn(true); 60 | when(gerritConfiguration.isValid()).thenReturn(false); 61 | when(gerritFacadeFactory.getFacade()).thenReturn(gerritFacade); 62 | 63 | GerritInitializer gerritInitializer = new GerritInitializer(gerritConfiguration, gerritFacadeFactory); 64 | gerritInitializer.execute(); 65 | verify(gerritFacade, never()).listFiles(); 66 | } 67 | 68 | @Test 69 | public void shouldCatchExceptionIfListFilesThrowsIt() throws GerritPluginException { 70 | when(gerritConfiguration.isEnabled()).thenReturn(true); 71 | when(gerritConfiguration.isValid()).thenReturn(true); 72 | when(gerritFacadeFactory.getFacade()).thenReturn(gerritFacade); 73 | when(gerritFacade.listFiles()).thenThrow(new GerritPluginException("Mock Exception During Test")); 74 | 75 | GerritInitializer gerritInitializer = new GerritInitializer(gerritConfiguration, gerritFacadeFactory); 76 | gerritInitializer.execute(); 77 | verify(gerritFacade, times(1)).listFiles(); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/test/java/fr/techad/sonar/GerritPostJobTest.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar; 2 | 3 | import fr.techad.sonar.gerrit.GerritFacade; 4 | import fr.techad.sonar.gerrit.factory.GerritFacadeFactory; 5 | import fr.techad.sonar.gerrit.review.ReviewFileComment; 6 | import fr.techad.sonar.gerrit.review.ReviewInput; 7 | import fr.techad.sonar.gerrit.review.ReviewLineComment; 8 | import fr.techad.sonar.mockito.MockitoExtension; 9 | import org.junit.jupiter.api.Assertions; 10 | import org.junit.jupiter.api.BeforeEach; 11 | import org.junit.jupiter.api.Test; 12 | import org.junit.jupiter.api.extension.ExtendWith; 13 | import org.junit.platform.runner.JUnitPlatform; 14 | import org.junit.runner.RunWith; 15 | import org.mockito.ArgumentCaptor; 16 | import org.mockito.Captor; 17 | import org.sonar.api.batch.fs.InputPath; 18 | import org.sonar.api.batch.postjob.PostJobContext; 19 | import org.sonar.api.batch.postjob.PostJobDescriptor; 20 | import org.sonar.api.batch.postjob.issue.PostJobIssue; 21 | import org.sonar.api.batch.rule.Severity; 22 | import org.sonar.api.config.internal.MapSettings; 23 | import org.sonar.api.rule.RuleKey; 24 | 25 | import java.io.File; 26 | import java.util.ArrayList; 27 | import java.util.List; 28 | import java.util.Map; 29 | 30 | import static org.mockito.ArgumentMatchers.any; 31 | import static org.mockito.Mockito.doThrow; 32 | import static org.mockito.Mockito.mock; 33 | import static org.mockito.Mockito.never; 34 | import static org.mockito.Mockito.times; 35 | import static org.mockito.Mockito.verify; 36 | import static org.mockito.Mockito.when; 37 | 38 | /** 39 | * TECH ADVANTAGE 40 | * All right reserved 41 | * Created by cochon on 31/07/2018. 42 | */ 43 | @ExtendWith(MockitoExtension.class) 44 | @RunWith(JUnitPlatform.class) 45 | class GerritPostJobTest { 46 | private static final String LABEL = "Code-Review"; 47 | private static final String PATH1 = "src/main/java/F1.java"; 48 | private static final String PATH2 = "src/main/java/F2.java"; 49 | 50 | @Captor 51 | ArgumentCaptor describeStringCaptor; 52 | @Captor 53 | ArgumentCaptor reviewInputCaptor; 54 | 55 | private MapSettings settings; 56 | 57 | @BeforeEach 58 | public void setUp() { 59 | ReviewHolder.getReviewInput().emptyComments(); 60 | // Common Settings 61 | settings = new MapSettings(); 62 | settings.setProperty(PropertyKey.GERRIT_SCHEME, GerritConstants.SCHEME_HTTP) 63 | .setProperty(PropertyKey.GERRIT_HOST, "localhost") 64 | .appendProperty(PropertyKey.GERRIT_PORT, "10800") 65 | .setProperty(PropertyKey.GERRIT_PROJECT, "project") 66 | .setProperty(PropertyKey.GERRIT_CHANGE_ID, "changeid") 67 | .setProperty(PropertyKey.GERRIT_REVISION_ID, "revisionid") 68 | .setProperty(PropertyKey.GERRIT_VOTE_NO_ISSUE, "1") 69 | .setProperty(PropertyKey.GERRIT_VOTE_ISSUE_ABOVE_THRESHOLD, "-2") 70 | .setProperty(PropertyKey.GERRIT_VOTE_ISSUE_BELOW_THRESHOLD, "-1") 71 | .setProperty(PropertyKey.GERRIT_ENABLED, "true") 72 | .setProperty(PropertyKey.GERRIT_MESSAGE, "Message Test") 73 | .setProperty(PropertyKey.GERRIT_ISSUE_COMMENT, "[New: ${issue.isNew}] ${issue.severity}(${issue.ruleKey}) found: ${issue.message}") 74 | .setProperty(PropertyKey.GERRIT_LABEL, LABEL); 75 | } 76 | 77 | @Test 78 | void shouldDescribeTheJob() { 79 | GerritConfiguration gerritConfiguration = mock(GerritConfiguration.class); 80 | GerritFacadeFactory gerritFacadeFactory = mock(GerritFacadeFactory.class); 81 | PostJobDescriptor descriptor = mock(PostJobDescriptor.class); 82 | 83 | GerritPostJob gerritPostJob = new GerritPostJob(settings, gerritConfiguration, gerritFacadeFactory); 84 | gerritPostJob.describe(descriptor); 85 | verify(descriptor).name(describeStringCaptor.capture()); 86 | String name = describeStringCaptor.getValue(); 87 | verify(descriptor).requireProperty(describeStringCaptor.capture()); 88 | String property = describeStringCaptor.getValue(); 89 | Assertions.assertEquals("GERRIT PLUGIN", name); 90 | Assertions.assertEquals(PropertyKey.GERRIT_CHANGE_ID, property); 91 | } 92 | 93 | @Test 94 | public void shouldCallOneListFilesOnAssertOrFetchGerritModifiedFiles() throws GerritPluginException { 95 | GerritConfiguration gerritConfiguration = mock(GerritConfiguration.class); 96 | GerritFacadeFactory gerritFacadeFactory = mock(GerritFacadeFactory.class); 97 | GerritFacade gerritFacade = mock(GerritFacade.class); 98 | when(gerritFacadeFactory.getFacade()).thenReturn(gerritFacade); 99 | when(gerritFacade.listFiles()).thenReturn(new ArrayList<>()); 100 | 101 | GerritPostJob gerritPostJob = new GerritPostJob(settings, gerritConfiguration, gerritFacadeFactory); 102 | gerritPostJob.assertOrFetchGerritModifiedFiles(); 103 | gerritPostJob.assertOrFetchGerritModifiedFiles(); 104 | verify(gerritFacade, times(1)).listFiles(); 105 | } 106 | 107 | @Test 108 | public void shouldConvertIssueToComment() { 109 | GerritConfiguration gerritConfiguration = new GerritConfiguration(settings); 110 | GerritFacadeFactory gerritFacadeFactory = mock(GerritFacadeFactory.class); 111 | 112 | RuleKey ruleKey = RuleKey.of("test-repo", "sonar-1"); 113 | PostJobIssue postJobIssue = mock(PostJobIssue.class); 114 | when(postJobIssue.line()).thenReturn(12); 115 | when(postJobIssue.severity()).thenReturn(Severity.INFO); 116 | when(postJobIssue.message()).thenReturn("Should be a message test"); 117 | when(postJobIssue.ruleKey()).thenReturn(ruleKey); 118 | when(postJobIssue.isNew()).thenReturn(Boolean.TRUE); 119 | 120 | GerritPostJob gerritPostJob = new GerritPostJob(settings, gerritConfiguration, gerritFacadeFactory); 121 | ReviewLineComment reviewLineComment = gerritPostJob.issueToComment(postJobIssue); 122 | Assertions.assertEquals(new Integer(12), reviewLineComment.getLine()); 123 | Assertions.assertEquals(0, reviewLineComment.getSeverity()); 124 | Assertions.assertEquals("[New: true] INFO(test-repo:sonar-1) found: Should be a message test", reviewLineComment.getMessage()); 125 | } 126 | 127 | @Test 128 | public void shouldDoNothingIfThePluginIsDisabled() throws GerritPluginException { 129 | GerritConfiguration gerritConfiguration = mock(GerritConfiguration.class); 130 | when(gerritConfiguration.isEnabled()).thenReturn(Boolean.FALSE); 131 | GerritFacadeFactory gerritFacadeFactory = mock(GerritFacadeFactory.class); 132 | GerritFacade gerritFacade = mock(GerritFacade.class); 133 | when(gerritFacadeFactory.getFacade()).thenReturn(gerritFacade); 134 | PostJobContext postJobContext = mock(PostJobContext.class); 135 | 136 | GerritPostJob gerritPostJob = new GerritPostJob(settings, gerritConfiguration, gerritFacadeFactory); 137 | gerritPostJob.execute(postJobContext); 138 | verify(gerritFacade, never()).setReview(any()); 139 | } 140 | 141 | @Test 142 | public void shouldSendNoIssueOnExecute() throws GerritPluginException { 143 | GerritConfiguration gerritConfiguration = new GerritConfiguration(settings); 144 | GerritFacadeFactory gerritFacadeFactory = mock(GerritFacadeFactory.class); 145 | GerritFacade gerritFacade = mock(GerritFacade.class); 146 | when(gerritFacadeFactory.getFacade()).thenReturn(gerritFacade); 147 | PostJobContext postJobContext = mock(PostJobContext.class); 148 | when(postJobContext.issues()).thenReturn(new ArrayList<>()); 149 | 150 | GerritPostJob gerritPostJob = new GerritPostJob(settings, gerritConfiguration, gerritFacadeFactory); 151 | gerritPostJob.execute(postJobContext); 152 | 153 | verify(gerritFacade).setReview(reviewInputCaptor.capture()); 154 | ReviewInput reviewInput = reviewInputCaptor.getValue(); 155 | Map labels = reviewInput.getLabels(); 156 | Assertions.assertEquals(1, labels.size()); 157 | Integer integer = labels.get(LABEL); 158 | Assertions.assertNotNull(integer); 159 | Assertions.assertEquals(1, integer.intValue()); 160 | Assertions.assertEquals(0, reviewInput.getComments().size()); 161 | } 162 | 163 | @Test 164 | public void shouldSendBelowMsgIssueOnExecute() throws GerritPluginException { 165 | settings.setProperty(PropertyKey.GERRIT_THRESHOLD, "BLOCKER"); 166 | GerritConfiguration gerritConfiguration = new GerritConfiguration(settings); 167 | GerritFacadeFactory gerritFacadeFactory = mock(GerritFacadeFactory.class); 168 | GerritFacade gerritFacade = mock(GerritFacade.class); 169 | when(gerritFacadeFactory.getFacade()).thenReturn(gerritFacade); 170 | List listFiles = new ArrayList<>(); 171 | listFiles.add(PATH1); 172 | listFiles.add(PATH2); 173 | when(gerritFacade.listFiles()).thenReturn(listFiles); 174 | 175 | InputPath inputPath1 = createInputPath(PATH1, Boolean.TRUE); 176 | InputPath inputPath2 = createInputPath(PATH2, Boolean.TRUE); 177 | 178 | List postJobIssues = new ArrayList<>(); 179 | postJobIssues.add(createPostJobIssueMock(10, inputPath1, Severity.INFO, "R1", "Msg 1", Boolean.TRUE)); 180 | postJobIssues.add(createPostJobIssueMock(20, inputPath1, Severity.MAJOR, "R2", "Msg 2", Boolean.TRUE)); 181 | postJobIssues.add(createPostJobIssueMock(1020, inputPath2, Severity.INFO, "R3", "Msg 3", Boolean.TRUE)); 182 | PostJobContext postJobContext = mock(PostJobContext.class); 183 | when(postJobContext.issues()).thenReturn(postJobIssues); 184 | 185 | GerritPostJob gerritPostJob = new GerritPostJob(settings, gerritConfiguration, gerritFacadeFactory); 186 | gerritPostJob.execute(postJobContext); 187 | 188 | verify(gerritFacade).setReview(reviewInputCaptor.capture()); 189 | ReviewInput reviewInput = reviewInputCaptor.getValue(); 190 | Map labels = reviewInput.getLabels(); 191 | Assertions.assertEquals(1, labels.size()); 192 | // Vote Value 193 | Integer integer = labels.get(LABEL); 194 | Assertions.assertNotNull(integer); 195 | Assertions.assertEquals(-1, integer.intValue()); 196 | Map> inputComments = reviewInput.getComments(); 197 | Assertions.assertEquals(2, inputComments.size()); 198 | List reviewFileComments = inputComments.get(PATH1); 199 | Assertions.assertEquals(2, reviewFileComments.size()); 200 | Assertions.assertEquals(0, reviewFileComments.get(0).getSeverity()); 201 | ReviewLineComment reviewLineComment = (ReviewLineComment) reviewFileComments.get(0); 202 | Assertions.assertEquals(10, reviewLineComment.getLine().intValue()); 203 | Assertions.assertEquals(2, reviewFileComments.get(1).getSeverity()); 204 | reviewLineComment = (ReviewLineComment) reviewFileComments.get(1); 205 | Assertions.assertEquals(20, reviewLineComment.getLine().intValue()); 206 | reviewFileComments = inputComments.get(PATH2); 207 | Assertions.assertEquals(1, reviewFileComments.size()); 208 | Assertions.assertEquals(0, reviewFileComments.get(0).getSeverity()); 209 | reviewLineComment = (ReviewLineComment) reviewFileComments.get(0); 210 | Assertions.assertEquals(1020, reviewLineComment.getLine().intValue()); 211 | } 212 | 213 | @Test 214 | public void shouldSendAboveMsgIssueOnExecute() throws GerritPluginException { 215 | settings.setProperty(PropertyKey.GERRIT_THRESHOLD, "INFO"); 216 | GerritConfiguration gerritConfiguration = new GerritConfiguration(settings); 217 | GerritFacadeFactory gerritFacadeFactory = mock(GerritFacadeFactory.class); 218 | GerritFacade gerritFacade = mock(GerritFacade.class); 219 | when(gerritFacadeFactory.getFacade()).thenReturn(gerritFacade); 220 | List listFiles = new ArrayList<>(); 221 | listFiles.add(PATH1); 222 | listFiles.add(PATH2); 223 | when(gerritFacade.listFiles()).thenReturn(listFiles); 224 | 225 | InputPath inputPath1 = createInputPath(PATH1, Boolean.TRUE); 226 | InputPath inputPath2 = createInputPath(PATH2, Boolean.TRUE); 227 | 228 | List postJobIssues = new ArrayList<>(); 229 | postJobIssues.add(createPostJobIssueMock(10, inputPath1, Severity.MAJOR, "R1", "Msg 1", Boolean.TRUE)); 230 | postJobIssues.add(createPostJobIssueMock(20, inputPath1, Severity.MAJOR, "R2", "Msg 2", Boolean.TRUE)); 231 | postJobIssues.add(createPostJobIssueMock(1020, inputPath2, Severity.MAJOR, "R3", "Msg 3", Boolean.TRUE)); 232 | PostJobContext postJobContext = mock(PostJobContext.class); 233 | when(postJobContext.issues()).thenReturn(postJobIssues); 234 | 235 | GerritPostJob gerritPostJob = new GerritPostJob(settings, gerritConfiguration, gerritFacadeFactory); 236 | gerritPostJob.execute(postJobContext); 237 | 238 | verify(gerritFacade).setReview(reviewInputCaptor.capture()); 239 | ReviewInput reviewInput = reviewInputCaptor.getValue(); 240 | Map labels = reviewInput.getLabels(); 241 | Assertions.assertEquals(1, labels.size()); 242 | // Vote Value 243 | Integer integer = labels.get(LABEL); 244 | Assertions.assertNotNull(integer); 245 | Assertions.assertEquals(-2, integer.intValue()); 246 | Map> inputComments = reviewInput.getComments(); 247 | Assertions.assertEquals(2, inputComments.size()); 248 | List reviewFileComments = inputComments.get(PATH1); 249 | Assertions.assertEquals(2, reviewFileComments.size()); 250 | Assertions.assertEquals(2, reviewFileComments.get(0).getSeverity()); 251 | ReviewLineComment reviewLineComment = (ReviewLineComment) reviewFileComments.get(0); 252 | Assertions.assertEquals(10, reviewLineComment.getLine().intValue()); 253 | Assertions.assertEquals(2, reviewFileComments.get(1).getSeverity()); 254 | reviewLineComment = (ReviewLineComment) reviewFileComments.get(1); 255 | Assertions.assertEquals(20, reviewLineComment.getLine().intValue()); 256 | reviewFileComments = inputComments.get(PATH2); 257 | Assertions.assertEquals(1, reviewFileComments.size()); 258 | Assertions.assertEquals(2, reviewFileComments.get(0).getSeverity()); 259 | reviewLineComment = (ReviewLineComment) reviewFileComments.get(0); 260 | Assertions.assertEquals(1020, reviewLineComment.getLine().intValue()); 261 | } 262 | 263 | @Test 264 | public void shouldCommentNewIssueOnly() throws GerritPluginException { 265 | settings.setProperty(PropertyKey.GERRIT_THRESHOLD, "INFO"); 266 | settings.setProperty(PropertyKey.GERRIT_COMMENT_NEW_ISSUES_ONLY, "true"); 267 | GerritConfiguration gerritConfiguration = new GerritConfiguration(settings); 268 | GerritFacadeFactory gerritFacadeFactory = mock(GerritFacadeFactory.class); 269 | GerritFacade gerritFacade = mock(GerritFacade.class); 270 | when(gerritFacadeFactory.getFacade()).thenReturn(gerritFacade); 271 | List listFiles = new ArrayList<>(); 272 | listFiles.add(PATH1); 273 | when(gerritFacade.listFiles()).thenReturn(listFiles); 274 | 275 | InputPath inputPath1 = createInputPath(PATH1, Boolean.TRUE); 276 | 277 | List postJobIssues = new ArrayList<>(); 278 | postJobIssues.add(createPostJobIssueMock(10, inputPath1, Severity.MAJOR, "R1", "Msg 1", Boolean.TRUE)); 279 | postJobIssues.add(createPostJobIssueMock(20, inputPath1, Severity.BLOCKER, "R2", "Msg 2", Boolean.FALSE)); 280 | PostJobContext postJobContext = mock(PostJobContext.class); 281 | when(postJobContext.issues()).thenReturn(postJobIssues); 282 | 283 | GerritPostJob gerritPostJob = new GerritPostJob(settings, gerritConfiguration, gerritFacadeFactory); 284 | gerritPostJob.execute(postJobContext); 285 | 286 | verify(gerritFacade).setReview(reviewInputCaptor.capture()); 287 | ReviewInput reviewInput = reviewInputCaptor.getValue(); 288 | Map labels = reviewInput.getLabels(); 289 | Assertions.assertEquals(1, labels.size()); 290 | // Vote Value 291 | Integer integer = labels.get(LABEL); 292 | Assertions.assertNotNull(integer); 293 | Assertions.assertEquals(-2, integer.intValue()); 294 | Map> inputComments = reviewInput.getComments(); 295 | Assertions.assertEquals(1, inputComments.size()); 296 | List reviewFileComments = inputComments.get(PATH1); 297 | Assertions.assertEquals(1, reviewFileComments.size()); 298 | Assertions.assertEquals(2, reviewFileComments.get(0).getSeverity()); 299 | ReviewLineComment reviewLineComment = (ReviewLineComment) reviewFileComments.get(0); 300 | Assertions.assertEquals(10, reviewLineComment.getLine().intValue()); 301 | } 302 | 303 | @Test 304 | public void shouldFoundFilenameWithPrependValue() throws GerritPluginException { 305 | String path1WithProject = "P1/" + PATH1; 306 | settings.setProperty(PropertyKey.GERRIT_THRESHOLD, "INFO"); 307 | GerritConfiguration gerritConfiguration = new GerritConfiguration(settings); 308 | GerritFacadeFactory gerritFacadeFactory = mock(GerritFacadeFactory.class); 309 | GerritFacade gerritFacade = mock(GerritFacade.class); 310 | when(gerritFacadeFactory.getFacade()).thenReturn(gerritFacade); 311 | List listFiles = new ArrayList<>(); 312 | listFiles.add(PATH1); 313 | when(gerritFacade.listFiles()).thenReturn(listFiles); 314 | when(gerritFacade.parseFileName(path1WithProject)).thenReturn(PATH1); 315 | 316 | InputPath inputPath1 = createInputPath(path1WithProject, Boolean.TRUE); 317 | 318 | List postJobIssues = new ArrayList<>(); 319 | postJobIssues.add(createPostJobIssueMock(10, inputPath1, Severity.MAJOR, "R1", "Msg 1", Boolean.TRUE)); 320 | PostJobContext postJobContext = mock(PostJobContext.class); 321 | when(postJobContext.issues()).thenReturn(postJobIssues); 322 | 323 | GerritPostJob gerritPostJob = new GerritPostJob(settings, gerritConfiguration, gerritFacadeFactory); 324 | gerritPostJob.execute(postJobContext); 325 | 326 | verify(gerritFacade).setReview(reviewInputCaptor.capture()); 327 | ReviewInput reviewInput = reviewInputCaptor.getValue(); 328 | Map labels = reviewInput.getLabels(); 329 | Assertions.assertEquals(1, labels.size()); 330 | // Vote Value 331 | Integer integer = labels.get(LABEL); 332 | Assertions.assertNotNull(integer); 333 | Assertions.assertEquals(-2, integer.intValue()); 334 | Map> inputComments = reviewInput.getComments(); 335 | Assertions.assertEquals(1, inputComments.size()); 336 | List reviewFileComments = inputComments.get(PATH1); 337 | Assertions.assertEquals(1, reviewFileComments.size()); 338 | Assertions.assertEquals(2, reviewFileComments.get(0).getSeverity()); 339 | ReviewLineComment reviewLineComment = (ReviewLineComment) reviewFileComments.get(0); 340 | Assertions.assertEquals(10, reviewLineComment.getLine().intValue()); 341 | } 342 | 343 | @Test 344 | public void shouldFoundFilenameByParsingGerritFileList() throws GerritPluginException { 345 | String path1WithProject = "P1/" + PATH1; 346 | settings.setProperty(PropertyKey.GERRIT_THRESHOLD, "INFO"); 347 | GerritConfiguration gerritConfiguration = new GerritConfiguration(settings); 348 | GerritFacadeFactory gerritFacadeFactory = mock(GerritFacadeFactory.class); 349 | GerritFacade gerritFacade = mock(GerritFacade.class); 350 | when(gerritFacadeFactory.getFacade()).thenReturn(gerritFacade); 351 | List listFiles = new ArrayList<>(); 352 | listFiles.add(path1WithProject); 353 | when(gerritFacade.listFiles()).thenReturn(listFiles); 354 | when(gerritFacade.parseFileName(path1WithProject)).thenReturn(PATH1); 355 | 356 | InputPath inputPath1 = createInputPath(PATH1, Boolean.TRUE); 357 | 358 | List postJobIssues = new ArrayList<>(); 359 | postJobIssues.add(createPostJobIssueMock(10, inputPath1, Severity.MAJOR, "R1", "Msg 1", Boolean.TRUE)); 360 | PostJobContext postJobContext = mock(PostJobContext.class); 361 | when(postJobContext.issues()).thenReturn(postJobIssues); 362 | 363 | GerritPostJob gerritPostJob = new GerritPostJob(settings, gerritConfiguration, gerritFacadeFactory); 364 | gerritPostJob.execute(postJobContext); 365 | 366 | verify(gerritFacade).setReview(reviewInputCaptor.capture()); 367 | ReviewInput reviewInput = reviewInputCaptor.getValue(); 368 | Map labels = reviewInput.getLabels(); 369 | Assertions.assertEquals(1, labels.size()); 370 | // Vote Value 371 | Integer integer = labels.get(LABEL); 372 | Assertions.assertNotNull(integer); 373 | Assertions.assertEquals(-2, integer.intValue()); 374 | Map> inputComments = reviewInput.getComments(); 375 | Assertions.assertEquals(1, inputComments.size()); 376 | List reviewFileComments = inputComments.get(path1WithProject); 377 | Assertions.assertEquals(1, reviewFileComments.size()); 378 | Assertions.assertEquals(2, reviewFileComments.get(0).getSeverity()); 379 | ReviewLineComment reviewLineComment = (ReviewLineComment) reviewFileComments.get(0); 380 | Assertions.assertEquals(10, reviewLineComment.getLine().intValue()); 381 | } 382 | 383 | @Test 384 | public void shouldIgnoreIssueWhenNotFoundFilename() throws GerritPluginException { 385 | settings.setProperty(PropertyKey.GERRIT_THRESHOLD, "INFO"); 386 | GerritConfiguration gerritConfiguration = new GerritConfiguration(settings); 387 | GerritFacadeFactory gerritFacadeFactory = mock(GerritFacadeFactory.class); 388 | GerritFacade gerritFacade = mock(GerritFacade.class); 389 | when(gerritFacadeFactory.getFacade()).thenReturn(gerritFacade); 390 | List listFiles = new ArrayList<>(); 391 | listFiles.add(PATH1); 392 | when(gerritFacade.listFiles()).thenReturn(listFiles); 393 | when(gerritFacade.parseFileName(PATH1)).thenReturn(PATH1); 394 | 395 | InputPath inputPath1 = createInputPath(PATH2, Boolean.TRUE); 396 | 397 | List postJobIssues = new ArrayList<>(); 398 | postJobIssues.add(createPostJobIssueMock(10, inputPath1, Severity.MAJOR, "R1", "Msg 1", Boolean.TRUE)); 399 | PostJobContext postJobContext = mock(PostJobContext.class); 400 | when(postJobContext.issues()).thenReturn(postJobIssues); 401 | 402 | GerritPostJob gerritPostJob = new GerritPostJob(settings, gerritConfiguration, gerritFacadeFactory); 403 | gerritPostJob.execute(postJobContext); 404 | 405 | verify(gerritFacade).setReview(reviewInputCaptor.capture()); 406 | ReviewInput reviewInput = reviewInputCaptor.getValue(); 407 | Map labels = reviewInput.getLabels(); 408 | Assertions.assertEquals(1, labels.size()); 409 | Integer integer = labels.get(LABEL); 410 | Assertions.assertNotNull(integer); 411 | Assertions.assertEquals(1, integer.intValue()); 412 | Assertions.assertEquals(0, reviewInput.getComments().size()); 413 | } 414 | 415 | @Test 416 | public void shouldIgnoreIssueWhenFileTypeIsNotFile() throws GerritPluginException { 417 | settings.setProperty(PropertyKey.GERRIT_THRESHOLD, "INFO"); 418 | GerritConfiguration gerritConfiguration = new GerritConfiguration(settings); 419 | GerritFacadeFactory gerritFacadeFactory = mock(GerritFacadeFactory.class); 420 | GerritFacade gerritFacade = mock(GerritFacade.class); 421 | when(gerritFacadeFactory.getFacade()).thenReturn(gerritFacade); 422 | List listFiles = new ArrayList<>(); 423 | listFiles.add(PATH1); 424 | when(gerritFacade.listFiles()).thenReturn(listFiles); 425 | when(gerritFacade.parseFileName(PATH1)).thenReturn(PATH1); 426 | 427 | InputPath inputPath1 = createInputPath(PATH1, Boolean.FALSE); 428 | 429 | List postJobIssues = new ArrayList<>(); 430 | postJobIssues.add(createPostJobIssueMock(10, inputPath1, Severity.MAJOR, "R1", "Msg 1", Boolean.TRUE)); 431 | PostJobContext postJobContext = mock(PostJobContext.class); 432 | when(postJobContext.issues()).thenReturn(postJobIssues); 433 | 434 | GerritPostJob gerritPostJob = new GerritPostJob(settings, gerritConfiguration, gerritFacadeFactory); 435 | gerritPostJob.execute(postJobContext); 436 | 437 | verify(gerritFacade).setReview(reviewInputCaptor.capture()); 438 | ReviewInput reviewInput = reviewInputCaptor.getValue(); 439 | Map labels = reviewInput.getLabels(); 440 | Assertions.assertEquals(1, labels.size()); 441 | Integer integer = labels.get(LABEL); 442 | Assertions.assertNotNull(integer); 443 | Assertions.assertEquals(1, integer.intValue()); 444 | Assertions.assertEquals(0, reviewInput.getComments().size()); 445 | } 446 | 447 | @Test 448 | public void shouldCatchThrownExceptionDuringGetListFileFromGerrit() throws GerritPluginException { 449 | settings.setProperty(PropertyKey.GERRIT_THRESHOLD, "INFO"); 450 | GerritConfiguration gerritConfiguration = new GerritConfiguration(settings); 451 | GerritFacadeFactory gerritFacadeFactory = mock(GerritFacadeFactory.class); 452 | GerritFacade gerritFacade = mock(GerritFacade.class); 453 | when(gerritFacadeFactory.getFacade()).thenReturn(gerritFacade); 454 | when(gerritFacade.listFiles()).thenThrow(new GerritPluginException("Test")); 455 | 456 | InputPath inputPath1 = createInputPath(PATH1, Boolean.TRUE); 457 | 458 | List postJobIssues = new ArrayList<>(); 459 | postJobIssues.add(createPostJobIssueMock(10, inputPath1, Severity.MAJOR, "R1", "Msg 1", Boolean.TRUE)); 460 | PostJobContext postJobContext = mock(PostJobContext.class); 461 | when(postJobContext.issues()).thenReturn(postJobIssues); 462 | 463 | GerritPostJob gerritPostJob = new GerritPostJob(settings, gerritConfiguration, gerritFacadeFactory); 464 | gerritPostJob.execute(postJobContext); 465 | 466 | verify(gerritFacade).setReview(reviewInputCaptor.capture()); 467 | ReviewInput reviewInput = reviewInputCaptor.getValue(); 468 | Map labels = reviewInput.getLabels(); 469 | Assertions.assertEquals(1, labels.size()); 470 | Integer integer = labels.get(LABEL); 471 | Assertions.assertNotNull(integer); 472 | Assertions.assertEquals(1, integer.intValue()); 473 | Assertions.assertEquals(0, reviewInput.getComments().size()); 474 | 475 | 476 | } 477 | 478 | @Test 479 | public void shouldCatchThrownExceptionDuringExecute() throws GerritPluginException { 480 | GerritConfiguration gerritConfiguration = new GerritConfiguration(settings); 481 | 482 | GerritFacadeFactory gerritFacadeFactory = mock(GerritFacadeFactory.class); 483 | GerritFacade gerritFacade = mock(GerritFacade.class); 484 | when(gerritFacadeFactory.getFacade()).thenReturn(gerritFacade); 485 | doThrow(new GerritPluginException("Test")).when(gerritFacade).setReview(any(ReviewInput.class)); 486 | PostJobContext postJobContext = mock(PostJobContext.class); 487 | when(postJobContext.issues()).thenReturn(new ArrayList<>()); 488 | 489 | GerritPostJob gerritPostJob = new GerritPostJob(settings, gerritConfiguration, gerritFacadeFactory); 490 | gerritPostJob.execute(postJobContext); 491 | } 492 | 493 | private PostJobIssue createPostJobIssueMock(int line, InputPath inputPath, Severity severity, String rule, String msg, Boolean isNew) { 494 | PostJobIssue postJobIssue = mock(PostJobIssue.class); 495 | when(postJobIssue.line()).thenReturn(line); 496 | when(postJobIssue.inputComponent()).thenReturn(inputPath); 497 | when(postJobIssue.severity()).thenReturn(severity); 498 | when(postJobIssue.ruleKey()).thenReturn(RuleKey.of("SQ-repo", rule)); 499 | when(postJobIssue.message()).thenReturn(msg); 500 | when(postJobIssue.isNew()).thenReturn(isNew); 501 | return postJobIssue; 502 | } 503 | 504 | private InputPath createInputPath(String path, Boolean isFile) { 505 | File file = mock(File.class); 506 | when(file.isFile()).thenReturn(isFile); 507 | InputPath inputPath = mock(InputPath.class); 508 | when(inputPath.file()).thenReturn(file); 509 | when(inputPath.relativePath()).thenReturn(path); 510 | return inputPath; 511 | } 512 | } 513 | -------------------------------------------------------------------------------- /src/test/java/fr/techad/sonar/gerrit/GerritFacadeTest.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.gerrit; 2 | 3 | import fr.techad.sonar.GerritPluginException; 4 | import fr.techad.sonar.gerrit.review.ReviewFileComment; 5 | import fr.techad.sonar.gerrit.review.ReviewInput; 6 | import fr.techad.sonar.gerrit.review.ReviewLineComment; 7 | import fr.techad.sonar.mockito.MockitoExtension; 8 | import org.junit.jupiter.api.Assertions; 9 | import org.junit.jupiter.api.Test; 10 | import org.junit.jupiter.api.extension.ExtendWith; 11 | import org.junit.platform.runner.JUnitPlatform; 12 | import org.junit.runner.RunWith; 13 | import org.mockito.ArgumentCaptor; 14 | import org.mockito.Captor; 15 | import org.mockito.Mock; 16 | import org.mockito.Mockito; 17 | 18 | import java.io.IOException; 19 | import java.util.ArrayList; 20 | import java.util.HashMap; 21 | import java.util.List; 22 | import java.util.Map; 23 | 24 | import static org.hamcrest.CoreMatchers.is; 25 | import static org.junit.Assert.assertThat; 26 | import static org.mockito.Mockito.when; 27 | 28 | @ExtendWith(MockitoExtension.class) 29 | @RunWith(JUnitPlatform.class) 30 | public class GerritFacadeTest { 31 | 32 | @Mock 33 | GerritConnector gerritConnectorMock; 34 | 35 | @Captor 36 | ArgumentCaptor argCaptor; 37 | 38 | @Test 39 | public void shouldCallOnceFillListFilesFromGerrit() throws GerritPluginException { 40 | GerritFacade gerritFacade = new GerritFacadeUT(gerritConnectorMock); 41 | // First call 42 | List listFiles = gerritFacade.listFiles(); 43 | Assertions.assertEquals(1, listFiles.size()); 44 | Assertions.assertEquals("FileNameClass.java", listFiles.get(0)); 45 | // Second call: should be ignored -> cnt=1 46 | gerritFacade.listFiles(); 47 | Assertions.assertEquals(1, ((GerritFacadeUT) gerritFacade).getCnt()); 48 | } 49 | 50 | @Test 51 | public void shouldSetReview() throws GerritPluginException, IOException { 52 | ReviewInput reviewInputMock = Mockito.mock(ReviewInput.class); 53 | // Mock the message 54 | when(reviewInputMock.getMessage()).thenReturn("Message Test"); 55 | // Mock labels 56 | Map labels = new HashMap<>(); 57 | labels.put("Quality Control", 1); 58 | labels.put("Verify", 2); 59 | when(reviewInputMock.getLabels()).thenReturn(labels); 60 | // Mock comments 61 | ReviewLineComment reviewLineCommentMock = Mockito.mock(ReviewLineComment.class); 62 | when(reviewLineCommentMock.getLine()).thenReturn(1, 4, 6, 8).thenReturn(null); 63 | when(reviewLineCommentMock.getMessage()).thenReturn("Msg1", "Msg2", "Msg3", "Msg4").thenReturn(null); 64 | List reviewFileComments = new ArrayList<>(); 65 | reviewFileComments.add(reviewLineCommentMock); 66 | reviewFileComments.add(reviewLineCommentMock); 67 | Map> comments = new HashMap<>(); 68 | comments.put("FileTest1.java", reviewFileComments); 69 | comments.put("FileTest2.java", reviewFileComments); 70 | when(reviewInputMock.getComments()).thenReturn(comments); 71 | 72 | GerritFacade gerritFacade = new GerritFacadeUT(gerritConnectorMock); 73 | gerritFacade.setReview(reviewInputMock); 74 | 75 | Mockito.verify(gerritConnectorMock).setReview(argCaptor.capture()); 76 | String captorValue = argCaptor.getValue(); 77 | Assertions.assertEquals("{\"message\":\"Message Test\",\"labels\":{\"Verify\":2,\"Quality Control\":1},\"comments\":{\"FileTest2.java\":[{\"line\":1,\"message\":\"Msg1\"},{\"line\":4,\"message\":\"Msg2\"}],\"FileTest1.java\":[{\"line\":6,\"message\":\"Msg3\"},{\"line\":8,\"message\":\"Msg4\"}]}}", captorValue); 78 | } 79 | 80 | @Test 81 | public void shouldSetReviewOnlyMessage() throws GerritPluginException, IOException { 82 | ReviewInput reviewInputMock = Mockito.mock(ReviewInput.class); 83 | when(reviewInputMock.getMessage()).thenReturn("Message Test"); 84 | 85 | GerritFacade gerritFacade = new GerritFacadeUT(gerritConnectorMock); 86 | gerritFacade.setReview(reviewInputMock); 87 | 88 | Mockito.verify(gerritConnectorMock).setReview(argCaptor.capture()); 89 | String captorValue = argCaptor.getValue(); 90 | Assertions.assertEquals("{\"message\":\"Message Test\"}", captorValue); 91 | } 92 | 93 | @Test 94 | public void shouldSetReviewWithNullMessage() throws GerritPluginException, IOException { 95 | 96 | ReviewInput reviewInputMock = Mockito.mock(ReviewInput.class); 97 | when(reviewInputMock.getMessage()).thenReturn(null); 98 | 99 | GerritFacade gerritFacade = new GerritFacadeUT(gerritConnectorMock); 100 | gerritFacade.setReview(reviewInputMock); 101 | 102 | Mockito.verify(gerritConnectorMock).setReview(argCaptor.capture()); 103 | String captorValue = argCaptor.getValue(); 104 | Assertions.assertEquals("{\"message\":null}", captorValue); 105 | } 106 | 107 | @Test 108 | public void shouldThrowException() { 109 | Assertions.assertThrows(GerritPluginException.class, () -> { 110 | ReviewInput reviewInputMock = Mockito.mock(ReviewInput.class); 111 | GerritFacade gerritFacade = new GerritFacadeUT(gerritConnectorMock); 112 | when(gerritConnectorMock.setReview(Mockito.any())).thenThrow(new IOException("Test")); 113 | gerritFacade.setReview(reviewInputMock); 114 | }); 115 | } 116 | 117 | @Test 118 | public void shouldGetGerritConnector() { 119 | GerritFacade gerritFacade = new GerritFacadeUT(gerritConnectorMock); 120 | Assertions.assertEquals(gerritConnectorMock, gerritFacade.getGerritConnector()); 121 | } 122 | 123 | @Test 124 | public void testParseFileName() { 125 | GerritFacade facade = Mockito.mock(GerritFacade.class, Mockito.CALLS_REAL_METHODS); 126 | assertThat(facade.parseFileName("subdirectory/src/fr/techad/sonar/gerrit/GerritFacadeTest.java"), 127 | is("src/fr/techad/sonar/gerrit/GerritFacadeTest.java")); 128 | assertThat(facade.parseFileName("fr/techad/sonar/gerrit/GerritFacadeTest.java"), 129 | is("fr/techad/sonar/gerrit/GerritFacadeTest.java")); 130 | assertThat(facade.parseFileName("sub1/sub2/sub3/sub4/src/fr/techad/sonar/gerrit/GerritFacadeTest.java"), 131 | is("src/fr/techad/sonar/gerrit/GerritFacadeTest.java")); 132 | assertThat(facade.parseFileName("subdirectory/src/main/java/src/fr/techad/sonar/gerrit/GerritFacadeTest.java"), 133 | is("src/main/java/src/fr/techad/sonar/gerrit/GerritFacadeTest.java")); 134 | assertThat(facade.parseFileName("src/main/java/src/fr/techad/sonar/gerrit/GerritFacadeTest.java"), 135 | is("src/main/java/src/fr/techad/sonar/gerrit/GerritFacadeTest.java")); 136 | assertThat(facade.parseFileName("/src/main/java/src/fr/techad/sonar/gerrit/GerritFacadeTest.java"), 137 | is("src/main/java/src/fr/techad/sonar/gerrit/GerritFacadeTest.java")); 138 | } 139 | 140 | class GerritFacadeUT extends GerritFacade { 141 | private int cnt = 0; 142 | 143 | public GerritFacadeUT(GerritConnector gerritConnector) { 144 | super(gerritConnector); 145 | } 146 | 147 | @Override 148 | protected void fillListFilesFromGerrit() throws GerritPluginException { 149 | addFile("FileNameClass.java"); 150 | addFile("/COMMIT_MSG"); // Should be ignored because it's the commit message "key" 151 | cnt++; 152 | } 153 | 154 | public int getCnt() { 155 | return cnt; 156 | } 157 | } 158 | 159 | } 160 | -------------------------------------------------------------------------------- /src/test/java/fr/techad/sonar/gerrit/factory/GerritConnectorFactoryTest.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.gerrit.factory; 2 | 3 | import fr.techad.sonar.GerritConfiguration; 4 | import fr.techad.sonar.GerritConstants; 5 | import fr.techad.sonar.gerrit.GerritConnector; 6 | import fr.techad.sonar.gerrit.network.rest.GerritRestConnector; 7 | import fr.techad.sonar.gerrit.network.ssh.GerritSshConnector; 8 | import fr.techad.sonar.mockito.MockitoExtension; 9 | import org.junit.jupiter.api.Test; 10 | import org.junit.jupiter.api.extension.ExtendWith; 11 | import org.junit.platform.runner.JUnitPlatform; 12 | import org.junit.runner.RunWith; 13 | import org.mockito.Mock; 14 | import org.mockito.Mockito; 15 | 16 | import static org.junit.Assert.assertEquals; 17 | 18 | @ExtendWith(MockitoExtension.class) 19 | @RunWith(JUnitPlatform.class) 20 | public class GerritConnectorFactoryTest { 21 | @Mock 22 | private GerritConfiguration gerritConfiguration; 23 | 24 | @Test 25 | public void shouldGetConnectorAsGerritRestConnectorWhenSchemeIsHttp() throws Exception { 26 | Mockito.when(gerritConfiguration.getScheme()).thenReturn(GerritConstants.SCHEME_HTTP); 27 | GerritConnectorFactory gerritConnectorFactory = new GerritConnectorFactory(gerritConfiguration); 28 | GerritConnector gerritConnector = gerritConnectorFactory.getConnector(); 29 | assertEquals(true, gerritConnector instanceof GerritRestConnector); 30 | } 31 | 32 | @Test 33 | public void shouldGetConnectorAsGerritRestConnectorWhenSchemeIsHttps() throws Exception { 34 | Mockito.when(gerritConfiguration.getScheme()).thenReturn(GerritConstants.SCHEME_HTTPS); 35 | GerritConnectorFactory gerritConnectorFactory = new GerritConnectorFactory(gerritConfiguration); 36 | GerritConnector gerritConnector = gerritConnectorFactory.getConnector(); 37 | assertEquals(true, gerritConnector instanceof GerritRestConnector); 38 | } 39 | 40 | @Test 41 | public void shouldGetConnectorAsGerritSshConnectorWhenSchemeIsSSh() throws Exception { 42 | Mockito.when(gerritConfiguration.getScheme()).thenReturn(GerritConstants.SCHEME_SSH); 43 | Mockito.when(gerritConfiguration.getUsername()).thenReturn("user"); 44 | Mockito.when(gerritConfiguration.getHost()).thenReturn("localhost"); 45 | Mockito.when(gerritConfiguration.getPort()).thenReturn(22); 46 | GerritConnectorFactory gerritConnectorFactory = new GerritConnectorFactory(gerritConfiguration); 47 | GerritConnector gerritConnector = gerritConnectorFactory.getConnector(); 48 | assertEquals(true, gerritConnector instanceof GerritSshConnector); 49 | } 50 | 51 | @Test 52 | public void shouldGetConnectorAsNullWhenSchemeIsUnknown() throws Exception { 53 | Mockito.when(gerritConfiguration.getScheme()).thenReturn("UnknownProtocol"); 54 | GerritConnectorFactory gerritConnectorFactory = new GerritConnectorFactory(gerritConfiguration); 55 | GerritConnector gerritConnector = gerritConnectorFactory.getConnector(); 56 | assertEquals(null, gerritConnector); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/test/java/fr/techad/sonar/gerrit/factory/GerritFacadeFactoryTest.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.gerrit.factory; 2 | 3 | import fr.techad.sonar.GerritConfiguration; 4 | import fr.techad.sonar.GerritConstants; 5 | import fr.techad.sonar.gerrit.GerritFacade; 6 | import fr.techad.sonar.gerrit.network.rest.GerritRestFacade; 7 | import fr.techad.sonar.gerrit.network.ssh.GerritSshFacade; 8 | import fr.techad.sonar.mockito.MockitoExtension; 9 | import org.junit.jupiter.api.Test; 10 | import org.junit.jupiter.api.extension.ExtendWith; 11 | import org.junit.platform.runner.JUnitPlatform; 12 | import org.junit.runner.RunWith; 13 | import org.mockito.Mock; 14 | import org.mockito.Mockito; 15 | 16 | import static org.junit.Assert.assertEquals; 17 | 18 | @ExtendWith(MockitoExtension.class) 19 | @RunWith(JUnitPlatform.class) 20 | public class GerritFacadeFactoryTest { 21 | @Mock 22 | private GerritConfiguration gerritConfiguration; 23 | 24 | @Test 25 | public void shouldGetFacadeAsGerritRestFaceWhenConnectorIsGerritRestConnector() throws Exception { 26 | Mockito.when(gerritConfiguration.getScheme()).thenReturn(GerritConstants.SCHEME_HTTP); 27 | GerritConnectorFactory gerritConnectorFactory = new GerritConnectorFactory(gerritConfiguration); 28 | GerritFacadeFactory gerritFacadeFactory = new GerritFacadeFactory(gerritConnectorFactory); 29 | GerritFacade gerritFacade = gerritFacadeFactory.getFacade(); 30 | assertEquals(true, gerritFacade instanceof GerritRestFacade); 31 | } 32 | 33 | @Test 34 | public void shouldGetFacadeAsGerritSshFacadeWhenConnectorIsGerritSshConnector() throws Exception { 35 | Mockito.when(gerritConfiguration.getScheme()).thenReturn(GerritConstants.SCHEME_SSH); 36 | Mockito.when(gerritConfiguration.getUsername()).thenReturn("user"); 37 | Mockito.when(gerritConfiguration.getHost()).thenReturn("localhost"); 38 | Mockito.when(gerritConfiguration.getPort()).thenReturn(22); 39 | GerritConnectorFactory gerritConnectorFactory = new GerritConnectorFactory(gerritConfiguration); 40 | GerritFacadeFactory gerritFacadeFactory = new GerritFacadeFactory(gerritConnectorFactory); 41 | GerritFacade gerritFacade = gerritFacadeFactory.getFacade(); 42 | assertEquals(true, gerritFacade instanceof GerritSshFacade); 43 | } 44 | 45 | @Test 46 | public void shouldGetFacadeAsNullWhenConnectorIsUnknown() throws Exception { 47 | Mockito.when(gerritConfiguration.getScheme()).thenReturn("UnknownProtocol"); 48 | GerritConnectorFactory gerritConnectorFactory = new GerritConnectorFactory(gerritConfiguration); 49 | GerritFacadeFactory gerritFacadeFactory = new GerritFacadeFactory(gerritConnectorFactory); 50 | GerritFacade gerritFacade = gerritFacadeFactory.getFacade(); 51 | assertEquals(null, gerritFacade); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/fr/techad/sonar/gerrit/network/rest/GerritRestConnectorTest.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.gerrit.network.rest; 2 | 3 | import fr.techad.sonar.GerritConfiguration; 4 | import fr.techad.sonar.GerritConstants; 5 | import fr.techad.sonar.GerritPluginException; 6 | import fr.techad.sonar.PropertyKey; 7 | import fr.techad.sonar.gerrit.GerritConnector; 8 | import fr.techad.sonar.gerrit.factory.GerritConnectorFactory; 9 | import fr.techad.sonar.mockito.MockitoExtension; 10 | import org.apache.commons.lang3.StringUtils; 11 | import org.junit.jupiter.api.AfterAll; 12 | import org.junit.jupiter.api.Assertions; 13 | import org.junit.jupiter.api.BeforeAll; 14 | import org.junit.jupiter.api.BeforeEach; 15 | import org.junit.jupiter.api.Test; 16 | import org.junit.jupiter.api.TestInstance; 17 | import org.junit.jupiter.api.extension.ExtendWith; 18 | import org.junit.platform.runner.JUnitPlatform; 19 | import org.junit.runner.RunWith; 20 | import org.mockserver.integration.ClientAndServer; 21 | import org.mockserver.model.Header; 22 | import org.sonar.api.config.internal.MapSettings; 23 | 24 | import java.io.IOException; 25 | import java.util.concurrent.TimeUnit; 26 | 27 | import static org.junit.jupiter.api.Assertions.assertEquals; 28 | import static org.mockserver.integration.ClientAndServer.startClientAndServer; 29 | import static org.mockserver.model.HttpRequest.request; 30 | import static org.mockserver.model.HttpResponse.response; 31 | 32 | @ExtendWith(MockitoExtension.class) 33 | @RunWith(JUnitPlatform.class) 34 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 35 | public class GerritRestConnectorTest { 36 | static private String listFiles = ")]}'" + 37 | " {" + 38 | " \"/COMMIT_MSG\": {" + 39 | " \"status\": \"A\"," + 40 | " \"lines_inserted\": 7," + 41 | " \"size_delta\": 551," + 42 | " \"size\": 551" + 43 | " }," + 44 | " \"gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java\": {" + 45 | " \"status\": \"D\"," + 46 | " \"lines_inserted\": 5," + 47 | " \"lines_deleted\": 3," + 48 | " \"size_delta\": 98," + 49 | " \"size\": 23348" + 50 | " }" + 51 | " }"; 52 | private MapSettings settings; 53 | private ClientAndServer mockServer; 54 | 55 | @BeforeAll 56 | public void startServer() { 57 | mockServer = startClientAndServer(10800); 58 | } 59 | 60 | @BeforeEach 61 | public void setUp() { 62 | // Common Settings 63 | settings = new MapSettings(); 64 | settings.setProperty(PropertyKey.GERRIT_SCHEME, GerritConstants.SCHEME_HTTP) 65 | .setProperty(PropertyKey.GERRIT_HOST, "localhost") 66 | .appendProperty(PropertyKey.GERRIT_PORT, "10800") 67 | .setProperty(PropertyKey.GERRIT_PROJECT, "project") 68 | .setProperty(PropertyKey.GERRIT_CHANGE_ID, "changeid") 69 | .setProperty(PropertyKey.GERRIT_REVISION_ID, "revisionid") 70 | .setProperty(PropertyKey.GERRIT_LABEL, "Code-Review"); 71 | } 72 | 73 | @AfterAll 74 | public void stopServer() { 75 | mockServer.stop(); 76 | } 77 | 78 | @Test 79 | public void shouldAggregateBasicParamsWhenAuthenticated() throws GerritPluginException { 80 | // given 81 | settings.setProperty(PropertyKey.GERRIT_USERNAME, "sonar") 82 | .setProperty(PropertyKey.GERRIT_PASSWORD, "sonar") 83 | .appendProperty(PropertyKey.GERRIT_BASE_PATH, "") 84 | .setProperty(PropertyKey.GERRIT_BRANCH, "branch"); 85 | 86 | // when 87 | GerritRestConnector gerritRestConnector = getRestConnector(); 88 | 89 | // then 90 | assertEquals("/a/changes/project~branch~changeid/revisions/revisionid", 91 | gerritRestConnector.rootUriBuilder()); 92 | } 93 | 94 | @Test 95 | public void shouldEncodeBranchWithSlash() throws GerritPluginException { 96 | // given 97 | settings.setProperty(PropertyKey.GERRIT_USERNAME, "sonar") 98 | .setProperty(PropertyKey.GERRIT_PASSWORD, "sonar") 99 | .appendProperty(PropertyKey.GERRIT_BASE_PATH, "") 100 | .setProperty(PropertyKey.GERRIT_BRANCH, "branch/subbranch"); 101 | 102 | // when 103 | GerritRestConnector gerritRestConnector = getRestConnector(); 104 | 105 | // then 106 | assertEquals("/a/changes/project~branch%2Fsubbranch~changeid/revisions/revisionid", 107 | gerritRestConnector.rootUriBuilder()); 108 | } 109 | 110 | @Test 111 | public void shouldPrependCustomBasePath() throws GerritPluginException { 112 | // given 113 | settings.setProperty(PropertyKey.GERRIT_USERNAME, "sonar") 114 | .setProperty(PropertyKey.GERRIT_PASSWORD, "sonar") 115 | .appendProperty(PropertyKey.GERRIT_BASE_PATH, "/r") 116 | .setProperty(PropertyKey.GERRIT_BRANCH, "branch/subbranch"); 117 | 118 | // when 119 | GerritRestConnector gerritRestConnector = getRestConnector(); 120 | 121 | // then 122 | assertEquals("/r/a/changes/project~branch%2Fsubbranch~changeid/revisions/revisionid", 123 | gerritRestConnector.rootUriBuilder()); 124 | } 125 | 126 | @Test 127 | public void shouldAggregateBasicParamsWhenAnonymous() throws GerritPluginException { 128 | // given 129 | settings.setProperty(PropertyKey.GERRIT_USERNAME, "").appendProperty(PropertyKey.GERRIT_PASSWORD, "") 130 | .setProperty(PropertyKey.GERRIT_BASE_PATH, "") 131 | .setProperty(PropertyKey.GERRIT_BRANCH, "branch/subbranch"); 132 | // when 133 | GerritRestConnector gerritRestConnector = getRestConnector(); 134 | 135 | // then 136 | assertEquals("/changes/project~branch%2Fsubbranch~changeid/revisions/revisionid", 137 | gerritRestConnector.rootUriBuilder()); 138 | } 139 | 140 | @Test 141 | public void shouldPrependCustomBasePathWhenAnonymous() throws GerritPluginException { 142 | // given 143 | settings.setProperty(PropertyKey.GERRIT_USERNAME, "").appendProperty(PropertyKey.GERRIT_PASSWORD, "") 144 | .setProperty(PropertyKey.GERRIT_BASE_PATH, "/r") 145 | .setProperty(PropertyKey.GERRIT_BRANCH, "branch/subbranch"); 146 | // when 147 | GerritRestConnector gerritRestConnector = getRestConnector(); 148 | 149 | // then 150 | assertEquals("/r/changes/project~branch%2Fsubbranch~changeid/revisions/revisionid", 151 | gerritRestConnector.rootUriBuilder()); 152 | } 153 | 154 | @Test 155 | public void shouldSetReview() throws IOException { 156 | mockServer.when( 157 | request() 158 | .withPath("/a/changes/project~branch~changeid/revisions/revisionid/review") 159 | .withMethod("POST")) 160 | .respond( 161 | response() 162 | .withStatusCode(200) 163 | .withHeaders( 164 | new Header("Content-Type", "application/json; charset=utf-8"), 165 | new Header("Cache-Control", "public, max-age=86400")) 166 | .withBody("{ message: 'Review committed' }") 167 | .withDelay(TimeUnit.SECONDS, 1) 168 | ); 169 | settings.setProperty(PropertyKey.GERRIT_USERNAME, "sonar") 170 | .setProperty(PropertyKey.GERRIT_PASSWORD, "sonar") 171 | .appendProperty(PropertyKey.GERRIT_BASE_PATH, "") 172 | .setProperty(PropertyKey.GERRIT_BRANCH, "branch"); 173 | 174 | String response = getRestConnector().setReview("review"); 175 | Assertions.assertEquals("{ message: 'Review committed' }", response); 176 | } 177 | 178 | @Test 179 | public void shouldSetReviewWithNullResponseBody() throws IOException { 180 | mockServer.when( 181 | request() 182 | .withPath("/a/changes/project~branch~changeid2/revisions/revisionid/review") 183 | .withMethod("POST")) 184 | .respond( 185 | response() 186 | .withStatusCode(200) 187 | .withHeaders( 188 | new Header("Content-Type", "application/json; charset=utf-8"), 189 | new Header("Cache-Control", "public, max-age=86400")) 190 | .withDelay(TimeUnit.SECONDS, 1) 191 | ); 192 | settings.setProperty(PropertyKey.GERRIT_USERNAME, "sonar") 193 | .setProperty(PropertyKey.GERRIT_PASSWORD, "sonar") 194 | .appendProperty(PropertyKey.GERRIT_BASE_PATH, "") 195 | .setProperty(PropertyKey.GERRIT_BRANCH, "branch") 196 | .setProperty(PropertyKey.GERRIT_CHANGE_ID, "changeid2") 197 | ; 198 | 199 | String response = getRestConnector().setReview("review"); 200 | Assertions.assertEquals(StringUtils.EMPTY, response); 201 | } 202 | 203 | @Test 204 | public void shouldSetReviewAsAnonymous() throws IOException { 205 | mockServer.when( 206 | request() 207 | .withPath("/changes/project~branch~changeid/revisions/revisionid/review") 208 | .withMethod("POST")) 209 | .respond( 210 | response() 211 | .withStatusCode(200) 212 | .withHeaders( 213 | new Header("Content-Type", "application/json; charset=utf-8"), 214 | new Header("Cache-Control", "public, max-age=86400")) 215 | .withBody("{ message: 'Review committed' }") 216 | .withDelay(TimeUnit.SECONDS, 1) 217 | ); 218 | settings.setProperty(PropertyKey.GERRIT_BRANCH, "branch"); 219 | 220 | String response = getRestConnector().setReview("review"); 221 | Assertions.assertEquals("{ message: 'Review committed' }", response); 222 | } 223 | 224 | @Test 225 | public void shouldListFiles() throws IOException { 226 | mockServer.when( 227 | request() 228 | .withPath("/a/changes/project~branch~changeid/revisions/revisionid/files/") 229 | .withMethod("GET")) 230 | .respond( 231 | response() 232 | .withStatusCode(200) 233 | .withHeaders( 234 | new Header("Content-Type", "application/json; charset=utf-8"), 235 | new Header("Cache-Control", "public, max-age=86400")) 236 | .withBody(listFiles) 237 | .withDelay(TimeUnit.SECONDS, 1) 238 | ); 239 | settings.setProperty(PropertyKey.GERRIT_USERNAME, "sonar") 240 | .setProperty(PropertyKey.GERRIT_PASSWORD, "sonar") 241 | .appendProperty(PropertyKey.GERRIT_BASE_PATH, "") 242 | .setProperty(PropertyKey.GERRIT_BRANCH, "branch"); 243 | 244 | String response = getRestConnector().listFiles(); 245 | Assertions.assertEquals(listFiles, response); 246 | } 247 | 248 | private GerritRestConnector getRestConnector() { 249 | GerritConfiguration gerritConfiguration = new GerritConfiguration(settings); 250 | GerritConnector gerritConnector = new GerritConnectorFactory(gerritConfiguration).getConnector(); 251 | return (GerritRestConnector) gerritConnector; 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /src/test/java/fr/techad/sonar/gerrit/network/rest/GerritRestFacadeTest.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.gerrit.network.rest; 2 | 3 | import fr.techad.sonar.GerritPluginException; 4 | import fr.techad.sonar.gerrit.GerritConnector; 5 | import fr.techad.sonar.mockito.MockitoExtension; 6 | import org.junit.jupiter.api.Assertions; 7 | import org.junit.jupiter.api.DisplayName; 8 | import org.junit.jupiter.api.Test; 9 | import org.junit.jupiter.api.extension.ExtendWith; 10 | import org.junit.platform.runner.JUnitPlatform; 11 | import org.junit.runner.RunWith; 12 | import org.mockito.Mock; 13 | 14 | import java.io.IOException; 15 | import java.util.List; 16 | 17 | import static org.mockito.Mockito.when; 18 | 19 | /** 20 | * TECH ADVANTAGE 21 | * All right reserved 22 | * Created by cochon on 21/07/2018. 23 | */ 24 | @ExtendWith(MockitoExtension.class) 25 | @RunWith(JUnitPlatform.class) 26 | public class GerritRestFacadeTest { 27 | 28 | @Mock 29 | private GerritConnector gerritConnector; 30 | 31 | @Test 32 | @DisplayName("Should return a list files") 33 | public void shouldGetListFiles() throws IOException, GerritPluginException { 34 | String response = ")]}'\n" + 35 | " {\n" + 36 | " \"/COMMIT_MSG\": {\n" + 37 | " \"status\": \"A\",\n" + 38 | " \"lines_inserted\": 7,\n" + 39 | " \"size_delta\": 551,\n" + 40 | " \"size\": 551\n" + 41 | " },\n" + 42 | " \"gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java\": {\n" + 43 | " \"lines_inserted\": 5,\n" + 44 | " \"lines_deleted\": 3,\n" + 45 | " \"size_delta\": 98,\n" + 46 | " \"size\": 23348\n" + 47 | " },\n" + 48 | " \"gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl2.java\": {\n" + 49 | " \"lines_inserted\": 5,\n" + 50 | " \"lines_deleted\": 3,\n" + 51 | " \"size_delta\": 98,\n" + 52 | " \"size\": 23348\n" + 53 | " }\n" + 54 | " }"; 55 | when(gerritConnector.listFiles()).thenReturn(response); 56 | 57 | GerritRestFacade gerritRestFacade = new GerritRestFacade(gerritConnector); 58 | // Will call fillListFilesFromGerrit 59 | List listFiles = gerritRestFacade.listFiles(); 60 | Assertions.assertEquals(2, listFiles.size()); 61 | Assertions.assertEquals("gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java", listFiles.get(0)); 62 | Assertions.assertEquals("gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl2.java", listFiles.get(1)); 63 | } 64 | 65 | @Test 66 | @DisplayName("Should return a list files with a defined status") 67 | public void shouldGetListFilesWithStatus() throws IOException, GerritPluginException { 68 | String response = ")]}'\n" + 69 | " {\n" + 70 | " \"/COMMIT_MSG\": {\n" + 71 | " \"status\": \"A\",\n" + 72 | " \"lines_inserted\": 7,\n" + 73 | " \"size_delta\": 551,\n" + 74 | " \"size\": 551\n" + 75 | " },\n" + 76 | " \"gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java\": {\n" + 77 | " \"status\": \"A\",\n" + 78 | " \"lines_inserted\": 5,\n" + 79 | " \"lines_deleted\": 3,\n" + 80 | " \"size_delta\": 98,\n" + 81 | " \"size\": 23348\n" + 82 | " }\n" + 83 | " }"; 84 | when(gerritConnector.listFiles()).thenReturn(response); 85 | 86 | GerritRestFacade gerritRestFacade = new GerritRestFacade(gerritConnector); 87 | // Will call fillListFilesFromGerrit 88 | List listFiles = gerritRestFacade.listFiles(); 89 | Assertions.assertEquals(1, listFiles.size()); 90 | Assertions.assertEquals("gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java", listFiles.get(0)); 91 | 92 | } 93 | 94 | @Test 95 | @DisplayName("Should ignored deleted file") 96 | public void shouldIgnoredDeletedFiles() throws IOException, GerritPluginException { 97 | String response = ")]}'\n" + 98 | " {\n" + 99 | " \"/COMMIT_MSG\": {\n" + 100 | " \"status\": \"A\",\n" + 101 | " \"lines_inserted\": 7,\n" + 102 | " \"size_delta\": 551,\n" + 103 | " \"size\": 551\n" + 104 | " },\n" + 105 | " \"gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java\": {\n" + 106 | " \"status\": \"D\",\n" + 107 | " \"lines_inserted\": 5,\n" + 108 | " \"lines_deleted\": 3,\n" + 109 | " \"size_delta\": 98,\n" + 110 | " \"size\": 23348\n" + 111 | " }\n" + 112 | " }"; 113 | when(gerritConnector.listFiles()).thenReturn(response); 114 | 115 | GerritRestFacade gerritRestFacade = new GerritRestFacade(gerritConnector); 116 | // Will call fillListFilesFromGerrit 117 | List listFiles = gerritRestFacade.listFiles(); 118 | Assertions.assertEquals(0, listFiles.size()); 119 | 120 | } 121 | 122 | @Test 123 | @DisplayName("Should return an empty list if the review doesn't contain file") 124 | public void shouldReturnEmptyListIfReviewIsEmpty() throws IOException, GerritPluginException { 125 | String response = ")]}'\n" + 126 | " {\n" + 127 | " \"/COMMIT_MSG\": {\n" + 128 | " \"status\": \"A\",\n" + 129 | " \"lines_inserted\": 7,\n" + 130 | " \"size_delta\": 551,\n" + 131 | " \"size\": 551\n" + 132 | " }\n" + 133 | " }"; 134 | when(gerritConnector.listFiles()).thenReturn(response); 135 | 136 | GerritRestFacade gerritRestFacade = new GerritRestFacade(gerritConnector); 137 | // Will call fillListFilesFromGerrit 138 | List listFiles = gerritRestFacade.listFiles(); 139 | Assertions.assertEquals(0, listFiles.size()); 140 | 141 | } 142 | 143 | @Test 144 | @DisplayName("Should throw an exception on IOException") 145 | public void shouldThrowAnGerritException() { 146 | Assertions.assertThrows(GerritPluginException.class, () -> { 147 | when(gerritConnector.listFiles()).thenThrow(new IOException("Error during Test")); 148 | 149 | GerritRestFacade gerritRestFacade = new GerritRestFacade(gerritConnector); 150 | // Will call fillListFilesFromGerrit 151 | gerritRestFacade.listFiles(); 152 | }); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/test/java/fr/techad/sonar/gerrit/network/ssh/GerritSshFacadeTest.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.gerrit.network.ssh; 2 | 3 | import fr.techad.sonar.GerritPluginException; 4 | import fr.techad.sonar.gerrit.GerritConnector; 5 | import fr.techad.sonar.mockito.MockitoExtension; 6 | import org.junit.jupiter.api.Assertions; 7 | import org.junit.jupiter.api.DisplayName; 8 | import org.junit.jupiter.api.Test; 9 | import org.junit.jupiter.api.extension.ExtendWith; 10 | import org.junit.platform.runner.JUnitPlatform; 11 | import org.junit.runner.RunWith; 12 | import org.mockito.Mock; 13 | 14 | import java.io.IOException; 15 | import java.util.List; 16 | 17 | import static org.mockito.Mockito.when; 18 | 19 | /** 20 | * TECH ADVANTAGE 21 | * All right reserved 22 | * Created by cochon on 21/07/2018. 23 | */ 24 | @ExtendWith(MockitoExtension.class) 25 | @RunWith(JUnitPlatform.class) 26 | public class GerritSshFacadeTest { 27 | private static String COMMON_RESPONSE = "\"project\":\"sonar-gerrit-plugin\",\"branch\":\"feature/test\",\"id\":\"I218fb47cc01cbca2809dc82d54de019a60\",\"number\":11782,\"subject\":\"To develop\","; 28 | @Mock 29 | private GerritConnector gerritConnector; 30 | 31 | @Test 32 | @DisplayName("Should return a list files") 33 | public void shouldGetListFiles() throws IOException, GerritPluginException { 34 | String response = "{" + COMMON_RESPONSE + 35 | " \"currentPatchSet\": {" + 36 | "\"files\": [" + 37 | "{ " + 38 | "\"file\": \"gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java\"," + 39 | "\"type\": \"ADDED\"" + 40 | "}," + 41 | "{ " + 42 | "\"file\": \"gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl2.java\"," + 43 | "\"type\": \"ADDED\"" + 44 | "}" + 45 | "]" + 46 | "}" + 47 | "}"; 48 | when(gerritConnector.listFiles()).thenReturn(response); 49 | 50 | GerritSshFacade gerritSshFacade = new GerritSshFacade(gerritConnector); 51 | // Will call fillListFilesFromGerrit 52 | List listFiles = gerritSshFacade.listFiles(); 53 | Assertions.assertEquals(2, listFiles.size()); 54 | Assertions.assertEquals("gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java", listFiles.get(0)); 55 | Assertions.assertEquals("gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl2.java", listFiles.get(1)); 56 | } 57 | 58 | @Test 59 | @DisplayName("Should return a list files with a defined type") 60 | public void shouldGetListFilesWithType() throws IOException, GerritPluginException { 61 | String response = "{" + COMMON_RESPONSE + 62 | " \"currentPatchSet\": {" + 63 | "\"files\": [" + 64 | "{ " + 65 | "\"file\": \"gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java\"," + 66 | "\"type\": \"ADDED\"" + 67 | "}" + 68 | "]" + 69 | "}" + 70 | "}"; 71 | when(gerritConnector.listFiles()).thenReturn(response); 72 | 73 | GerritSshFacade gerritSshFacade = new GerritSshFacade(gerritConnector); 74 | // Will call fillListFilesFromGerrit 75 | List listFiles = gerritSshFacade.listFiles(); 76 | Assertions.assertEquals(1, listFiles.size()); 77 | Assertions.assertEquals("gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java", listFiles.get(0)); 78 | } 79 | 80 | @Test 81 | @DisplayName("Should ignored deleted file") 82 | public void shouldIgnoredDeletedFiles() throws IOException, GerritPluginException { 83 | String response = "{" + COMMON_RESPONSE + 84 | " \"currentPatchSet\": {" + 85 | "\"files\": [" + 86 | "{ " + 87 | "\"file\": \"gerrit-server/src/main/java/com/google/gerrit/server/project/RefControl.java\"," + 88 | "\"type\": \"DELETED\"" + 89 | "}" + 90 | "]" + 91 | "}" + 92 | "}"; 93 | when(gerritConnector.listFiles()).thenReturn(response); 94 | 95 | GerritSshFacade gerritSshFacade = new GerritSshFacade(gerritConnector); 96 | // Will call fillListFilesFromGerrit 97 | List listFiles = gerritSshFacade.listFiles(); 98 | Assertions.assertEquals(0, listFiles.size()); 99 | } 100 | 101 | @Test 102 | @DisplayName("Should return an empty list if the review doesn't contain file") 103 | public void shouldReturnEmptyListIfReviewIsEmpty() throws IOException, GerritPluginException { 104 | String response = "{" + COMMON_RESPONSE + 105 | " \"currentPatchSet\": {" + 106 | "\"files\": [" + 107 | "]" + 108 | "}" + 109 | "}"; 110 | 111 | when(gerritConnector.listFiles()).thenReturn(response); 112 | 113 | GerritSshFacade gerritSshFacade = new GerritSshFacade(gerritConnector); 114 | // Will call fillListFilesFromGerrit 115 | List listFiles = gerritSshFacade.listFiles(); 116 | Assertions.assertEquals(0, listFiles.size()); 117 | } 118 | 119 | @Test 120 | @DisplayName("Should throw an exception on IOException") 121 | public void shouldThrowAnGerritException() { 122 | Assertions.assertThrows(GerritPluginException.class, () -> { 123 | when(gerritConnector.listFiles()).thenThrow(new IOException("Error during Test")); 124 | 125 | GerritSshFacade gerritRestFacade = new GerritSshFacade(gerritConnector); 126 | // Will call fillListFilesFromGerrit 127 | gerritRestFacade.listFiles(); 128 | }); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/test/java/fr/techad/sonar/gerrit/review/ReviewFileCommentTest.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.gerrit.review; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.junit.jupiter.api.Assertions; 5 | import org.junit.jupiter.api.Test; 6 | import org.sonar.api.batch.rule.Severity; 7 | 8 | public class ReviewFileCommentTest { 9 | 10 | static private final String MESSAGE = "Gerrit Message"; 11 | 12 | @Test 13 | public void testMessage() { 14 | ReviewFileComment reviewFileComment = new ReviewFileComment(); 15 | reviewFileComment.setMessage(MESSAGE); 16 | Assertions.assertEquals(MESSAGE, reviewFileComment.getMessage()); 17 | } 18 | 19 | @Test 20 | public void testNullMessage() { 21 | ReviewFileComment reviewFileComment = new ReviewFileComment(); 22 | reviewFileComment.setMessage(null); 23 | Assertions.assertEquals(StringUtils.EMPTY, reviewFileComment.getMessage()); 24 | } 25 | 26 | @Test 27 | public void testSeverity() { 28 | ReviewFileComment reviewFileComment = new ReviewFileComment(); 29 | reviewFileComment.setMessage(MESSAGE); 30 | reviewFileComment.setSeverity(Severity.BLOCKER.ordinal()); 31 | Assertions.assertEquals(Severity.BLOCKER.ordinal(), reviewFileComment.getSeverity()); 32 | } 33 | 34 | @Test 35 | public void testToString() { 36 | ReviewFileComment reviewFileComment = new ReviewFileComment(); 37 | reviewFileComment.setMessage(MESSAGE); 38 | reviewFileComment.setSeverity(Severity.BLOCKER.ordinal()); 39 | Assertions.assertEquals( 40 | "ReviewFileComment [message:" + MESSAGE + ", severity: " + Severity.BLOCKER.ordinal() + "]", 41 | reviewFileComment.toString()); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/fr/techad/sonar/gerrit/review/ReviewInputTest.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.gerrit.review; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | import static org.fest.assertions.Assertions.assertThat; 10 | import static org.junit.jupiter.api.Assertions.assertEquals; 11 | 12 | public class ReviewInputTest { 13 | private static final String DEFAULT_MESSAGE = "Looks good to me."; 14 | private static final String NEW_MESSAGE = "A new message"; 15 | 16 | private static final String PLUS_ONE_LABEL = "+1 Label"; 17 | private static final String MINUS_ONE_LABEL = "-1 Label"; 18 | private static final String OTHER_LABEL = "other Label"; 19 | 20 | private static final Integer PLUS_ONE = new Integer(1); 21 | private static final Integer MINUS_ONE = new Integer(-1); 22 | private static final Integer OTHER_VALUE = new Integer(42); 23 | 24 | private static final String KEY_COMMENT1 = "Key1"; 25 | private static final String KEY_COMMENT2 = "Key2"; 26 | 27 | @Test 28 | public void shouldHaveAMessage() { 29 | ReviewInput reviewInput = new ReviewInput(); 30 | assertEquals(DEFAULT_MESSAGE, reviewInput.getMessage()); 31 | reviewInput.setMessage(NEW_MESSAGE); 32 | assertEquals(NEW_MESSAGE, reviewInput.getMessage()); 33 | } 34 | 35 | @Test 36 | public void shouldHaveAPlusOneLabel() { 37 | ReviewInput reviewInput = new ReviewInput(); 38 | reviewInput.setLabelToPlusOne(PLUS_ONE_LABEL); 39 | Map labels = reviewInput.getLabels(); 40 | assertEquals(1, labels.size()); 41 | assertEquals(PLUS_ONE, labels.get(PLUS_ONE_LABEL)); 42 | 43 | } 44 | 45 | @Test 46 | public void shouldHaveAMinusOneLabel() { 47 | ReviewInput reviewInput = new ReviewInput(); 48 | reviewInput.setLabelToMinusOne(MINUS_ONE_LABEL); 49 | Map labels = reviewInput.getLabels(); 50 | assertEquals(1, labels.size()); 51 | assertEquals(MINUS_ONE, labels.get(MINUS_ONE_LABEL)); 52 | 53 | } 54 | 55 | @Test 56 | public void shouldHaveAOtherLabel() { 57 | ReviewInput reviewInput = new ReviewInput(); 58 | reviewInput.setValueAndLabel(OTHER_VALUE, OTHER_LABEL); 59 | Map labels = reviewInput.getLabels(); 60 | assertEquals(1, labels.size()); 61 | assertEquals(OTHER_VALUE, labels.get(OTHER_LABEL)); 62 | } 63 | 64 | @Test 65 | public void shouldHaveSeveralLabel() { 66 | ReviewInput reviewInput = new ReviewInput(); 67 | reviewInput.setLabelToPlusOne(PLUS_ONE_LABEL); 68 | reviewInput.setValueAndLabel(OTHER_VALUE, OTHER_LABEL); 69 | reviewInput.setLabelToMinusOne(MINUS_ONE_LABEL); 70 | Map labels = reviewInput.getLabels(); 71 | assertEquals(3, labels.size()); 72 | assertEquals(OTHER_VALUE, labels.get(OTHER_LABEL)); 73 | assertEquals(PLUS_ONE, labels.get(PLUS_ONE_LABEL)); 74 | assertEquals(MINUS_ONE, labels.get(MINUS_ONE_LABEL)); 75 | } 76 | 77 | @Test 78 | public void shouldEmptyTheComments() { 79 | ReviewInput reviewInput = new ReviewInput(); 80 | List list = new ArrayList<>(); 81 | list.add(new ReviewFileComment()); 82 | reviewInput.addComments(KEY_COMMENT1, list); 83 | assertEquals(1, reviewInput.size()); 84 | reviewInput.emptyComments(); 85 | assertEquals(0, reviewInput.size()); 86 | } 87 | 88 | @Test 89 | public void shouldHaveTheComments() { 90 | ReviewInput reviewInput = new ReviewInput(); 91 | List list1 = new ArrayList<>(); 92 | list1.add(new ReviewFileComment()); 93 | list1.add(new ReviewFileComment()); 94 | reviewInput.addComments(KEY_COMMENT1, list1); 95 | List list2 = new ArrayList<>(); 96 | list2.add(new ReviewFileComment()); 97 | reviewInput.addComments(KEY_COMMENT2, list2); 98 | assertEquals(2, reviewInput.size()); 99 | Map> comments = reviewInput.getComments(); 100 | 101 | assertEquals(2, comments.get(KEY_COMMENT1).size()); 102 | assertEquals(1, comments.get(KEY_COMMENT2).size()); 103 | } 104 | 105 | @Test 106 | public void shouldHaveTheUnmodifiedComments() { 107 | ReviewInput reviewInput = new ReviewInput(); 108 | List list1 = new ArrayList<>(); 109 | list1.add(new ReviewFileComment()); 110 | list1.add(new ReviewFileComment()); 111 | reviewInput.addComments(KEY_COMMENT1, list1); 112 | list1.add(new ReviewFileComment()); 113 | assertEquals(1, reviewInput.size()); 114 | Map> comments = reviewInput.getComments(); 115 | 116 | assertEquals(2, comments.get(KEY_COMMENT1).size()); 117 | } 118 | 119 | @Test 120 | public void shouldHaveAToString() { 121 | ReviewInput reviewInput = new ReviewInput(); 122 | reviewInput.setLabelToPlusOne(PLUS_ONE_LABEL); 123 | reviewInput.setMessage(NEW_MESSAGE); 124 | List list1 = new ArrayList<>(); 125 | list1.add(new ReviewFileComment()); 126 | assertEquals("ReviewInput [message=A new message, labels={+1 Label=1}, comments={}]", reviewInput.toString()); 127 | } 128 | 129 | @Test 130 | public void shoulsHaveAEmptyReview() { 131 | ReviewInput reviewInput = new ReviewInput(); 132 | reviewInput.emptyComments(); 133 | assertThat(reviewInput.isEmpty()).isTrue(); 134 | } 135 | 136 | @Test 137 | public void shouldHaveANoEmptyReview() { 138 | ReviewInput reviewInput = new ReviewInput(); 139 | List list = new ArrayList<>(); 140 | list.add(new ReviewFileComment()); 141 | reviewInput.addComments(KEY_COMMENT1, list); 142 | assertThat(reviewInput.isEmpty()).isFalse(); 143 | } 144 | 145 | } 146 | -------------------------------------------------------------------------------- /src/test/java/fr/techad/sonar/gerrit/review/ReviewLineCommentTest.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.gerrit.review; 2 | 3 | import fr.techad.sonar.GerritPluginException; 4 | import fr.techad.sonar.mockito.MockitoExtension; 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.api.extension.ExtendWith; 8 | import org.junit.platform.runner.JUnitPlatform; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.fest.assertions.Assertions.assertThat; 12 | 13 | @ExtendWith(MockitoExtension.class) 14 | @RunWith(JUnitPlatform.class) 15 | public class ReviewLineCommentTest { 16 | static final private String MESSAGE = "Gerrit Message"; 17 | static final private Integer DEFAULT_LINE = new Integer(0); 18 | static final private Integer LINE = 42; 19 | static final private Integer NEGATIVE_LINE = -42; 20 | private ReviewLineComment reviewLineComment; 21 | 22 | @BeforeEach 23 | public void setUp() { 24 | reviewLineComment = new ReviewLineComment(); 25 | } 26 | 27 | @Test 28 | public void shouldHandleLine() throws GerritPluginException { 29 | // given 30 | // when 31 | reviewLineComment.setLine(LINE); 32 | reviewLineComment.setMessage(MESSAGE); 33 | // then 34 | assertThat(reviewLineComment.getLine()).isEqualTo(42); 35 | assertThat(reviewLineComment.toString()) 36 | .isEqualTo("ReviewLineComment [line=" + LINE + ", message=" + MESSAGE + "]"); 37 | } 38 | 39 | @Test 40 | public void shouldHandleNullLine() throws GerritPluginException { 41 | // given 42 | // when 43 | reviewLineComment.setLine(null); 44 | // then 45 | assertThat(reviewLineComment.getLine()).isEqualTo(DEFAULT_LINE); 46 | } 47 | 48 | @Test 49 | public void shouldHandleNegativeLine() throws GerritPluginException { 50 | // given 51 | // when 52 | reviewLineComment.setLine(NEGATIVE_LINE); 53 | // then 54 | assertThat(reviewLineComment.getLine()).isEqualTo(DEFAULT_LINE); 55 | } 56 | 57 | @Test 58 | public void shouldHandleZeroLine() throws GerritPluginException { 59 | // given 60 | // when 61 | reviewLineComment.setLine(DEFAULT_LINE); 62 | // then 63 | assertThat(reviewLineComment.getLine()).isEqualTo(DEFAULT_LINE); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/test/java/fr/techad/sonar/gerrit/utils/ReviewUtilsTest.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.gerrit.utils; 2 | 3 | import fr.techad.sonar.gerrit.review.ReviewFileComment; 4 | import fr.techad.sonar.gerrit.review.ReviewInput; 5 | import fr.techad.sonar.gerrit.review.ReviewLineComment; 6 | import org.junit.jupiter.api.BeforeEach; 7 | import org.junit.jupiter.api.DisplayName; 8 | import org.junit.jupiter.api.Test; 9 | import org.sonar.api.batch.rule.Severity; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | import static org.fest.assertions.Assertions.assertThat; 15 | 16 | public class ReviewUtilsTest { 17 | 18 | private ReviewInput reviewInput; 19 | private ReviewLineComment rlcInfo; 20 | private ReviewLineComment rlcCritical; 21 | private List reviewList; 22 | 23 | @BeforeEach 24 | public void setUp() { 25 | reviewInput = new ReviewInput(); 26 | 27 | reviewInput.setMessage("Not the default message."); 28 | 29 | rlcInfo = new ReviewLineComment(); 30 | rlcInfo.setLine(12); 31 | rlcInfo.setMessage("INFORMATION tldr"); 32 | rlcInfo.setSeverity(Severity.INFO.ordinal()); 33 | 34 | rlcCritical = new ReviewLineComment(); 35 | rlcCritical.setLine(34); 36 | rlcCritical.setMessage("CRITI tldr"); 37 | rlcCritical.setSeverity(Severity.CRITICAL.ordinal()); 38 | 39 | reviewList = new ArrayList(2); 40 | reviewList.add(rlcInfo); 41 | reviewList.add(rlcCritical); 42 | } 43 | 44 | @Test 45 | @DisplayName("Validate Threshold To Value") 46 | public void validateThresholdToValue() { 47 | // given 48 | // when 49 | // then 50 | assertThat(ReviewUtils.thresholdToValue("INFO")).isEqualTo(Severity.INFO.ordinal()); 51 | assertThat(ReviewUtils.thresholdToValue("MINOR")).isEqualTo(Severity.MINOR.ordinal()); 52 | assertThat(ReviewUtils.thresholdToValue("MAJOR")).isEqualTo(Severity.MAJOR.ordinal()); 53 | assertThat(ReviewUtils.thresholdToValue("CRITICAL")).isEqualTo(Severity.CRITICAL.ordinal()); 54 | assertThat(ReviewUtils.thresholdToValue("BLOCKER")).isEqualTo(Severity.BLOCKER.ordinal()); 55 | assertThat(ReviewUtils.thresholdToValue("NOOP")).isEqualTo(ReviewUtils.UNKNOWN_VALUE); 56 | } 57 | 58 | @Test 59 | public void validateValueToThreshold() { 60 | // given 61 | // when 62 | // then 63 | assertThat(ReviewUtils.valueToThreshold(Severity.INFO.ordinal())).isEqualTo("INFO"); 64 | assertThat(ReviewUtils.valueToThreshold(Severity.MINOR.ordinal())).isEqualTo("MINOR"); 65 | assertThat(ReviewUtils.valueToThreshold(Severity.MAJOR.ordinal())).isEqualTo("MAJOR"); 66 | assertThat(ReviewUtils.valueToThreshold(Severity.CRITICAL.ordinal())).isEqualTo("CRITICAL"); 67 | assertThat(ReviewUtils.valueToThreshold(Severity.BLOCKER.ordinal())).isEqualTo("BLOCKER"); 68 | assertThat(ReviewUtils.valueToThreshold(42)).isEqualTo(ReviewUtils.UNKNOWN); 69 | assertThat(ReviewUtils.valueToThreshold(-1)).isEqualTo(ReviewUtils.UNKNOWN); 70 | } 71 | 72 | @Test 73 | public void detectInfoLevel() { 74 | // given 75 | reviewInput.emptyComments(); 76 | reviewList.clear(); 77 | reviewList.add(rlcInfo); 78 | // when 79 | reviewInput.addComments("TLDR", reviewList); 80 | // then 81 | assertThat(reviewInput.maxLevelSeverity()).isEqualTo(ReviewUtils.thresholdToValue("INFO")); 82 | } 83 | 84 | @Test 85 | public void detectCriticalLevel() { 86 | // given 87 | // when 88 | reviewInput.addComments("TLDR", reviewList); 89 | // then 90 | assertThat(reviewInput.maxLevelSeverity()).isEqualTo(ReviewUtils.thresholdToValue("CRITICAL")); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/test/java/fr/techad/sonar/mockito/MockitoExtension.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.mockito; 2 | 3 | import org.junit.jupiter.api.extension.ExtensionContext; 4 | import org.junit.jupiter.api.extension.ParameterContext; 5 | import org.junit.jupiter.api.extension.ParameterResolver; 6 | import org.junit.jupiter.api.extension.TestInstancePostProcessor; 7 | import org.mockito.Mock; 8 | import org.mockito.MockitoAnnotations; 9 | 10 | import java.lang.reflect.Parameter; 11 | 12 | import static org.mockito.Mockito.mock; 13 | 14 | /** 15 | * TECH ADVANTAGE 16 | * All right reserved 17 | * Created by cochon on 21/07/2018. 18 | */ 19 | public class MockitoExtension 20 | implements TestInstancePostProcessor, ParameterResolver { 21 | 22 | @Override 23 | public void postProcessTestInstance(Object testInstance, 24 | ExtensionContext context) { 25 | MockitoAnnotations.initMocks(testInstance); 26 | } 27 | 28 | @Override 29 | public boolean supportsParameter(ParameterContext parameterContext, 30 | ExtensionContext extensionContext) { 31 | return 32 | parameterContext.getParameter().isAnnotationPresent(Mock.class); 33 | } 34 | 35 | @Override 36 | public Object resolveParameter(ParameterContext parameterContext, 37 | ExtensionContext extensionContext) { 38 | return getMock(parameterContext.getParameter(), extensionContext); 39 | } 40 | 41 | private Object getMock( 42 | Parameter parameter, ExtensionContext extensionContext) { 43 | 44 | Class mockType = parameter.getType(); 45 | ExtensionContext.Store mocks = extensionContext.getStore(ExtensionContext.Namespace.create( 46 | MockitoExtension.class, mockType)); 47 | String mockName = getMockName(parameter); 48 | 49 | if (mockName != null) { 50 | return mocks.getOrComputeIfAbsent( 51 | mockName, key -> mock(mockType, mockName)); 52 | } 53 | else { 54 | return mocks.getOrComputeIfAbsent( 55 | mockType.getCanonicalName(), key -> mock(mockType)); 56 | } 57 | } 58 | 59 | private String getMockName(Parameter parameter) { 60 | String explicitMockName = parameter.getAnnotation(Mock.class) 61 | .name().trim(); 62 | if (!explicitMockName.isEmpty()) { 63 | return explicitMockName; 64 | } 65 | else if (parameter.isNamePresent()) { 66 | return parameter.getName(); 67 | } 68 | return null; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/test/java/fr/techad/sonar/utils/MessageUtilsTest.java: -------------------------------------------------------------------------------- 1 | package fr.techad.sonar.utils; 2 | 3 | import fr.techad.sonar.PropertyKey; 4 | import org.junit.jupiter.api.Test; 5 | import org.sonar.api.batch.postjob.issue.PostJobIssue; 6 | import org.sonar.api.batch.rule.Severity; 7 | import org.sonar.api.config.internal.MapSettings; 8 | import org.sonar.api.rule.RuleKey; 9 | 10 | import static org.fest.assertions.Assertions.assertThat; 11 | import static org.mockito.Mockito.mock; 12 | import static org.mockito.Mockito.when; 13 | 14 | public class MessageUtilsTest { 15 | 16 | @Test 17 | public void validateSubstitution() { 18 | // given 19 | MapSettings settings = new MapSettings(); 20 | settings.setProperty(PropertyKey.GERRIT_MESSAGE, "Sonar review at ${sonar.host.url}") 21 | .setProperty("sonar.host.url", "http://sq.example.com/"); 22 | // then 23 | assertThat(MessageUtils.createMessage(settings.getString(PropertyKey.GERRIT_MESSAGE), settings)) 24 | .isEqualTo("Sonar review at http://sq.example.com/"); 25 | } 26 | 27 | @Test 28 | public void validateIssueSubstitution() { 29 | // given 30 | PostJobIssue issue = mock(PostJobIssue.class); 31 | when(issue.isNew()).thenReturn(true); 32 | when(issue.ruleKey()).thenReturn(RuleKey.of("squid", "XX12")); 33 | when(issue.message()).thenReturn("You have a problem there"); 34 | when(issue.severity()).thenReturn(Severity.BLOCKER); 35 | // when 36 | MapSettings settings = new MapSettings(); 37 | settings.setProperty(PropertyKey.GERRIT_ISSUE_COMMENT, 38 | "[${issue.isNew}] New: ${issue.ruleKey} on ${sonar.host.url} Severity: ${issue.severity}, Message: ${issue.message}") 39 | .setProperty("sonar.host.url", "http://sq.example.com/"); 40 | // then 41 | assertThat(MessageUtils.createIssueMessage(settings.getString(PropertyKey.GERRIT_ISSUE_COMMENT), settings, 42 | issue)).isEqualTo( 43 | "[true] New: squid:XX12 on http://sq.example.com/ Severity: BLOCKER, Message: You have a problem there"); 44 | } 45 | 46 | } 47 | --------------------------------------------------------------------------------