├── .editorconfig ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── stepstone │ │ └── sonar │ │ └── plugin │ │ └── coldfusion │ │ ├── ColdFusion.java │ │ ├── ColdFusionPlugin.java │ │ ├── ColdFusionSensor.java │ │ ├── cflint │ │ ├── CFLintAnalysisResultImporter.java │ │ ├── CFLintAnalyzer.java │ │ ├── CFLintConfigExporter.java │ │ ├── CFLintExtractor.java │ │ └── xml │ │ │ ├── CountsAttributes.java │ │ │ ├── IssueAttributes.java │ │ │ ├── LocationAttributes.java │ │ │ └── TagAttribute.java │ │ ├── errors │ │ └── ColdFusionPluginException.java │ │ ├── package-info.java │ │ ├── profile │ │ ├── ColdFusionProfileExporter.java │ │ └── ColdFusionSonarWayProfile.java │ │ └── rules │ │ └── ColdFusionSonarRulesDefinition.java └── resources │ └── com │ └── stepstone │ └── sonar │ └── plugin │ └── coldfusion │ ├── profile.json │ └── rules.xml └── test ├── java └── com │ └── stepstone │ └── sonar │ └── plugin │ └── coldfusion │ ├── ColdfusionPluginTest.java │ ├── ColdfusionSensorTest.java │ └── OSValidator.java └── resources ├── EpisodeClaim.cfc ├── testmetrics1.cfm └── testmetrics2.cfm /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | insert_final_newline = true 6 | indent_style = space 7 | indent_size = 4 8 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven 3 | 4 | name: CI 5 | 6 | on: 7 | push: 8 | branches: [ master, sonar-9, sonar-9.0 ] 9 | pull_request: 10 | types: [opened, synchronize, reopened] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v2 18 | with: 19 | fetch-depth: 0 20 | - name: Set up JDK 11 21 | uses: actions/setup-java@v2 22 | with: 23 | distribution: 'adopt' 24 | java-version: '11' 25 | - name: Cache SonarCloud packages 26 | uses: actions/cache@v1 27 | with: 28 | path: ~/.sonar/cache 29 | key: ${{ runner.os }}-sonar 30 | restore-keys: ${{ runner.os }}-sonar 31 | - name: Cache Maven packages 32 | uses: actions/cache@v1 33 | with: 34 | path: ~/.m2 35 | key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} 36 | restore-keys: ${{ runner.os }}-m2 37 | - name: Build and analyze 38 | env: 39 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 40 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 41 | run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Psonar 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Maven 2 | target/ 3 | *.versionsBackup 4 | 5 | # IntelliJ IDEA 6 | *.iws 7 | *.iml 8 | *.ipr 9 | .idea/ 10 | 11 | # Eclipse 12 | .classpath 13 | .project 14 | .settings 15 | 16 | # ---- Windows 17 | # Windows image file caches 18 | Thumbs.db 19 | # Folder config file 20 | Desktop.ini 21 | 22 | # SonarQube 23 | .sonar/ 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SonarQube ColdFusion Plugin 2 | [![CI](https://github.com/stepstone-tech/sonar-coldfusion/actions/workflows/ci.yml/badge.svg)](https://github.com/stepstone-tech/sonar-coldfusion/actions/workflows/ci.yml) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=stepstone-tech_sonar-coldfusion&metric=alert_status)](https://sonarcloud.io/dashboard?id=stepstone-tech_sonar-coldfusion) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=stepstone-tech_sonar-coldfusion&metric=coverage)](https://sonarcloud.io/dashboard?id=stepstone-tech_sonar-coldfusion) 3 | 4 | A [SonarQube plugin](http://www.sonarqube.org/) for analyzing ColdFusion code, based on the [CFLint library](https://github.com/cflint/CFLint). 5 | 6 | ## Installation 7 | 8 | 1. Download the JAR file from the [releases section](https://github.com/stepstone-tech/sonar-coldfusion/releases) or build it yourself by cloning the code and running `mvn install`. 9 | 1. Copy `sonar-coldfusion-plugin-{version}.jar` to `/extensions/plugins`. 10 | 1. Restart SonarQube. 11 | 12 | ## Compatibility 13 | 14 | SonarQube Version | Plugin Version 15 | ------------------|--------------- 16 | 9.0 - 9.1 | 2.2.0 17 | 7.6 - 8.9 | 2.1.1 18 | 5.6 - 7.5 | 1.5.0 19 | 20 | ## Running 21 | 22 | Follow the instructions for [analyzing code with SonarQube Scanner](http://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner). The ColdFusion plugin will automatically discover and analyze `.cfc` and `.cfm` files. 23 | 24 | ## Parameters tuning 25 | 26 | If you encounter log output indicating, that the Compute Engine of SonarQube has insufficient memory, similar to: 27 | 28 | ``` 29 | 2016.06.22 16:17:43 INFO ce[o.s.s.c.t.CeWorkerCallableImpl] Execute task | project=ApplyNowModule | type=REPORT | id=AVV4eUIgcn4uboqEX1C3 30 | java.lang.OutOfMemoryError: GC overhead limit exceeded 31 | Dumping heap to java_pid8400.hprof ... 32 | Heap dump file created [565019912 bytes in 6.373 secs] 33 | ``` 34 | 35 | you'll need to increase heap memory on the server, in `/conf/sonar.properties`: 36 | 37 | ``` 38 | sonar.ce.javaOpts=-Xmx2g -Xms128m -XX:+HeapDumpOnOutOfMemoryError 39 | ``` 40 | 41 | 2GB might be enough, or perhaps your code base warrants more. 42 | 43 | ## Building 44 | 45 | Run Maven goal 46 | 47 | ```bash 48 | mvn clean package 49 | ``` 50 | 51 | ## Releasing 52 | 53 | Setup Maven settings.xml with 54 | 55 | ```xml 56 | 57 | 58 | github 59 | yourprivatekey 60 | 61 | 62 | ``` 63 | 64 | Run Maven goal 65 | 66 | ```bash 67 | mvn clean package de.jutzig:github-release-plugin:1.3.0:release 68 | ``` 69 | 70 | This will build the plugin jar file, create a release and a tag on github and upload the artifact to 71 | the [repo](https://github.com/stepstone-tech/sonar-coldfusion). 72 | ## Contributors 73 | 74 | Many thanks for the people, who created or improved this project: 75 | 76 | - Tomek Stec 77 | - Michał Paluchowski 78 | - Nicolas Bihan 79 | - Gareth Edwards 80 | 81 | ## License 82 | 83 | Copyright 2016-2019 StepStone GmbH 84 | and contributors 85 | 86 | 87 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 88 | 89 | http://www.apache.org/licenses/LICENSE-2.0 90 | 91 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 92 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.stepstone.sonar.plugin 7 | sonar-coldfusion-plugin 8 | sonar-plugin 9 | 2.2.0 10 | 11 | SonarQube Coldfusion Plugin 12 | Enables scanning of ColdFusion source files 13 | https://github.com/stepstone-tech/sonar-coldfusion 14 | 15 | 16 | StepStone GmbH 17 | http://www.stepstone.com/ 18 | 19 | 20 | 21 | The Apache Software License, Version 2.0 22 | http://www.apache.org/licenses/LICENSE-2.0.txt 23 | repo 24 | 25 | 26 | 27 | 28 | git@github.com:stepstone-tech/sonar-coldfusion.git 29 | git@github.com:stepstone-tech/sonar-coldfusion.git 30 | https://github.com/stepstone-tech/sonar-coldfusion 31 | 32 | 33 | 34 | GitHub 35 | https://github.com/stepstone-tech/sonar-coldfusion/issues 36 | 37 | 38 | 39 | UTF-8 40 | 11 41 | 11 42 | 9.0.0.45539 43 | 1.5.0 44 | 1.16.0.719 45 | 46 | 47 | 48 | 49 | junit 50 | junit 51 | 4.13.2 52 | test 53 | 54 | 55 | org.mockito 56 | mockito-all 57 | 1.10.19 58 | test 59 | 60 | 61 | 62 | org.assertj 63 | assertj-core 64 | 3.21.0 65 | test 66 | 67 | 68 | 69 | org.sonarsource.sslr-squid-bridge 70 | sslr-squid-bridge 71 | 2.7.1.392 72 | 73 | 74 | sonar-plugin-api 75 | org.sonarsource.sonarqube 76 | 77 | 78 | 79 | 80 | 81 | org.sonarsource.analyzer-commons 82 | sonar-analyzer-commons 83 | ${sonar-analyzer-commons.version} 84 | 85 | 86 | 87 | 88 | org.sonarsource.sonarqube 89 | sonar-plugin-api 90 | ${sonar.version} 91 | provided 92 | 93 | 94 | 95 | org.sonarsource.sonarqube 96 | sonar-plugin-api-impl 97 | ${sonar.version} 98 | test 99 | 100 | 101 | 102 | 103 | 104 | 105 | org.sonarsource.sonar-packaging-maven-plugin 106 | sonar-packaging-maven-plugin 107 | 1.20.0.405 108 | true 109 | 110 | com.stepstone.sonar.plugin.coldfusion.ColdFusionPlugin 111 | ColdFusion 112 | CFLint ${cflint.version} Plugin for Sonarqube 113 | https://github.com/stepstone-tech/sonar-coldfusion 114 | 115 | 116 | 117 | org.apache.maven.plugins 118 | maven-dependency-plugin 119 | 2.10 120 | 121 | 122 | include-cflint 123 | generate-resources 124 | 125 | copy 126 | 127 | 128 | 129 | 130 | com.github.cflint 131 | CFLint 132 | ${cflint.version} 133 | all 134 | cflint.jar 135 | 136 | 137 | ${project.build.outputDirectory}/META-INF/runner 138 | 139 | 140 | 141 | 142 | 143 | de.jutzig 144 | github-release-plugin 145 | 1.4.0 146 | 147 | Sonarqube Coldfusion Plugin release 148 | ${project.version} 149 | ${project.version} 150 | 151 | 152 | ${project.build.directory} 153 | 154 | ${project.artifactId}*.jar 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | sonar 165 | 166 | stepstone-tech_sonar-coldfusion 167 | stepstone-tech 168 | https://sonarcloud.io 169 | 170 | 171 | 172 | 173 | 174 | org.sonarsource.scanner.maven 175 | sonar-maven-plugin 176 | 3.9.0.2155 177 | 178 | 179 | org.jacoco 180 | jacoco-maven-plugin 181 | 0.8.7 182 | 183 | 184 | 185 | 186 | 187 | org.jacoco 188 | jacoco-maven-plugin 189 | 190 | 191 | 192 | prepare-agent 193 | 194 | 195 | 196 | report 197 | 198 | report 199 | 200 | 201 | 202 | META-INF/runner/cflint.jar 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | -------------------------------------------------------------------------------- /src/main/java/com/stepstone/sonar/plugin/coldfusion/ColdFusion.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 StepStone GmbH 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.stepstone.sonar.plugin.coldfusion; 18 | 19 | import org.sonar.api.config.Configuration; 20 | import org.sonar.api.resources.AbstractLanguage; 21 | 22 | public class ColdFusion extends AbstractLanguage { 23 | 24 | private final Configuration configuration; 25 | 26 | public ColdFusion(Configuration configuration) { 27 | super(ColdFusionPlugin.LANGUAGE_KEY, ColdFusionPlugin.LANGUAGE_NAME); 28 | this.configuration = configuration; 29 | } 30 | 31 | @Override 32 | public String[] getFileSuffixes() { 33 | return configuration.getStringArray(ColdFusionPlugin.FILE_SUFFIXES_KEY); 34 | } 35 | 36 | @Override 37 | public boolean equals(Object o) { 38 | if (this == o) { 39 | return true; 40 | } 41 | if (o == null || getClass() != o.getClass()) { 42 | return false; 43 | } 44 | if (!super.equals(o)) { 45 | return false; 46 | } 47 | 48 | ColdFusion that = (ColdFusion) o; 49 | 50 | return !(configuration != null ? !configuration.equals(that.configuration) : that.configuration != null); 51 | 52 | } 53 | 54 | @Override 55 | public int hashCode() { 56 | int result = super.hashCode(); 57 | result = 31 * result + (configuration != null ? configuration.hashCode() : 0); 58 | return result; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/stepstone/sonar/plugin/coldfusion/ColdFusionPlugin.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 StepStone GmbH 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.stepstone.sonar.plugin.coldfusion; 18 | 19 | import com.stepstone.sonar.plugin.coldfusion.profile.ColdFusionProfileExporter; 20 | import com.stepstone.sonar.plugin.coldfusion.profile.ColdFusionSonarWayProfile; 21 | import com.stepstone.sonar.plugin.coldfusion.rules.ColdFusionSonarRulesDefinition; 22 | 23 | import org.sonar.api.Plugin; 24 | import org.sonar.api.Properties; 25 | import org.sonar.api.Property; 26 | 27 | @Properties({ 28 | @Property( 29 | key = ColdFusionPlugin.FILE_SUFFIXES_KEY, 30 | defaultValue = ColdFusionPlugin.FILE_SUFFIXES_DEFVALUE, 31 | name = "File suffixes", 32 | description = "Comma-separated list of suffixes of files to analyze.", 33 | project = true, 34 | multiValues = true, 35 | global = true 36 | ), 37 | @Property( 38 | key = ColdFusionPlugin.CFLINT_JAVA, 39 | defaultValue = "java", 40 | name = "Java executable", 41 | description = "", 42 | project = true, 43 | global = true 44 | ), 45 | @Property( 46 | key = ColdFusionPlugin.CFLINT_JAVA_OPTS, 47 | defaultValue = "", 48 | name = "Java executable options", 49 | description = "Additional parameters passed to java process. E.g. -Xmx1g", 50 | project = true, 51 | global = true 52 | ), 53 | }) 54 | public class ColdFusionPlugin implements Plugin { 55 | 56 | public static final String LANGUAGE_KEY = "cf"; 57 | public static final String LANGUAGE_NAME = "ColdFusion"; 58 | 59 | public static final String FILE_SUFFIXES_KEY = "sonar.cf.file.suffixes"; 60 | public static final String FILE_SUFFIXES_DEFVALUE = ".cfc,.cfm"; 61 | 62 | public static final String REPOSITORY_KEY = "coldfusionsquid"; 63 | public static final String REPOSITORY_NAME = "SonarQube"; 64 | 65 | public static final String CFLINT_JAVA = "sonar.cf.cflint.java"; 66 | public static final String CFLINT_JAVA_OPTS = "sonar.cf.cflint.java.opts"; 67 | 68 | @Override 69 | public void define(Context context) { 70 | context.addExtensions( 71 | ColdFusion.class, 72 | ColdFusionSensor.class, 73 | ColdFusionSonarRulesDefinition.class, 74 | ColdFusionSonarWayProfile.class, 75 | ColdFusionProfileExporter.class 76 | ); 77 | 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/stepstone/sonar/plugin/coldfusion/ColdFusionSensor.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 StepStone GmbH 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.stepstone.sonar.plugin.coldfusion; 18 | 19 | import com.google.common.base.Preconditions; 20 | import com.stepstone.sonar.plugin.coldfusion.cflint.CFLintAnalyzer; 21 | import com.stepstone.sonar.plugin.coldfusion.cflint.CFLintAnalysisResultImporter; 22 | import com.stepstone.sonar.plugin.coldfusion.cflint.CFLintConfigExporter; 23 | import org.sonar.api.batch.fs.FileSystem; 24 | import org.sonar.api.batch.fs.InputFile; 25 | import org.sonar.api.batch.sensor.Sensor; 26 | import org.sonar.api.batch.sensor.SensorContext; 27 | import org.sonar.api.batch.sensor.SensorDescriptor; 28 | import org.sonar.api.measures.CoreMetrics; 29 | import org.sonar.api.batch.rule.ActiveRules; 30 | import org.sonar.api.utils.log.Logger; 31 | import org.sonar.api.utils.log.Loggers; 32 | 33 | import javax.xml.stream.XMLStreamException; 34 | import java.io.BufferedReader; 35 | import java.io.File; 36 | import java.io.IOException; 37 | import java.io.InputStreamReader; 38 | import java.nio.file.Files; 39 | import java.util.ArrayList; 40 | import java.util.Collection; 41 | import java.util.List; 42 | import java.util.concurrent.Callable; 43 | import java.util.concurrent.ExecutorService; 44 | import java.util.concurrent.Executors; 45 | import java.util.concurrent.TimeUnit; 46 | import java.util.regex.Matcher; 47 | import java.util.regex.Pattern; 48 | import java.util.stream.Collectors; 49 | 50 | public class ColdFusionSensor implements Sensor { 51 | 52 | private final FileSystem fs; 53 | private final ActiveRules ruleProfile; 54 | private final Logger LOGGER = Loggers.get(ColdFusionSensor.class); 55 | 56 | public ColdFusionSensor(FileSystem fs, ActiveRules ruleProfile) { 57 | Preconditions.checkNotNull(fs); 58 | Preconditions.checkNotNull(ruleProfile); 59 | 60 | this.fs = fs; 61 | this.ruleProfile = ruleProfile; 62 | } 63 | 64 | 65 | @Override 66 | public void describe(SensorDescriptor descriptor) { 67 | descriptor.onlyOnLanguage(ColdFusionPlugin.LANGUAGE_KEY); 68 | descriptor.createIssuesForRuleRepository(ColdFusionPlugin.REPOSITORY_KEY); 69 | } 70 | 71 | @Override 72 | public void execute(SensorContext context) { 73 | try { 74 | analyze(context); 75 | importResults(context); 76 | measureProcessor(context); 77 | } catch (IOException | XMLStreamException e) { 78 | LOGGER.error("",e); 79 | } 80 | } 81 | 82 | private void analyze(SensorContext context) throws IOException, XMLStreamException { 83 | File configFile = generateCflintConfig(); 84 | try { 85 | new CFLintAnalyzer(context).analyze(configFile); 86 | } finally { 87 | //when analysis is done we delete the created file 88 | deleteFile(configFile); 89 | } 90 | } 91 | 92 | private File generateCflintConfig() throws IOException, XMLStreamException { 93 | final File configFile = new File(fs.workDir(), "cflint-config.xml"); 94 | Collection ruleKeys = ruleProfile.findByRepository(ColdFusionPlugin.REPOSITORY_KEY) 95 | .stream().map(rule -> rule.ruleKey().toString()).collect(Collectors.toList()); 96 | new CFLintConfigExporter(ruleKeys).save(configFile); 97 | return configFile; 98 | } 99 | 100 | private void deleteFile(File configFile) throws IOException { 101 | if(configFile!= null){ 102 | Files.deleteIfExists(configFile.toPath()); 103 | } 104 | } 105 | 106 | private void importResults(SensorContext sensorContext) throws IOException { 107 | try { 108 | new CFLintAnalysisResultImporter(fs, sensorContext).parse(new File(fs.workDir(), "cflint-result.xml")); 109 | } catch (XMLStreamException e) { 110 | LOGGER.error(",e"); 111 | } finally { 112 | deleteFile(new File(fs.workDir(), "cflint-result.xml")); 113 | } 114 | } 115 | 116 | private void measureProcessor(SensorContext context) { 117 | LOGGER.info("Starting measure processor"); 118 | 119 | ExecutorService executorService = Executors.newSingleThreadExecutor(); 120 | List> callableTasks = new ArrayList<>(); 121 | 122 | for (InputFile inputFile : fs.inputFiles(fs.predicates().hasLanguage(ColdFusionPlugin.LANGUAGE_KEY))) { 123 | Callable callableTask = () -> { 124 | try { 125 | metricsCounter(inputFile, context); 126 | return 1; 127 | } catch (IOException e) { 128 | return 0; 129 | } 130 | }; 131 | callableTasks.add(callableTask); 132 | } 133 | 134 | try { 135 | executorService.invokeAll(callableTasks); 136 | executorService.shutdown(); 137 | executorService.awaitTermination(2, TimeUnit.MINUTES); 138 | } catch (InterruptedException e) { 139 | LOGGER.error("",e); 140 | } 141 | 142 | LOGGER.info("Measure processor done"); 143 | } 144 | 145 | //Very basic and naive line of code counter for Coldfusion 146 | //Might count a line of code as comment 147 | private void metricsCounter(InputFile inputFile, SensorContext context) throws IOException { 148 | String currentLine; 149 | int commentLines = 0; 150 | int blankLines = 0; 151 | int lines = 0; 152 | int complexity = 1; 153 | 154 | 155 | try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputFile.inputStream()))) { 156 | if (inputFile.inputStream() != null) { 157 | while ((currentLine = reader.readLine()) != null) { 158 | lines++; 159 | 160 | if (currentLine.contains("")) { 163 | continue; 164 | } 165 | commentLines++; 166 | lines++; 167 | while (!(reader.readLine()).contains("-->")) { 168 | lines++; 169 | commentLines++; 170 | } 171 | } else if (currentLine.trim().isEmpty()) { 172 | blankLines++; 173 | continue; 174 | } 175 | 176 | complexity = getLineComplexity(currentLine, complexity); 177 | } 178 | } 179 | } 180 | int linesOfCode = lines-blankLines-commentLines; 181 | // every 100 lines of code add 1 to the content's complexity 182 | complexity = complexity + (linesOfCode / 100); 183 | 184 | context.newMeasure().forMetric(CoreMetrics.COMMENT_LINES).on(inputFile).withValue(commentLines).save(); 185 | context.newMeasure().forMetric(CoreMetrics.NCLOC).on(inputFile).withValue(linesOfCode).save(); 186 | context.newMeasure().forMetric(CoreMetrics.LINES).on(inputFile).withValue(lines).save(); 187 | context.newMeasure().forMetric(CoreMetrics.COMPLEXITY).on(inputFile).withValue(complexity).save(); 188 | } 189 | 190 | private int getLineComplexity(String currentLine, int complexity) { 191 | int mcCabeComplexity =0; 192 | int lineByLineComplexity = 0; 193 | int lineByLineComplexityIncrement = 4; 194 | int thisLineComplexityAdd = 0; 195 | int thisLineComplexitySubtract = 0; 196 | 197 | // SCORE INCREMENTS 198 | mcCabeComplexity += countRegexOccurrences(currentLine, "(inputFile.lines()){ 121 | logger 122 | .error("Problem creating issue for file {}, issue is line {} but file has {} lines", inputFile, locationAttributes.getLine().get(), inputFile.lines()); 123 | return; 124 | } 125 | 126 | logger.debug("create New Issue {} for file {}", issueAttributes, inputFile.filename()); 127 | final NewIssue issue = sensorContext.newIssue(); 128 | 129 | final NewIssueLocation issueLocation = issue.newLocation(); 130 | issueLocation.on(inputFile); 131 | issueLocation.at(inputFile.selectLine(locationAttributes.getLine().get())); 132 | issueLocation.message(locationAttributes.getMessage().get()); 133 | 134 | issue.forRule(RuleKey.of(ColdFusionPlugin.REPOSITORY_KEY, issueAttributes.getId().get())); 135 | issue.at(issueLocation); 136 | issue.save(); 137 | } 138 | 139 | private void closeXmlStream() throws XMLStreamException { 140 | if (stream != null) { 141 | try { 142 | stream.close(); 143 | } catch (Exception e) { 144 | throw e; 145 | } 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/main/java/com/stepstone/sonar/plugin/coldfusion/cflint/CFLintAnalyzer.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 StepStone GmbH 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.stepstone.sonar.plugin.coldfusion.cflint; 18 | 19 | import com.stepstone.sonar.plugin.coldfusion.ColdFusionPlugin; 20 | 21 | import com.google.common.base.Preconditions; 22 | import com.google.common.base.Strings; 23 | 24 | import org.sonar.api.batch.fs.FileSystem; 25 | import org.sonar.api.batch.sensor.SensorContext; 26 | import org.sonar.api.config.Configuration; 27 | import org.sonar.api.utils.command.Command; 28 | import org.sonar.api.utils.command.CommandExecutor; 29 | import org.sonar.api.utils.command.StreamConsumer; 30 | import org.sonar.api.utils.log.Logger; 31 | import org.sonar.api.utils.log.Loggers; 32 | 33 | import java.io.File; 34 | import java.io.IOException; 35 | import javax.xml.stream.XMLStreamException; 36 | 37 | public class CFLintAnalyzer { 38 | 39 | private final Logger logger = Loggers.get(CFLintAnalyzer.class); 40 | private final Configuration settings; 41 | private final FileSystem fs; 42 | 43 | public CFLintAnalyzer(SensorContext sensorContext) { 44 | Preconditions.checkNotNull(sensorContext); 45 | 46 | this.settings = sensorContext.config(); 47 | this.fs = sensorContext.fileSystem(); 48 | } 49 | 50 | public void analyze(File configFile) throws IOException, XMLStreamException { 51 | File executableJar = null; 52 | try { 53 | Command command = Command.create(settings.get(ColdFusionPlugin.CFLINT_JAVA).orElseThrow( 54 | IllegalStateException::new 55 | )); 56 | addCflintJavaOpts(command); 57 | executableJar = extractCflintJar(); 58 | command.addArgument("-jar") 59 | .addArgument(executableJar.getPath()) 60 | .addArgument("-xml") 61 | .addArgument("-folder") 62 | .addArgument(settings.get("sonar.projectBaseDir").orElseThrow( 63 | IllegalStateException::new 64 | )) 65 | .addArgument("-xmlfile") 66 | .addArgument(fs.workDir() + File.separator + "cflint-result.xml") 67 | .addArgument("-configfile") 68 | .addArgument(configFile.getPath()); 69 | 70 | CommandExecutor executor = CommandExecutor.create(); 71 | int exitCode = executor.execute(command, new LogInfoStreamConsumer(), new LogErrorStreamConsumer(), Integer.MAX_VALUE); 72 | 73 | if (exitCode != 0) { 74 | throw new IllegalStateException("The CFLint analyzer failed with exit code: " + exitCode); 75 | } 76 | } finally { 77 | //cleanup 78 | if(executableJar!= null && executableJar.exists()) { 79 | executableJar.deleteOnExit(); 80 | } 81 | } 82 | 83 | } 84 | 85 | protected File extractCflintJar() throws IOException { 86 | return new CFLintExtractor(fs.workDir()).extract(); 87 | } 88 | 89 | protected void addCflintJavaOpts(Command command) { 90 | final String cflintJavaOpts = settings.get(ColdFusionPlugin.CFLINT_JAVA_OPTS).orElse(""); 91 | if (!Strings.isNullOrEmpty(cflintJavaOpts)) { 92 | final String[] arguments = cflintJavaOpts.split(" "); 93 | for (String argument : arguments) { 94 | command.addArgument(argument); 95 | } 96 | } 97 | } 98 | 99 | private class LogInfoStreamConsumer implements StreamConsumer { 100 | 101 | @Override 102 | public void consumeLine(String line) { 103 | logger.info("Consuming line {}", line); 104 | } 105 | 106 | } 107 | 108 | private class LogErrorStreamConsumer implements StreamConsumer { 109 | 110 | @Override 111 | public void consumeLine(String line) { 112 | logger.error("Error consuming line {}", line); 113 | } 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /src/main/java/com/stepstone/sonar/plugin/coldfusion/cflint/CFLintConfigExporter.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 StepStone GmbH 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.stepstone.sonar.plugin.coldfusion.cflint; 18 | 19 | import javax.xml.stream.XMLOutputFactory; 20 | import javax.xml.stream.XMLStreamException; 21 | import javax.xml.stream.XMLStreamWriter; 22 | import java.io.File; 23 | import java.io.FileWriter; 24 | import java.io.IOException; 25 | import java.io.Writer; 26 | import java.util.Collection; 27 | 28 | public class CFLintConfigExporter { 29 | 30 | private final Collection ruleKeys; 31 | public CFLintConfigExporter(Collection ruleKeys) { 32 | this.ruleKeys = ruleKeys; 33 | } 34 | 35 | public void save(File configFile) throws IOException, XMLStreamException { 36 | try (FileWriter writer = new FileWriter(configFile)) { 37 | save(writer); 38 | } 39 | } 40 | 41 | public void save(Writer writer) throws IOException, XMLStreamException { 42 | final XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance(); 43 | XMLStreamWriter xtw=null; 44 | try { 45 | xtw = xmlOutputFactory.createXMLStreamWriter(writer); 46 | 47 | xtw.writeStartDocument(); 48 | xtw.writeStartElement("config"); 49 | 50 | for (String ruleKey: ruleKeys) { 51 | xtw.writeStartElement("includes"); 52 | xtw.writeAttribute("code", ruleKey); 53 | xtw.writeEndElement(); 54 | } 55 | 56 | xtw.writeEndElement(); 57 | xtw.writeEndDocument(); 58 | } finally { 59 | if(xtw!=null) { 60 | xtw.close(); 61 | } 62 | } 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/stepstone/sonar/plugin/coldfusion/cflint/CFLintExtractor.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 StepStone GmbH 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.stepstone.sonar.plugin.coldfusion.cflint; 18 | 19 | import static com.google.common.base.Preconditions.checkNotNull; 20 | 21 | import org.sonar.api.batch.InstantiationStrategy; 22 | 23 | import java.io.File; 24 | import java.io.IOException; 25 | import java.io.InputStream; 26 | import java.nio.file.Files; 27 | import java.nio.file.StandardCopyOption; 28 | 29 | @InstantiationStrategy(InstantiationStrategy.PER_BATCH) 30 | public class CFLintExtractor { 31 | 32 | private static final String CFLINT_RESOURCE = "/META-INF/runner/cflint.jar"; 33 | private static final String CFLINT = "runner/cflint.jar"; 34 | 35 | private final File workDir; 36 | 37 | public CFLintExtractor(File workDir) { 38 | checkNotNull(workDir); 39 | 40 | this.workDir = workDir; 41 | } 42 | 43 | public File extract() throws IOException { 44 | File cflintJar = getFile(); 45 | 46 | try (InputStream input = getClass().getResourceAsStream(CFLINT_RESOURCE)) { 47 | Files.copy(input, cflintJar.toPath(), StandardCopyOption.REPLACE_EXISTING); 48 | } 49 | 50 | return cflintJar; 51 | } 52 | 53 | private File getFile() throws IOException { 54 | final File cflintJar = new File(workDir, CFLINT); 55 | 56 | mkdirs(cflintJar.getParentFile()); 57 | 58 | return cflintJar; 59 | } 60 | 61 | private void mkdirs(File directory) throws IOException { 62 | if (!directory.exists()) { 63 | final boolean mkdirs = directory.mkdirs(); 64 | 65 | if (!mkdirs) { 66 | throw new IOException("Cannot create directory: " + directory); 67 | } 68 | } 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/stepstone/sonar/plugin/coldfusion/cflint/xml/CountsAttributes.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 StepStone GmbH 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.stepstone.sonar.plugin.coldfusion.cflint.xml; 18 | 19 | import javax.xml.stream.XMLStreamReader; 20 | 21 | public class CountsAttributes extends TagAttribute { 22 | 23 | private Integer totallines; 24 | private Integer totalfiles; 25 | 26 | public CountsAttributes(XMLStreamReader stream) { 27 | this.totallines = getAttributeInteger("totallines", stream); 28 | this.totalfiles = getAttributeInteger("totalfiles", stream); 29 | } 30 | 31 | public Integer getTotalLines() { 32 | return totallines; 33 | } 34 | 35 | public Integer getTotalFiles() { 36 | return totalfiles; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/stepstone/sonar/plugin/coldfusion/cflint/xml/IssueAttributes.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 StepStone GmbH 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.stepstone.sonar.plugin.coldfusion.cflint.xml; 18 | 19 | 20 | import java.util.Optional; 21 | import javax.xml.stream.XMLStreamReader; 22 | 23 | public class IssueAttributes extends TagAttribute { 24 | 25 | private Optional id; 26 | 27 | public IssueAttributes(XMLStreamReader stream) { 28 | this.id = getAttributeValue("id", stream); 29 | } 30 | 31 | public Optional getId() { 32 | return id; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/stepstone/sonar/plugin/coldfusion/cflint/xml/LocationAttributes.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 StepStone GmbH 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.stepstone.sonar.plugin.coldfusion.cflint.xml; 18 | 19 | 20 | import java.util.Optional; 21 | import javax.xml.stream.XMLStreamReader; 22 | 23 | public class LocationAttributes extends TagAttribute { 24 | 25 | private final String file; 26 | private final Optional line; 27 | private final Optional message; 28 | 29 | public LocationAttributes(XMLStreamReader stream) { 30 | file = getAttributeValue("file", stream).get(); 31 | message = getAttributeValue("message", stream); 32 | 33 | Optional currentLine = getAttributeValue("line", stream); 34 | 35 | this.line = currentLine.map(Integer::parseInt); 36 | } 37 | 38 | public String getFile() { 39 | return file; 40 | } 41 | 42 | public Optional getLine() { 43 | return line; 44 | } 45 | 46 | public Optional getMessage() { 47 | return message; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/stepstone/sonar/plugin/coldfusion/cflint/xml/TagAttribute.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 StepStone GmbH 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.stepstone.sonar.plugin.coldfusion.cflint.xml; 18 | 19 | 20 | import org.apache.commons.lang.StringUtils; 21 | 22 | import java.util.Optional; 23 | import javax.xml.stream.XMLStreamReader; 24 | 25 | class TagAttribute { 26 | 27 | protected Optional getAttributeValue(String name, XMLStreamReader stream) { 28 | 29 | for (int i = 0; i < stream.getAttributeCount(); i++) { 30 | 31 | if (name.equalsIgnoreCase(stream.getAttributeLocalName(i))) { 32 | return Optional.of(StringUtils.trimToEmpty(stream.getAttributeValue(i))); 33 | } 34 | } 35 | 36 | return Optional.empty(); 37 | } 38 | 39 | 40 | protected Integer getAttributeInteger(String name, XMLStreamReader stream) { 41 | 42 | for (int i = 0; i < stream.getAttributeCount(); i++) { 43 | 44 | if (name.equalsIgnoreCase(stream.getAttributeLocalName(i))) { 45 | return Integer.valueOf(stream.getAttributeValue(i)); 46 | } 47 | } 48 | 49 | return 0; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/stepstone/sonar/plugin/coldfusion/errors/ColdFusionPluginException.java: -------------------------------------------------------------------------------- 1 | package com.stepstone.sonar.plugin.coldfusion.errors; 2 | 3 | public class ColdFusionPluginException extends RuntimeException { 4 | 5 | public ColdFusionPluginException(String message, Throwable cause) { 6 | super(message, cause); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/stepstone/sonar/plugin/coldfusion/package-info.java: -------------------------------------------------------------------------------- 1 | @ParametersAreNonnullByDefault package com.stepstone.sonar.plugin.coldfusion; 2 | 3 | import javax.annotation.ParametersAreNonnullByDefault; 4 | 5 | -------------------------------------------------------------------------------- /src/main/java/com/stepstone/sonar/plugin/coldfusion/profile/ColdFusionProfileExporter.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 StepStone GmbH 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.stepstone.sonar.plugin.coldfusion.profile; 18 | 19 | import com.google.common.base.Throwables; 20 | import com.stepstone.sonar.plugin.coldfusion.ColdFusionPlugin; 21 | import com.stepstone.sonar.plugin.coldfusion.cflint.CFLintConfigExporter; 22 | import org.sonar.api.profiles.ProfileExporter; 23 | import org.sonar.api.profiles.RulesProfile; 24 | 25 | import javax.xml.stream.XMLStreamException; 26 | import java.io.IOException; 27 | import java.io.Writer; 28 | import java.util.Collection; 29 | import java.util.stream.Collectors; 30 | 31 | public class ColdFusionProfileExporter extends ProfileExporter { 32 | 33 | public ColdFusionProfileExporter() { 34 | super("coldfusion-cflint", "CFLint Rule Set"); 35 | setSupportedLanguages(ColdFusionPlugin.LANGUAGE_KEY); 36 | } 37 | 38 | @Override 39 | public void exportProfile(RulesProfile ruleProfile, Writer writer) { 40 | try { 41 | Collection ruleKeys = ruleProfile.getActiveRulesByRepository(ColdFusionPlugin.REPOSITORY_KEY) 42 | .stream().map(rule -> rule.getRule().ruleKey().rule()) 43 | .collect(Collectors.toList()); 44 | new CFLintConfigExporter(ruleKeys).save(writer); 45 | } catch (IOException | XMLStreamException e) { 46 | Throwables.propagate(e); 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/stepstone/sonar/plugin/coldfusion/profile/ColdFusionSonarWayProfile.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 StepStone GmbH 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.stepstone.sonar.plugin.coldfusion.profile; 18 | 19 | import com.stepstone.sonar.plugin.coldfusion.ColdFusionPlugin; 20 | import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition; 21 | import org.sonarsource.analyzer.commons.BuiltInQualityProfileJsonLoader; 22 | 23 | public class ColdFusionSonarWayProfile implements BuiltInQualityProfilesDefinition { 24 | 25 | private static final String PROFILE_NAME = "Sonar way"; 26 | private static final String DEFAULT_PROFILE_PATH = "com/stepstone/sonar/plugin/coldfusion/profile.json"; 27 | 28 | @Override 29 | public void define(Context context) { 30 | NewBuiltInQualityProfile profile = context.createBuiltInQualityProfile(PROFILE_NAME, ColdFusionPlugin.LANGUAGE_KEY); 31 | BuiltInQualityProfileJsonLoader.load(profile, ColdFusionPlugin.REPOSITORY_KEY, DEFAULT_PROFILE_PATH); 32 | profile.done(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/stepstone/sonar/plugin/coldfusion/rules/ColdFusionSonarRulesDefinition.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016 StepStone GmbH 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.stepstone.sonar.plugin.coldfusion.rules; 18 | 19 | import static java.nio.charset.StandardCharsets.UTF_8; 20 | 21 | import com.stepstone.sonar.plugin.coldfusion.ColdFusionPlugin; 22 | 23 | import org.sonar.api.batch.ScannerSide; 24 | import org.sonar.api.server.rule.RulesDefinition; 25 | import org.sonar.api.server.rule.RulesDefinitionXmlLoader; 26 | 27 | import java.io.InputStreamReader; 28 | 29 | @ScannerSide 30 | public class ColdFusionSonarRulesDefinition implements RulesDefinition { 31 | 32 | private static final String DEFAULT_RULES_FILE = "/com/stepstone/sonar/plugin/coldfusion/rules.xml"; 33 | 34 | private final RulesDefinitionXmlLoader rulesLoader; 35 | 36 | public ColdFusionSonarRulesDefinition(RulesDefinitionXmlLoader rulesLoader) { 37 | this.rulesLoader = rulesLoader; 38 | } 39 | 40 | @Override 41 | public void define(Context context) { 42 | NewRepository repository = context 43 | .createRepository(ColdFusionPlugin.REPOSITORY_KEY, ColdFusionPlugin.LANGUAGE_KEY) 44 | .setName(ColdFusionPlugin.REPOSITORY_NAME); 45 | 46 | rulesLoader.load(repository, new InputStreamReader(getClass().getResourceAsStream(DEFAULT_RULES_FILE), UTF_8)); 47 | 48 | repository.done(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/resources/com/stepstone/sonar/plugin/coldfusion/profile.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Sonar way", 3 | "ruleKeys": [ 4 | "ARG_DEFAULT_MISSING", 5 | "ARG_VAR_CONFLICT", 6 | "ARG_VAR_MIXED", 7 | "NO_DEFAULT_INSIDE_SWITCH", 8 | "GLOBAL_VAR", 9 | "NESTED_CFOUTPUT", 10 | "OUTPUT_ATTR", 11 | "QUERYPARAM_REQ", 12 | "CFQUERYPARAM_REQ", 13 | "QUERYNEW_DATATYPE", 14 | "MISSING_VAR", 15 | "AVOID_USING_CFDUMP_TAG", 16 | "AVOID_USING_CFEXECUTE_TAG", 17 | "AVOID_USING_ISDATE", 18 | "AVOID_USING_CFABORT_TAG", 19 | "AVOID_USING_ABORT", 20 | "AVOID_USING_CFINSERT_TAG", 21 | "AVOID_USING_CFMODULE_TAG", 22 | "AVOID_USING_CFUPDATE_TAG", 23 | "AVOID_USING_CFINCLUDE_TAG", 24 | "COMPONENT_HINT_MISSING", 25 | "FUNCTION_HINT_MISSING", 26 | "ARG_HINT_MISSING", 27 | "ARG_HINT_MISSING_SCRIPT", 28 | "ARG_TYPE_MISSING", 29 | "ARG_TYPE_ANY", 30 | "EXCESSIVE_FUNCTION_LENGTH", 31 | "EXCESSIVE_COMPONENT_LENGTH", 32 | "FUNCTION_TYPE_MISSING", 33 | "FUNCTION_TYPE_ANY", 34 | "EXCESSIVE_ARGUMENTS", 35 | "EXCESSIVE_FUNCTIONS", 36 | "FUNCTION_TOO_COMPLEX", 37 | "AVOID_USING_WRITEDUMP", 38 | "AVOID_USING_STRUCTNEW", 39 | "AVOID_USING_ISDEBUGMODE", 40 | "AVOID_USING_ARRAYNEW", 41 | "COMPLEX_BOOLEAN_CHECK", 42 | "EXPLICIT_BOOLEAN_CHECK", 43 | "VAR_INVALID_NAME", 44 | "VAR_ALLCAPS_NAME", 45 | "SCOPE_ALLCAPS_NAME", 46 | "VAR_TOO_SHORT", 47 | "VAR_TOO_LONG", 48 | "VAR_TOO_WORDY", 49 | "VAR_IS_TEMPORARY", 50 | "VAR_HAS_PREFIX_OR_POSTFIX", 51 | "ARGUMENT_MISSING_NAME", 52 | "ARGUMENT_INVALID_NAME", 53 | "ARGUMENT_ALLCAPS_NAME", 54 | "ARGUMENT_TOO_SHORT", 55 | "ARGUMENT_TOO_LONG", 56 | "ARGUMENT_TOO_WORDY", 57 | "ARGUMENT_IS_TEMPORARY", 58 | "ARGUMENT_HAS_PREFIX_OR_POSTFIX", 59 | "METHOD_INVALID_NAME", 60 | "METHOD_ALLCAPS_NAME", 61 | "METHOD_TOO_SHORT", 62 | "METHOD_TOO_LONG", 63 | "METHOD_TOO_WORDY", 64 | "METHOD_IS_TEMPORARY", 65 | "METHOD_HAS_PREFIX_OR_POSTFIX", 66 | "COMPONENT_INVALID_NAME", 67 | "COMPONENT_ALLCAPS_NAME", 68 | "COMPONENT_TOO_SHORT", 69 | "COMPONENT_TOO_LONG", 70 | "COMPONENT_TOO_WORDY", 71 | "COMPONENT_IS_TEMPORARY", 72 | "COMPONENT_HAS_PREFIX_OR_POSTFIX", 73 | "FILE_SHOULD_START_WITH_LOWERCASE", 74 | "AVOID_USING_CREATEOBJECT", 75 | "AVOID_USING_DEBUG_ATTR", 76 | "AVOID_USING_CFSETTING_DEBUG", 77 | "UNUSED_LOCAL_VARIABLE", 78 | "UNUSED_METHOD_ARGUMENT", 79 | "COMPARE_INSTEAD_OF_ASSIGN", 80 | "PARSE_ERROR", 81 | "MISSING_SEMI", 82 | "UNQUOTED_STRUCT_KEY", 83 | "SQL_SELECT_STAR", 84 | "NEVER_USE_QUERY_IN_CFM", 85 | "USE_DISPLAY_NAME", 86 | "LOCAL_LITERAL_VALUE_USED_TOO_OFTEN", 87 | "GLOBAL_LITERAL_VALUE_USED_TOO_OFTEN", 88 | "PACKAGE_CASE_MISMATCH", 89 | "PARSE_NOTHING", 90 | "PLUGIN_ERROR", 91 | "AVOID_EMPTY_FILES" 92 | ] 93 | } 94 | 95 | -------------------------------------------------------------------------------- /src/main/resources/com/stepstone/sonar/plugin/coldfusion/rules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ARG_DEFAULT_MISSING 5 | Optional argument is missing a default value. 6 | CRITICAL 7 | SINGLE 8 |

]]>
9 | bug 10 |
11 | 12 | ARG_VAR_CONFLICT 13 | Variable declared in both var and argument scopes. 14 | MAJOR 15 | SINGLE 16 | Variable should not be declared in both local and argument scopes.

]]>
17 | bug 18 |
19 | 20 | ARG_VAR_MIXED 21 | Variable referenced in local and argument scopes. 22 | MAJOR 23 | SINGLE 24 | Variable should not be referenced in local and argument scope.

]]>
25 | bug 26 |
27 | 28 | NO_DEFAULT_INSIDE_SWITCH 29 | Missing default switch statement. 30 | MAJOR 31 | SINGLE 32 | Not having a Default statement defined for a switch could pose potential issues.

]]>
33 |
34 | 35 | GLOBAL_VAR 36 | Global variable exists. 37 | CRITICAL 38 | SINGLE 39 | Identifier is global. Referencing in a CFC or function should be avoided.

]]>
40 | bug 41 |
42 | 43 | NESTED_CFOUTPUT 44 | Nested cfoutput with cfquery tag. 45 | MINOR 46 | SINGLE 47 | Nested CFOutput, outer CFOutput has @query.

]]>
48 |
49 | 50 | OUTPUT_ATTR 51 | Tag should have output='false'. 52 | MAJOR 53 | SINGLE 54 | should have @output='false'

]]>
55 |
56 | 57 | QUERYPARAM_REQ 58 | SetSql() statement should use .addParam(). 59 | BLOCKER 60 | SINGLE 61 | setSql() statement should use .addParam() instead of #'s name="variable"

]]>
62 | security 63 |
64 | 65 | CFQUERYPARAM_REQ 66 | cfquery should use cfqueryparam 67 | BLOCKER 68 | SINGLE 69 | should use for variable 'variable'.

]]>
70 | security 71 |
72 | 73 | QUERYNEW_DATATYPE 74 | QueryNew statement should specify datatypes. 75 | BLOCKER 76 | SINGLE 77 |

]]>
78 | bug 79 |
80 | 81 | MISSING_VAR 82 | Variable is not declared with a var statement. 83 | CRITICAL 84 | SINGLE 85 | Variable is not declared with a var statement.

]]>
86 | bug 87 |
88 | 89 | AVOID_USING_CFDUMP_TAG 90 | Avoid use of cfdump tags. 91 | MAJOR 92 | SINGLE 93 | Avoid leaving tags in committed code. Debug information should be omitted from release code

]]>
94 | security 95 |
96 | 97 | AVOID_USING_CFEXECUTE_TAG 98 | Avoid use of cfexecute tags. 99 | CRITICAL 100 | SINGLE 101 | Avoid leaving tags in committed code. CFexecute can be used as an attack vector and is slow.

]]>
102 | security 103 |
104 | 105 | AVOID_USING_ISDATE 106 | Avoid use of isDate() 107 | MAJOR 108 | SINGLE 109 | Avoid using the isDate() built-in function. It is too permissive. Use isValid() instead.

]]>
110 | bug 111 |
112 | 113 | AVOID_USING_CFABORT_TAG 114 | Avoid use of cfabort tags. 115 | CRITICAL 116 | SINGLE 117 | Avoid leaving tags in committed code.

]]>
118 | bug 119 |
120 | 121 | AVOID_USING_ABORT 122 | Avoid use of abort statements. 123 | CRITICAL 124 | SINGLE 125 | Avoid using abort in production code.

]]>
126 | bug 127 |
128 | 129 | AVOID_USING_CFINSERT_TAG 130 | Avoid use of cfinsert tags. 131 | CRITICAL 132 | SINGLE 133 | Avoid using tags. Use cfquery and cfstoredproc instead.

]]>
134 | bug 135 |
136 | 137 | AVOID_USING_CFMODULE_TAG 138 | Avoid use of cfmodule tags. 139 | MAJOR 140 | SINGLE 141 |

]]>
142 | bug 143 |
144 | 145 | AVOID_USING_CFUPDATE_TAG 146 | Avoid use of cfupdate tags. 147 | MAJOR 148 | SINGLE 149 | Avoid using tags. Use cfquery and cfstoredproc instead.

]]>
150 | bug 151 |
152 | 153 | AVOID_USING_CFINCLUDE_TAG 154 | Avoid use of cfinclude tags. 155 | CRITICAL 156 | SINGLE 157 | Avoid using tags. Use components instead.

]]>
158 | 159 |
160 | 161 | COMPONENT_HINT_MISSING 162 | Component is missing a hint. 163 | MINOR 164 | SINGLE 165 |

]]>
166 |
167 | 168 | FUNCTION_HINT_MISSING 169 | Function is missing a hint. 170 | MINOR 171 | SINGLE 172 |

]]>
173 |
174 | 175 | ARG_HINT_MISSING 176 | Argument is missing a hint. 177 | MINOR 178 | SINGLE 179 |

]]>
180 |
181 | 182 | ARG_HINT_MISSING_SCRIPT 183 | Argument is missing a hint. 184 | MINOR 185 | SINGLE 186 | Argument is missing a hint. Use javadoc style annotations on cfscript functions.

]]>
187 |
188 | 189 | ARG_TYPE_MISSING 190 | Component is missing a type. 191 | BLOCKER 192 | SINGLE 193 | Argument variable is missing a type.

]]>
194 | bug 195 |
196 | 197 | ARG_TYPE_ANY 198 | Component is of type any. 199 | CRITICAL 200 | SINGLE 201 |

]]>
202 | bug 203 |
204 | 205 | EXCESSIVE_FUNCTION_LENGTH 206 | Method is too long. 207 | MAJOR 208 | SINGLE 209 | Function should be fewer than 100 lines.

]]>
210 |
211 | 212 | EXCESSIVE_COMPONENT_LENGTH 213 | Component is too long. 214 | MAJOR 215 | SINGLE 216 | Component should be fewer than 500 lines.

]]>
217 |
218 | 219 | FUNCTION_TYPE_MISSING 220 | Function is missing a return type. 221 | BLOCKER 222 | SINGLE 223 |

]]>
224 | bug 225 |
226 | 227 | FUNCTION_TYPE_ANY 228 | Function has a return type of any. 229 | CRITICAL 230 | SINGLE 231 |

]]>
232 | bug 233 |
234 | 235 | EXCESSIVE_ARGUMENTS 236 | Function has too many arguments. 237 | MAJOR 238 | SINGLE 239 | Function has too many arguments. Should be fewer than 10.

]]>
240 |
241 | 242 | EXCESSIVE_FUNCTIONS 243 | Too many functions. 244 | MINOR 245 | SINGLE 246 | Component has too many functions. Should be fewer than 10.

]]>
247 |
248 | 249 | FUNCTION_TOO_COMPLEX 250 | Function is too complex. 251 | CRITICAL 252 | SINGLE 253 | Function is too complex. Consider breaking the function into smaller functions.

]]>
254 |
255 | 256 | AVOID_USING_WRITEDUMP 257 | Avoid use of writedump statements. 258 | MAJOR 259 | SINGLE 260 |

]]>
261 | security 262 |
263 | 264 | AVOID_USING_STRUCTNEW 265 | Avoid use of structnew statements. Use {} instead. 266 | MINOR 267 | SINGLE 268 |

]]>
269 |
270 | 271 | AVOID_USING_ISDEBUGMODE 272 | Avoid use of isdebugmode statements. 273 | MINOR 274 | SINGLE 275 | Avoid using the IsDebugMode function in production code.

]]>
276 |
277 | 278 | AVOID_USING_ARRAYNEW 279 | Avoid use of arraynew statements. Use [] instead. 280 | MINOR 281 | SINGLE 282 |

]]>
283 |
284 | 285 | COMPLEX_BOOLEAN_CHECK 286 | Complex boolean expression. 287 | MAJOR 288 | SINGLE 289 |

]]>
290 |
291 | 292 | EXPLICIT_BOOLEAN_CHECK 293 | Checking boolean expression explicitly. 294 | MAJOR 295 | SINGLE 296 | Explicit check of boolean expression is not needed.

]]>
297 |
298 | 299 | VAR_INVALID_NAME 300 | Variable has invalid name. 301 | CRITICAL 302 | SINGLE 303 | Variable is not a valid name. Please use camelCase or underscores.

]]>
304 | bug 305 |
306 | 307 | VAR_ALLCAPS_NAME 308 | Variable name is allcaps. 309 | MINOR 310 | SINGLE 311 | Variable should not be upper case.

]]>
312 |
313 | 314 | VAR_TOO_SHORT 315 | Variable name is too short. 316 | MINOR 317 | SINGLE 318 |

]]>
319 |
320 | 321 | VAR_TOO_LONG 322 | Variable name is too long. 323 | MINOR 324 | SINGLE 325 |

]]>
326 |
327 | 328 | VAR_TOO_WORDY 329 | Variable name contain too many words. 330 | MINOR 331 | SINGLE 332 |

]]>
333 |
334 | 335 | VAR_IS_TEMPORARY 336 | Variable name looks temporary. 337 | MAJOR 338 | SINGLE 339 |

]]>
340 |
341 | 342 | VAR_HAS_PREFIX_OR_POSTFIX 343 | Variable name has prefix or postfix. 344 | MINOR 345 | SINGLE 346 | Variable has prefix or postfix variable and could be named better.

]]>
347 |
348 | 349 | ARGUMENT_MISSING_NAME 350 | Argument is missing a name. 351 | MINOR 352 | SINGLE 353 |

]]>
354 |
355 | 356 | ARGUMENT_INVALID_NAME 357 | Argument has invalid name. 358 | CRITICAL 359 | SINGLE 360 | Please use camelCase or underscores.

]]>
361 | bug 362 |
363 | 364 | ARGUMENT_ALLCAPS_NAME 365 | Argument name is allcaps. 366 | MINOR 367 | SINGLE 368 |

]]>
369 |
370 | 371 | ARGUMENT_TOO_SHORT 372 | Argument name is too short. 373 | MINOR 374 | SINGLE 375 |

]]>
376 |
377 | 378 | ARGUMENT_TOO_LONG 379 | Argument name is too long. 380 | MINOR 381 | SINGLE 382 |

]]>
383 |
384 | 385 | ARGUMENT_TOO_WORDY 386 | Argument name contain too many words. 387 | MINOR 388 | SINGLE 389 |

]]>
390 |
391 | 392 | ARGUMENT_IS_TEMPORARY 393 | Argument name looks temporary. 394 | MAJOR 395 | SINGLE 396 |

]]>
397 |
398 | 399 | ARGUMENT_HAS_PREFIX_OR_POSTFIX 400 | Argument name has prefix or postfix. 401 | MINOR 402 | SINGLE 403 |

]]>
404 |
405 | 406 | METHOD_INVALID_NAME 407 | Method has invalid name. 408 | CRITICAL 409 | SINGLE 410 |

]]>
411 | bug 412 |
413 | 414 | METHOD_ALLCAPS_NAME 415 | Method name is allcaps. 416 | MINOR 417 | SINGLE 418 |

]]>
419 |
420 | 421 | METHOD_TOO_SHORT 422 | Method name is too short. 423 | MINOR 424 | SINGLE 425 |

]]>
426 |
427 | 428 | METHOD_TOO_LONG 429 | Method name is too long. 430 | MINOR 431 | SINGLE 432 |

]]>
433 |
434 | 435 | METHOD_TOO_WORDY 436 | Method name contain too many words. 437 | MINOR 438 | SINGLE 439 |

]]>
440 |
441 | 442 | METHOD_IS_TEMPORARY 443 | Method name looks temporary. 444 | MAJOR 445 | SINGLE 446 |

]]>
447 |
448 | 449 | METHOD_HAS_PREFIX_OR_POSTFIX 450 | Method name has prefix or postfix. 451 | MINOR 452 | SINGLE 453 |

]]>
454 |
455 | 456 | COMPONENT_INVALID_NAME 457 | Component has invalid name. 458 | CRITICAL 459 | SINGLE 460 |

]]>
461 | bug 462 |
463 | 464 | COMPONENT_ALLCAPS_NAME 465 | Component name is allcaps. 466 | MINOR 467 | SINGLE 468 |

]]>
469 |
470 | 471 | COMPONENT_TOO_SHORT 472 | Component name is too short. 473 | MINOR 474 | SINGLE 475 |

]]>
476 |
477 | 478 | COMPONENT_TOO_LONG 479 | Component name is too long. 480 | MINOR 481 | SINGLE 482 |

]]>
483 |
484 | 485 | COMPONENT_TOO_WORDY 486 | Component name contain too many words. 487 | MINOR 488 | SINGLE 489 |

]]>
490 |
491 | 492 | COMPONENT_IS_TEMPORARY 493 | Component name looks temporary. 494 | MAJOR 495 | SINGLE 496 | Component name component could be named better.

]]>
497 |
498 | 499 | COMPONENT_HAS_PREFIX_OR_POSTFIX 500 | Component name has prefix or postfix. 501 | MINOR 502 | SINGLE 503 | Component name has prefix or postfix and could be named better.

]]>
504 |
505 | 506 | FILE_SHOULD_START_WITH_LOWERCASE 507 | CFM File starts with upper case. 508 | MINOR 509 | SINGLE 510 | Filename starts with an upper case letter. Only components (.cfc files) should start with an upper case letter.

]]>
511 |
512 | 513 | AVOID_USING_CREATEOBJECT 514 | Avoid use of creatobject statements. 515 | MAJOR 516 | SINGLE 517 |

]]>
518 |
519 | 520 | AVOID_USING_DEBUG_ATTR 521 | Avoid use of debug attribute. 522 | CRITICAL 523 | SINGLE 524 |

]]>
525 | security 526 |
527 | 528 | UNUSED_LOCAL_VARIABLE 529 | Unused local variable. 530 | MAJOR 531 | SINGLE 532 |

]]>
533 |
534 | 535 | UNUSED_METHOD_ARGUMENT 536 | Unused method argument. 537 | MAJOR 538 | SINGLE 539 |

]]>
540 |
541 | 542 | COMPARE_INSTEAD_OF_ASSIGN 543 | Using comparison where assignment was probably meant. 544 | CRITICAL 545 | SINGLE 546 | Comparing instead of Assigning

]]>
547 | bug 548 |
549 | 550 | PARSE_ERROR 551 | Unable to parse 552 | CRITICAL 553 | SINGLE 554 |

]]>
555 | bug 556 |
557 | 558 | SCOPE_ALLCAPS_NAME 559 | Variable scope name is allcaps. 560 | MINOR 561 | SINGLE 562 | Scope variable should not be upper case.

]]>
563 |
564 | 565 | AVOID_USING_CFSETTING_DEBUG 566 | Avoid using showDebugOutput attribute on cfsetting. 567 | CRITICAL 568 | SINGLE 569 |

]]>
570 | security 571 |
572 | 573 | MISSING_SEMI 574 | No semicolon! 575 | CRITICAL 576 | SINGLE 577 | This statement is missing a semicolon!

]]>
578 | bug 579 |
580 | 581 | UNQUOTED_STRUCT_KEY 582 | Unquoted struct key 583 | MAJOR 584 | SINGLE 585 | Unquoted structure keys may or may not maintain their case on output. Quoting is recommended to make sure the case of the key is always the same.

]]>
586 |
587 | 588 | SQL_SELECT_STAR 589 | Star in SQL SELECT 590 | MAJOR 591 | SINGLE 592 | Avoid using SELECT * in a query.

]]>
593 |
594 | 595 | NEVER_USE_QUERY_IN_CFM 596 | Never use CFQUERY in .cfm files 597 | MINOR 598 | SINGLE 599 | Don't use <cfquery> in .cfm files. Database should not be coupled with view.

]]>
600 |
601 | 602 | USE_DISPLAY_NAME 603 | Use displayName instead of name 604 | MINOR 605 | SINGLE 606 | The component has a name attribute perhaps you meant to use displayName?

]]>
607 |
608 | 609 | LOCAL_LITERAL_VALUE_USED_TOO_OFTEN 610 | Local literal value used too often 611 | MINOR 612 | SINGLE 613 | The literal occurs several times in the same file. Consider giving it a name and not hard coding values.

]]>
614 |
615 | 616 | GLOBAL_LITERAL_VALUE_USED_TOO_OFTEN 617 | Global literal value used too often 618 | MINOR 619 | SINGLE 620 | The literal occurs several times in one or more files. Consider giving it a name and not hard coding values.

]]>
621 |
622 | 623 | PACKAGE_CASE_MISMATCH 624 | Package name case mismatch 625 | MINOR 626 | SINGLE 627 | The case of the package folder and the object declaration do not match.

]]>
628 |
629 | 630 | PARSE_NOTHING 631 | PARSE NOTHING 632 | CRITICAL 633 | SINGLE 634 |

]]>
635 | bug 636 |
637 | 638 | PLUGIN_ERROR 639 | PLUGIN_ERROR 640 | CRITICAL 641 | SINGLE 642 |

]]>
643 | bug 644 |
645 | 646 | AVOID_EMPTY_FILES 647 | AVOID_EMPTY_FILES 648 | MINOR 649 | SINGLE 650 |

]]>
651 | bug 652 |
653 | 654 | STRUCT_ARRAY_NOTATION 655 | Use array notation 656 | MAJOR 657 | SINGLE 658 | Unquoted struct key variable is not case-sensitive. Using array notation is recommended.

]]>
659 |
660 |
661 | -------------------------------------------------------------------------------- /src/test/java/com/stepstone/sonar/plugin/coldfusion/ColdfusionPluginTest.java: -------------------------------------------------------------------------------- 1 | package com.stepstone.sonar.plugin.coldfusion; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | import org.sonar.api.Plugin; 6 | import org.sonar.api.SonarEdition; 7 | import org.sonar.api.SonarQubeSide; 8 | import org.sonar.api.SonarRuntime; 9 | import org.sonar.api.utils.Version; 10 | import org.sonar.api.internal.SonarRuntimeImpl; 11 | 12 | 13 | public class ColdfusionPluginTest { 14 | 15 | 16 | private static final Version VERSION_9_0 = Version.create(9, 0); 17 | 18 | @Test 19 | public void testExtensions() { 20 | ColdFusionPlugin plugin = new ColdFusionPlugin(); 21 | SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(VERSION_9_0, SonarQubeSide.SERVER, SonarEdition.COMMUNITY); 22 | Plugin.Context context = new Plugin.Context(runtime); 23 | plugin.define(context); 24 | 25 | Assert.assertEquals(5, context.getExtensions().size()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/com/stepstone/sonar/plugin/coldfusion/ColdfusionSensorTest.java: -------------------------------------------------------------------------------- 1 | package com.stepstone.sonar.plugin.coldfusion; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Rule; 5 | import org.junit.Test; 6 | import org.junit.rules.TemporaryFolder; 7 | import org.sonar.api.SonarEdition; 8 | import org.sonar.api.SonarQubeSide; 9 | import org.sonar.api.batch.fs.InputFile; 10 | import org.sonar.api.batch.fs.internal.DefaultFileSystem; 11 | import org.sonar.api.batch.fs.internal.DefaultInputFile; 12 | import org.sonar.api.batch.fs.internal.TestInputFileBuilder; 13 | import org.sonar.api.batch.sensor.internal.SensorContextTester; 14 | import org.sonar.api.batch.sensor.measure.Measure; 15 | import org.sonar.api.internal.SonarRuntimeImpl; 16 | import org.sonar.api.internal.apachecommons.io.Charsets; 17 | import org.sonar.api.measures.CoreMetrics; 18 | import org.sonar.api.batch.rule.ActiveRules; 19 | import org.sonar.api.batch.rule.internal.ActiveRulesBuilder; 20 | import org.sonar.api.utils.Version; 21 | import org.sonar.api.utils.command.CommandExecutor; 22 | 23 | import java.io.File; 24 | 25 | import static org.assertj.core.api.Assertions.assertThat; 26 | 27 | public class ColdfusionSensorTest { 28 | 29 | private ActiveRules rulesProfile = new ActiveRulesBuilder().build(); 30 | private File baseDir = new File("src/test/resources").getAbsoluteFile(); 31 | private SensorContextTester context = SensorContextTester.create(baseDir); 32 | 33 | @Rule 34 | public TemporaryFolder tmpFolder = new TemporaryFolder(); 35 | 36 | @Test 37 | public void testBasicCFMAnalysis() { 38 | DefaultFileSystem fileSystem = new DefaultFileSystem(tmpFolder.getRoot()); 39 | fileSystem.setEncoding(Charsets.UTF_8); 40 | fileSystem.setWorkDir(tmpFolder.getRoot().toPath()); 41 | 42 | context.setFileSystem(fileSystem); 43 | context.setRuntime(SonarRuntimeImpl.forSonarQube(Version.create(9, 0), SonarQubeSide.SCANNER, SonarEdition.COMMUNITY)); 44 | 45 | context.settings().appendProperty("sonar.projectBaseDir", baseDir.getPath()); 46 | addFilesToFs(); 47 | 48 | CommandExecutor commandExecutor = CommandExecutor.create(); 49 | String javaHome = System.getProperty("java.home"); 50 | Assert.assertTrue(javaHome!=null && !javaHome.equals("")); 51 | 52 | if(OSValidator.isWindows()) { 53 | context.settings().appendProperty(ColdFusionPlugin.CFLINT_JAVA, javaHome + "/bin/java.exe"); 54 | } else { 55 | context.settings().appendProperty(ColdFusionPlugin.CFLINT_JAVA, javaHome + "/bin/java"); 56 | } 57 | 58 | ColdFusionSensor sensor = new ColdFusionSensor(context.fileSystem(), rulesProfile); 59 | sensor.execute(context); 60 | 61 | Integer nloc = 0; 62 | Integer comments = 0; 63 | Integer complexity = 0; 64 | for (InputFile o : context.fileSystem().inputFiles()) { 65 | Measure measureNloc = context.measure(o.key(),CoreMetrics.NCLOC.key()); 66 | Measure measureComment = context.measure(o.key(),CoreMetrics.COMMENT_LINES.key()); 67 | Measure measureComplexity = context.measure(o.key(),CoreMetrics.COMPLEXITY.key()); 68 | nloc+=measureNloc.value(); 69 | comments+=measureComment.value(); 70 | complexity+=measureComplexity.value(); 71 | } 72 | assertThat(nloc).isEqualTo(56); 73 | assertThat(comments).isEqualTo(9); 74 | assertThat(complexity).isEqualTo(10); 75 | 76 | } 77 | 78 | private void addFilesToFs() { 79 | DefaultInputFile inputFileMetrics1 = new TestInputFileBuilder(context.module().key(), baseDir.getAbsoluteFile(), new File("src/test/resources/testmetrics1.cfm").getAbsoluteFile()).setLanguage(ColdFusionPlugin.LANGUAGE_KEY).build(); 80 | context.fileSystem().add(inputFileMetrics1); 81 | DefaultInputFile inputFileMetrics2 = new TestInputFileBuilder(context.module().key(), baseDir.getAbsoluteFile(), new File("src/test/resources/testmetrics2.cfm").getAbsoluteFile()).setLanguage(ColdFusionPlugin.LANGUAGE_KEY).build(); 82 | context.fileSystem().add(inputFileMetrics2); 83 | DefaultInputFile inputFileMetrics3 = new TestInputFileBuilder(context.module().key(), baseDir.getAbsoluteFile(), new File("src/test/resources/EpisodeClaim.cfc").getAbsoluteFile()).setLanguage(ColdFusionPlugin.LANGUAGE_KEY).build(); 84 | context.fileSystem().add(inputFileMetrics3); 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/test/java/com/stepstone/sonar/plugin/coldfusion/OSValidator.java: -------------------------------------------------------------------------------- 1 | package com.stepstone.sonar.plugin.coldfusion; 2 | 3 | public class OSValidator { 4 | 5 | private static String OS = System.getProperty("os.name").toLowerCase(); 6 | 7 | public static boolean isWindows() { 8 | return (OS.contains("win")); 9 | } 10 | 11 | public static boolean isMac() { 12 | return (OS.contains("mac") ); 13 | } 14 | 15 | public static boolean isUnix() { 16 | return (OS.contains("nix") || OS.contains("nux") || OS.contains("aix")); 17 | } 18 | 19 | public static boolean isSolaris() { 20 | return (OS.contains("sunos") ); 21 | } 22 | public static String getOS(){ 23 | if (isWindows()) { 24 | return "win"; 25 | } else if (isMac()) { 26 | return "osx"; 27 | } else if (isUnix()) { 28 | return "uni"; 29 | } else if (isSolaris()) { 30 | return "sol"; 31 | } else { 32 | return "err"; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/resources/EpisodeClaim.cfc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | if (local.InfusionTherapy is 1) 34 | { 35 | M0250 = M0250 + 14; 36 | } 37 | if (local.ParentalNutrition is 1) 38 | { 39 | M0250 = M0250 + 20; 40 | } 41 | if (local.EnteralNutrition is 1) 42 | { 43 | M0250 = M0250 + 24; 44 | } 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/test/resources/testmetrics1.cfm: -------------------------------------------------------------------------------- 1 | 2 | Hello #firstName#! 3 | 4 | This CFML tutorial was designed for 5 | 6 | you! 7 | 8 | 9 | the world to see. 10 | 11 | 12 | 13 | Nico! 14 | 15 | the world to see. 16 | 17 | -------------------------------------------------------------------------------- /src/test/resources/testmetrics2.cfm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | Hello #firstName#! 7 | This CFML tutorial was designed for 8 | 9 | you! 10 | 11 | 15 | 16 | the world to see. 17 | 18 | --------------------------------------------------------------------------------