├── .ci ├── bats.task.yml ├── gawk-lint.task.yml ├── markdownlint.task.yml └── shellcheck.task.yml ├── .dockerignore ├── .editorconfig ├── .gitattributes ├── .github ├── CODEOWNERS ├── dependabot.yml └── workflows │ └── ci.yml ├── .gitignore ├── .mailmap ├── .markdownlint.json ├── .vscode └── extensions.json ├── AUTHORS.md ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── Dockerfile ├── LICENSE ├── README.md ├── assets ├── check ├── common.sh ├── in ├── out └── readproperties.awk ├── sonar-project.properties ├── structure-test └── tests.yaml ├── test.sh ├── test ├── cli_projects.bats ├── mocks │ ├── qualitygates_project_status.json │ └── sonar-scanner ├── out_cli_project.json ├── out_maven_project.json └── workspace │ ├── cli_project │ ├── report-task.mock.txt │ ├── src1 │ │ └── test.xml │ └── src2 │ │ └── noop.ts │ └── maven_project │ ├── .gitignore │ ├── pom.xml │ └── src │ └── main │ └── java │ └── com │ └── example │ └── Main.java └── test_common.sh /.ci/bats.task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | platform: linux 3 | 4 | image_resource: 5 | type: docker-image 6 | source: 7 | repository: dduportal/bats 8 | tag: "0.4.0" 9 | 10 | inputs: 11 | - name: src 12 | 13 | params: 14 | TERM: xterm-256color 15 | 16 | run: 17 | path: bats 18 | args: 19 | - ./test/ 20 | dir: src 21 | -------------------------------------------------------------------------------- /.ci/gawk-lint.task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | platform: linux 3 | 4 | image_resource: 5 | type: docker-image 6 | source: 7 | repository: algas/gawk 8 | tag: latest 9 | 10 | inputs: 11 | - name: src 12 | 13 | 14 | run: 15 | path: sh 16 | args: 17 | - -exc 18 | - | 19 | gawk --lint=fatal -f ./readproperties.awk < /dev/null 20 | dir: src/assets 21 | -------------------------------------------------------------------------------- /.ci/markdownlint.task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | platform: linux 3 | 4 | image_resource: 5 | type: docker-image 6 | source: 7 | repository: mivok/markdownlint 8 | tag: "0.4.0" 9 | 10 | inputs: 11 | - name: src 12 | 13 | 14 | run: 15 | path: mdl 16 | args: 17 | - ./README.md 18 | - ./AUTHORS.md 19 | - ./CHANGELOG.md 20 | - ./CODE_OF_CONDUCT.md 21 | dir: src 22 | -------------------------------------------------------------------------------- /.ci/shellcheck.task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | platform: linux 3 | 4 | image_resource: 5 | type: docker-image 6 | source: 7 | repository: koalaman/shellcheck 8 | tag: v0.4.6 9 | 10 | inputs: 11 | - name: src 12 | 13 | 14 | run: 15 | path: shellcheck 16 | args: 17 | - --shell=bash 18 | - ./check 19 | - ./in 20 | - ./out 21 | - ./common.sh 22 | dir: src/assets 23 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | /.ci/ 2 | /.vscode/ 3 | /.editorconfig 4 | /.travis.yml 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | insert_final_newline = true 6 | trim_trailing_whitespace = true 7 | indent_style = tab 8 | indent_size = 8 9 | 10 | [*.{json,xml,yaml,yml}] 11 | indent_style = space 12 | indent_size = 2 13 | 14 | [*.properties] 15 | charset = latin1 16 | 17 | [*.awk] 18 | end_of_line = lf 19 | 20 | [*.sh] 21 | end_of_line = lf 22 | 23 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.awk eol=lf 3 | *.sh eol=lf 4 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @headcr4sh 2 | * @holgerstolzenberg 3 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2 3 | updates: 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "daily" 8 | - package-ecosystem: "docker" 9 | directory: "/" 10 | schedule: 11 | interval: "daily" 12 | ... 13 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | tags: 9 | - v* 10 | 11 | jobs: 12 | publish: 13 | runs-on: ubuntu-22.04 14 | 15 | steps: 16 | - uses: actions/checkout@v5 17 | - name: Prepare 18 | id: prepare 19 | run: | 20 | TAG=${GITHUB_REF##*/} 21 | echo "tag_name=${TAG}" >> $GITHUB_OUTPUT 22 | - name: Set up QEMU 23 | uses: docker/setup-qemu-action@v3 24 | - name: Set up Docker Buildx 25 | uses: docker/setup-buildx-action@v3 26 | - name: Login to docker.io 27 | id: docker-login 28 | if: ${{ github.actor != 'dependabot[bot]' }} 29 | uses: docker/login-action@v3 30 | with: 31 | username: "${{ secrets.DOCKER_HUB_USERNAME }}" 32 | password: "${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}" 33 | - name: build and publish image 34 | id: docker_build 35 | uses: docker/build-push-action@v6 36 | with: 37 | context: . 38 | file: ./Dockerfile 39 | platforms: linux/amd64,linux/arm64 40 | push: ${{ github.actor != 'dependabot[bot]' }} 41 | tags: | 42 | cathive/concourse-sonarqube-resource:${{ steps.prepare.outputs.tag_name }} 43 | cathive/concourse-sonarqube-resource:latest 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | /.idea/ 3 | /.scannerwork/ -------------------------------------------------------------------------------- /.mailmap: -------------------------------------------------------------------------------- 1 | Febin Rejoe Muthiah 2 | Fernando Torres <47677090+fftorres@users.noreply.github.com> 3 | Benjamin P. Jung Benjmain P. Jung 4 | Benjamin P. Jung 5 | Julien Syx 6 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "line-length": false, 3 | "no-duplicate-heading": false 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "davidanson.vscode-markdownlint", 4 | "editorconfig.editorconfig", 5 | "jetmartin.bats", 6 | "luggage66.awk", 7 | "pivotal.vscode-concourse", 8 | "timonwong.shellcheck" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /AUTHORS.md: -------------------------------------------------------------------------------- 1 | # Authors 2 | 3 | ## Maintainers 4 | 5 | * Benjamin P. Jung <headcr4sh@gmail.com> 6 | * Holger Stolzenberg <h.stolzenberg@ewerk.com> 7 | 8 | ## Contributors 9 | 10 | * Chien Jon Soon <sooncj@hotmail.com> 11 | * Febin Rejoe <FM046667@cerner.net> 12 | * Fernando Torres <fft@hellofresh.com> 13 | * Greg Carter <greg_carter@comcast.com> 14 | * Guillaume Pouilloux <gpouilloux@idmog.com> 15 | * Horst Gutmann <zerok@zerokspot.com> 16 | * Julien Syx <julien.syx@cycloid.io> 17 | * Marek Urban 18 | * Ming Xu <mingx@vmware.com> 19 | * Nabil Abdelwahd <nabil.labout@gmail.com> 20 | * "odidev" <odidev@puresoftware.com> 21 | * Pinaki Sarkar <pinaki.sarkar@calculi.com> 22 | * Pontus Arfwedson <pontus.arfwedson@netlight.com> 23 | * Pruthvidhar Rao Nadunooru <nadunoorup@vmware.com> 24 | * Rekha Mittal <rekha.mittal@calculi.com> 25 | * Roberto C. Salome <robertocsalome@gmail.com> 26 | * Rune Engseth <rune.engseth@tine.no> 27 | * Samed Ozdemir <samed@xsorcreations.com> 28 | * Ye Yang <yangye@vmware.com> 29 | 30 | ## Third party components 31 | 32 | * `readproperties.awk` is a snippet that has been written by Joshua Davis and shamelessly ripped off from 33 | [Stack Overflow](https://stackoverflow.com/a/2318840). 34 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 6 | and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ### Updated 11 | 12 | - The bundled version of Apache Maven has been updated to v3.9.1. 13 | 14 | 15 | ## [0.14.3] - ??? 16 | 17 | ### Updated 18 | 19 | - Some minor bugfixes 20 | - Upgrade to Maven 3.9.1 21 | - Upgrade to NoeJS 20 22 | 23 | ## [0.14.2] - 2023-01-10 24 | 25 | ### Updated 26 | 27 | - The bundled version of Apache Maven has been updated to v3.8.7. 28 | - The bundled version of Node.js has been updated to v18.x. 29 | - The bundled version of TypeScript has been updated to v4.9.4. 30 | 31 | 32 | ## [0.14.1] - 2022-08-24 33 | 34 | This version contains a minor bugfix. 35 | 36 | ### Fixed 37 | 38 | - Fixes small awk issue causing annoying log message 39 | 40 | 41 | ## [0.14.0] - 2022-07-21 42 | 43 | A new maintainer has stepped forward! 44 | Welcome, [Holger Stolzenberg](https://github.com/holgerstolzenberg)! 45 | 46 | 47 | ### Added 48 | 49 | - Container images are now available for amd64 *and* arm64 architecture. Thanks a lot, ["odidev"](https://github.com/odidev) 50 | for the initial pull request to introduce this feature. 51 | - A new parameter `additional_sonar_scanner_opts` is now available, which allows users to specifiy the 52 | `SONAR_SCANNER_OPTS` environment variable for elobarorated SonarQube scanner invocations. 53 | 54 | ### Changed 55 | 56 | - Main development branch has been renamed from `master` to `main`. 57 | - Fully-automated CI/CD builds that will create container images with tag `:latest` whenever changes to the 58 | `main` branch are pushed works again after some changes made by Docker Hub that broke the old CI/CD workflow. 59 | 60 | ### Fixed 61 | 62 | - Setting argument `__debug=true` no longer breaks Maven-based builds. Thanks for the fix,[Roberto C. Salome](https://github.com/rcsalome)! 63 | 64 | ### Updated 65 | 66 | - Sonar CLI, bundled Node.js version and all other dependencies in the container image(s) have been updated 67 | to their latest release versions. 68 | 69 | ## [0.13.2] - 2020-10-24 70 | 71 | This version contains fixes provided by [Julien Syx](https://github.com/Seraf). 72 | Thanks for helping out and making this release possible! 73 | 74 | ### Fixed 75 | 76 | - Fix broken builds that occured when no `maven_settings_file` is set. 77 | ([#66](https://github.com/cathive/concourse-sonarqube-resource/issues/66), [#67](https://github.com/cathive/concourse-sonarqube-resource/issues/67)) 78 | 79 | - Pull request identification if `decorate_pr` is set to `true` has been fixed. 80 | 81 | ## [0.13.1] - 2020-09-30 82 | 83 | ### Fixed 84 | 85 | - Wrong relative lookup of `maven_settings_file` has been fixed. 86 | ([#59](https://github.com/cathive/concourse-sonarqube-resource/issues/59), [#65](https://github.com/cathive/concourse-sonarqube-resource/issues/65)) 87 | 88 | ## [0.13.0] - 2020-09-30 89 | 90 | Thanks to [Chien Jon Soon](https://github.com/sooncj) and [Pruthvidhar Rao Nadunooru](https://github.com/pnedunuri) for their contributions to this release! 91 | 92 | ### Added 93 | 94 | - Globbing syntax support (`shopt -s globstar`) has been added. ([#60](https://github.com/cathive/concourse-sonarqube-resource/issues/60)) 95 | 96 | ### Fixed 97 | 98 | - `sonar.branch.name` should now work correctly when performing pull-request analysis 99 | 100 | ### Updated 101 | 102 | - Base docker image has been updaed to openjdk:11.0.8-slim. 103 | - The bundled Sonar Scanner CLI has been updated to v4.4.0.2170. 104 | - The bundled TypeScript version has been updated to v[3.9.7](https://github.com/microsoft/TypeScript/releases/tag/v3.9.7). 105 | 106 | ## [0.12.0] - 2020-06-12 107 | 108 | Thanks to "[noelcat](https://github.com/noelcatt)" for the pull request to add support 109 | for BitBucket pull request decorators. 110 | 111 | ### Added 112 | 113 | - Support for BitBucket pull request decorations has been added. 114 | 115 | ### Updated 116 | 117 | - Base docker image has been updaed to openjdk:11.0.7-slim. 118 | - The bundled Sonar Scanner CLI has been updated to v4.3.0.2102. 119 | - The bundled TypeScript version has been updated to v3.9.5. 120 | 121 | ## [0.11.4] - 2020-05-18 122 | 123 | ### Fixed 124 | 125 | Thanks to [Nabil Abdelwahd](https://github.com/Labout) for the patch that made this 126 | release possible. 127 | 128 | - The `branch_name_file` parameter should now work as supposed to. ([#55](https://github.com/cathive/concourse-sonarqube-resource/issues/55)) 129 | 130 | ## [0.11.3] - 2020-03-06 131 | 132 | Thanks to [Samed Ozdemir](https://github.com/xsorifc28) who provided a patch to 133 | enhance the functionality of this resource for this release. 134 | 135 | ### Added 136 | 137 | - The parameters `branch_name_file` and `branch_target_file` have been added to 138 | allow for more sophisticated integration options with SonarQube's branch 139 | management feature. ([#52](https://github.com/cathive/concourse-sonarqube-resource/issues/52)) 140 | 141 | ### Updated 142 | 143 | - The bundled TypeScript version has been updated to v3.8.3. 144 | 145 | ### Fixed 146 | 147 | - The environment variable `NODE_PATH` is now set correctly, which should fix 148 | issues with the sonar-typescript-plugin. ([#51](https://github.com/cathive/concourse-sonarqube-resource/issues/51)) 149 | 150 | ## [0.11.2] - 2020-02-05 151 | 152 | ### Fixed 153 | 154 | - JAVA_HOME was not correctly linked and rendered the `cli` variant of the sonar-scanner 155 | unusable. ([#50](https://github.com/cathive/concourse-sonarqube-resource/issues/50)) 156 | 157 | ## [0.11.1] - 2020-01-24 [YANKED] 158 | 159 | ### Fixed 160 | 161 | - Base container image has been downgraded to `openjdk:11.0.6-slim` 162 | SonarQube scanners as of now only support Java 8 and Java 11 163 | according to the [documentation](https://docs.sonarqube.org/latest/requirements/requirements/). 164 | Some plugins don't support newer Java runtimes which breaks all 165 | functionality of this resource. 166 | 167 | ## [0.11.0] - 2020-01-22 [YANKED] 168 | 169 | ### Updated 170 | 171 | - Base container image has been updated to `openjdk:13.0.1-slim` 172 | - The bundled sonar-scanner-cli has been updated to v4.2.0.1873. 173 | - The bundled Maven command line has been updated to v3.6.3. 174 | - The bundled sonar-maven-plugin has been updated to v3.7.0.1746. 175 | 176 | ### Fixed 177 | 178 | - The TypeScript (`tsc`) command line has been removed in a prior version of the 179 | resource without proper notice. This breaks existing build pipelines that rely 180 | upon tsc's existence and therefore TypeScript has been re-added to the image 181 | and is now properly being version-managed. ([#48](https://github.com/cathive/concourse-sonarqube-resource/issues/48)) 182 | 183 | ### Improved 184 | 185 | - A container structure test has been added to the repository to make sure that 186 | the resource won't break as easily when updates are being made under the hood. 187 | ([#48](https://github.com/cathive/concourse-sonarqube-resource/issues/48), [#49](https://github.com/cathive/concourse-sonarqube-resource/issues/49)) 188 | 189 | ## [0.10.0] - 2019-11-13 190 | 191 | Thanks to [Fernando Torres](https://github.com/fftorres) for all the fixes and 192 | enhancements that went into this release! 193 | 194 | ### Added 195 | 196 | - Add support for Pull Request decorations. 197 | 198 | ### Fixed 199 | 200 | - Fixed an issue when parsing the project status after analysis. ([#44](https://github.com/cathive/concourse-sonarqube-resource/issues/44)) 201 | - Fixed behavior of the defunct `autodetect_branch_name` flag. 202 | 203 | ## [0.9.1] - 2019-08-23 204 | 205 | ### Added 206 | 207 | - Improved support for wildcard path arguments for properties 208 | ending with `*reportPaths`. 209 | 210 | ### Updated 211 | - Corrected some documentation. 212 | 213 | ## [0.9.0] - 2019-07-26 214 | 215 | ### Added 216 | 217 | - New optional `out` step parameter: `project_key_file`. 218 | Thanks to [Guillaume Pouilloux](https://github.com/gpouilloux) for the patch. 219 | - New optional `in` step parameter: `quality_gate` 220 | Thanks to [Ming Xu](https://github.com/SimonXming) for the patch. 221 | - Support for Wildcard path arguments. 222 | Thanks to [Ming Xu](https://github.com/SimonXming) for the patch. 223 | - The output now contains additional metadata about quality gate status conditions 224 | Thanks to [Ye Yang](https://github.com/mgsolid) for the patch. 225 | 226 | ### Updated 227 | 228 | - The bundled sonar-scanner-cli has been updated to v4.0.0.1744. 229 | - The bundled Maven command line has been updated to v3.6.1. 230 | 231 | ## [0.8.1] - 2019-01-29 232 | 233 | ### Fixed 234 | 235 | - `params.maven_settings_file` should no longer be ignored. 236 | ([#36](https://github.com/cathive/concourse-sonarqube-resource/issues/36)) 237 | 238 | ## [0.8.0] - 2019-01-25 239 | 240 | ### Added 241 | 242 | - Error handling when fetching the compute engine status has been improved. 243 | Thanks to [Rekha Mittal](https://github.com/rekhamitt) for the provided 244 | patch. ([#33](https://github.com/cathive/concourse-sonarqube-resource/issues/33)) 245 | - A new flag (`additional_properties_file`) can be used to instrument the 246 | sonar-scanner. Thanks to [Horst Gutmanm](https://github.com/zerok) for the 247 | provided patch. 248 | 249 | ### Updated 250 | 251 | - The bundled sonar-scanner-cli has been updated to v3.3.0.1492. 252 | - The bundled sonar-maven-plugin has been updated to v3.6.0.1398. 253 | 254 | ### Fixed 255 | 256 | - Fix issues when an auth-token (instead of username + password) is being used 257 | for authentication/authorization. Thanks to [Febin Rejoe](https://github.com/febinrejoe) 258 | for the provided fix. ([#31](https://github.com/cathive/concourse-sonarqube-resource/issues/31)) 259 | 260 | ## [0.7.2] - 2018-12-09 261 | 262 | ### Added 263 | 264 | - If the specified URL of the SonarQube server instance 265 | doesn't end in a slash, the missing slash will be appended 266 | automatically. ([#20](https://github.com/cathive/concourse-sonarqube-resource/issues/20)) 267 | 268 | ## [0.7.1] - 2018-12-09 269 | 270 | ### Fixed 271 | 272 | - scanner-report.txt could not be found if `scanner_type` was set to `maven` ([#24](https://github.com/cathive/concourse-sonarqube-resource/issues/24)) 273 | - Version 0.7.0 contained a bug where the bundled sonar-maven-plugin was *not* updated 274 | to version v3.5.0.1254 as originally announced. This version fixes this issue and 275 | makes sure that the desired version of he sonar-maven-plugin is being used. 276 | 277 | ## [0.7.0] - 2018-12-07 278 | 279 | ### Fixed 280 | 281 | - Custom maven settings are used correctly when perfoming SonarQube analysis. Thanks to [Marek Urban](https://github.com/marek-urban) for the provided fix. 282 | ([#19](https://github.com/cathive/concourse-sonarqube-resource/issues/19)) 283 | - Docker builds should no longer fail because of corrupted sonar-scanner 284 | zip archive. ([#26](https://github.com/cathive/concourse-sonarqube-resource/issues/26)) 285 | - Anonymous access to SonarQube servers that don't require authentication 286 | should now be possible. ([#25](https://github.com/cathive/concourse-sonarqube-resource/issues/25)) 287 | 288 | ### Added 289 | 290 | - The integrity of the bundled Maven installation and the sonar-scanner 291 | distribution is now being checked agains sha512 checksums to ensure the contents of the downloads has not been altered. 292 | 293 | ### Updated 294 | 295 | - The bundled Maven installation has been updated to v3.6.0. 296 | - The bundled sonar-maven-plugin has been updated to v3.5.0.1254. 297 | 298 | ## [0.6.0] - 2018-05-30 299 | 300 | ### Removed 301 | 302 | - The idea of using a project-local maven wrapper instance seemed nice but 303 | was not really usable / stable in practice. Therefore the feature had to 304 | be removed. 305 | 306 | ## [0.5.1] - 2018-05-30 307 | 308 | ### Fixed 309 | 310 | - An issue with using the maven wrapper was introduced in 0.5.0. 311 | If a project uses the maven wrapper and the scanner_type is set to `maven` 312 | (or the scanner_type was automatically detected), such builds were broken, 313 | because the maven wrapper was not executed correctly. 314 | 315 | ## [0.5.0] - 2018-05-30 316 | 317 | ### Fixed 318 | 319 | - Anonymous analysis without username/password or access token should now be possible. 320 | ([#13](https://github.com/cathive/concourse-sonarqube-resource/issues/13)) 321 | 322 | ### Added 323 | 324 | - A new configuration parameter (`source.__debug`) has been added that can be used 325 | to debug the resource itself when developing new features or fixing bugs. 326 | (This flag is *not* ment to be used in production environments, though!) 327 | 328 | - The unit test framework has been enhanced and it should now be possible to write 329 | some real proper unit tests using the "bats" framework. 330 | 331 | - If the scanner type has been set to `maven` (or if it has been automatically 332 | determined by the existence of a pom.xml file), the resource will now use the 333 | installed maven wrapper (if there is an executable `mvww` file in the project's 334 | root folder). 335 | 336 | ### Changed 337 | 338 | - Starting with this release, the shell scripts will use BASH's double brackets 339 | syntax for all if-checks, because it's generally less error-prone and and offers 340 | fewer surprises when dealing with nasty things such as uninitialized variables. 341 | 342 | ## [0.4.0] - 2018-05-27 343 | 344 | ### Added 345 | 346 | - `sonar.branch.name` can now be auto-detected if `params.autodetect_branch_name` has 347 | been set to `true`. 348 | ([#3](https://github.com/cathive/concourse-sonarqube-resource/issues/3)) 349 | 350 | ### Changed 351 | 352 | - Update sonar-scanner-cli to v3.2.0 353 | - Update sonar-maven-plugin to v3.4.0 354 | 355 | ## [0.3.1] - 2018-05-16 356 | 357 | ### Fixed 358 | 359 | - Multiple additional parameters work now as supposed to. 360 | ([#14](https://github.com/cathive/concourse-sonarqube-resource/issues/14)) 361 | 362 | ## [0.3.0] - 2018-03-28 363 | 364 | ### Added 365 | 366 | - Workaround for buggy certificate propagations in Alpine OpenJDK images. 367 | ([#16](https://github.com/cathive/concourse-sonarqube-resource/issues/16)) 368 | 369 | ## [0.2.0] - 2018-02-07 370 | 371 | ### Fixed 372 | 373 | - Parameters that contain whitespace characters no longer fail the `out` action. 374 | ([#6](https://github.com/cathive/concourse-sonarqube-resource/issues/6)) 375 | 376 | ### Added 377 | 378 | - Support for `params.tests`. 379 | ([#7](https://github.com/cathive/concourse-sonarqube-resource/issues/7)) 380 | 381 | - Support for `params.branch_name` and `params.branch_target`. 382 | Requires the [Branch Plugin](https://docs.sonarqube.org/display/PLUG/Branch+Plugin) or 383 | SonarCloud. 384 | 385 | ### Changed 386 | 387 | - `params.sources` must now be specified as list instead of comma-separated strings 388 | 389 | ### Removed 390 | 391 | - `params.branch` and `params.analysis_mode` are no longer supported. 392 | (New SonarQube versions handle short-lived branches in a different way) 393 | Use `params.branch_name` and `params.branch_target` instead if you use the 394 | Branch plugin. 395 | 396 | ## [0.0.32] - 2018-01-31 397 | 398 | ### Fixed 399 | 400 | - Support old SonarQube servers that don't report the server version in report-task.txt (Just report "unknown" as server version) ([#11](https://github.com/cathive/concourse-sonarqube-resource/issues/11)) 401 | 402 | ## [0.0.31] - 2018-01-23 403 | 404 | ### Fixed 405 | 406 | - Support old SonarQube servers that don't report the server version in report-task.txt (under certain conditions, this fix will not work though) ([#11](https://github.com/cathive/concourse-sonarqube-resource/issues/11)) 407 | 408 | ## [0.0.30] - 2018-01-18 409 | 410 | ### Added 411 | 412 | - Support for any additional properties that might need to be passed to the sonar-scanner. 413 | 414 | ### Fixed 415 | 416 | - Updated the documentation to make clear how a quality gate can be used to break the build. 417 | ([#9](https://github.com/cathive/concourse-sonarqube-resource/issues/9)) 418 | 419 | ## [0.0.20] - 2018-01-04 420 | 421 | ### Added 422 | 423 | - Support for SonarQube/SonarCloud organizations. ([#8](https://github.com/cathive/concourse-sonarqube-resource/issues/8)) 424 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at . All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # ====================== 2 | # Global build arguments 3 | # ====================== 4 | ARG RESOURCE_VERSION="0.14.3" 5 | ARG MAVEN_VERSION="3.9.5" 6 | ARG MAVEN_SHA512_CHECKSUM="ca59380b839c6bea8f464a08bb7873a1cab91007b95876ba9ed8a9a2b03ceac893e661d218ba3d4af3ccf46d26600fc4c59fccabba9d7b2cc4adcd8aecc1df2a" 7 | ARG SONAR_SCANNER_CLI_VERSION="4.7.0.2747" 8 | ARG SONAR_SCANNER_CLI_SHA512_CHECKSUM="92475d0b32d15c3602657852e8670b862ba2d1a1ecafefbc40c2b176173375e21931ae94c5966f454d31e3dea7fb3033cec742498660cf0dc0ff9fa742a9fe4a" 9 | ARG SONAR_SCANNER_MAVEN_PLUGIN_VERSION="3.9.1.2184" 10 | 11 | # ================================================= 12 | # Builder image (just for downloads / preparations) 13 | # ================================================= 14 | FROM docker.io/library/debian:stable-slim as builder 15 | RUN apt-get -y update && apt-get -y install curl unzip 16 | ARG MAVEN_VERSION 17 | ARG MAVEN_SHA512_CHECKSUM 18 | ARG SONAR_SCANNER_CLI_VERSION 19 | ARG SONAR_SCANNER_CLI_SHA512_CHECKSUM 20 | ARG SONAR_SCANNER_DOWNLOAD_URL="https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SONAR_SCANNER_CLI_VERSION}-linux.zip" 21 | RUN curl -s -L "${SONAR_SCANNER_DOWNLOAD_URL}" > "/tmp/sonar-scanner-cli-${SONAR_SCANNER_CLI_VERSION}-linux.zip" 22 | RUN echo "${SONAR_SCANNER_CLI_SHA512_CHECKSUM} /tmp/sonar-scanner-cli-${SONAR_SCANNER_CLI_VERSION}-linux.zip" | sha512sum -c 23 | RUN unzip -qq "/tmp/sonar-scanner-cli-${SONAR_SCANNER_CLI_VERSION}-linux.zip" -d "/data" 24 | RUN mv "/data/sonar-scanner-${SONAR_SCANNER_CLI_VERSION}-linux" "/data/sonar-scanner" 25 | RUN rm -f "/tmp/sonar-scanner-cli-${SONAR_SCANNER_CLI_VERSION}-linux.zip" 26 | 27 | ARG MAVEN_DOWNLOAD_URL="https://dlcdn.apache.org/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.zip" 28 | RUN curl -s -L "${MAVEN_DOWNLOAD_URL}" > "/tmp/apache-maven-${MAVEN_VERSION}-bin.zip" 29 | RUN echo "${MAVEN_SHA512_CHECKSUM} /tmp/apache-maven-${MAVEN_VERSION}-bin.zip" | sha512sum -c 30 | RUN unzip -qq "/tmp/apache-maven-${MAVEN_VERSION}-bin.zip" -d "/data" 31 | RUN mv "/data/apache-maven-${MAVEN_VERSION}" "/data/apache-maven" 32 | RUN rm -f "/tmp/apache-maven-${MAVEN_VERSION}-bin.zip" 33 | 34 | # =========== 35 | # Final image 36 | # =========== 37 | FROM docker.io/openjdk:17-slim 38 | 39 | ARG NODE_MAJOR=20 40 | ARG TYPESCRIPT_VERSION="5.0.4" 41 | 42 | # Install nodejs 43 | RUN apt-get -y update && apt-get -y install bash curl gawk git jq shellcheck ca-certificates gnupg && \ 44 | mkdir -p /etc/apt/keyrings && \ 45 | curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \ 46 | echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list && \ 47 | apt-get update && \ 48 | apt-get install nodejs -y && \ 49 | npm install -g typescript@${TYPESCRIPT_VERSION} 50 | 51 | RUN ln -sf "${JAVA_HOME}/bin/java" "/usr/local/bin/java" && \ 52 | ln -sf "${JAVA_HOME}/bin/javac" "/usr/local/bin/javac" && \ 53 | ln -sf "${JAVA_HOME}/bin/jar" "/usr/local/bin/jar" 54 | 55 | # TODO How should we do this with Slim? 56 | # https://github.com/concourse/concourse/issues/2042 57 | #RUN unlink $JAVA_HOME/lib/security/cacerts && \ 58 | #cp "/etc/ssl/certs/java/cacerts" "${JAVA_HOME}/lib/security/cacerts" 59 | 60 | COPY --from=builder "/data/sonar-scanner" "/opt/sonar-scanner" 61 | RUN rm -Rf "/opt/sonar-scanner/jre" \ 62 | && ln -sf "${JAVA_HOME}" "/opt/sonar-scanner/jre" \ 63 | && ln -sf "/opt/sonar-scanner/bin/sonar-scanner" "/usr/local/bin/sonar-scanner" \ 64 | && ln -sf "/opt/sonar-scanner/bin/sonar-scanner-debug" "/usr/local/bin/sonar-scanner-debug" 65 | COPY --from=builder "/data/apache-maven" "/opt/apache-maven" 66 | RUN ln -sf "/opt/apache-maven/bin/mvn" "/usr/local/bin/mvn" \ 67 | && ln -sf "/opt/apache-maven/bin/mvnDebug" "/usr/local/bin/mvnDebug" 68 | ENV M2_HOME="/opt/apache-maven" 69 | 70 | ARG SONAR_SCANNER_MAVEN_PLUGIN_VERSION 71 | RUN mvn -q org.apache.maven.plugins:maven-dependency-plugin:3.3.0:get \ 72 | -DrepoUrl="https://repo.maven.apache.org/maven2/" \ 73 | -Dartifact="org.sonarsource.scanner.maven:sonar-maven-plugin:${SONAR_SCANNER_MAVEN_PLUGIN_VERSION}:jar" 74 | 75 | ENV NODE_PATH="/usr/local/lib/node_modules" 76 | ENV PATH="/usr/local/bin:/usr/bin:/bin" 77 | 78 | LABEL maintainer="Benjamin P. Jung " \ 79 | version="${RESOURCE_VERSION}" \ 80 | maven.version="{MAVEN_VERSION}" \ 81 | sonar-scanner.cli.version="${SONAR_SCANNER_CLI_VERSION}" \ 82 | sonar-scanner.maven-plugin.version="${SONAR_SCANNER_MAVEN_PLUGIN_VERSION}" \ 83 | typescript.version=${TYPESCRIPT_VERSION} \ 84 | org.concourse-ci.target-version="6.6.0" \ 85 | org.concourse-ci.resource-id="sonarqube" \ 86 | org.concourse-ci.resource-name="SonarQube Static Code Analysis" \ 87 | org.concourse-ci.resource-homepage="https://github.com/cathive/concourse-sonarqube-resource" 88 | 89 | # org.opencontainers annotations / labels. 90 | # See https://github.com/opencontainers/image-spec/blob/main/annotations.md for further details. 91 | LABEL org.opencontainers.image.title="concourse-sonarqube-resource" 92 | LABEL org.opencontainers.image.description="Concourse CI resource to interact with SonarQube" 93 | LABEL org.opencontainers.image.source="https://github.com/cathive/concourse-sonarqube-resource" 94 | LABEL org.opencontainers.image.vendor="The Cat Hive Developers" 95 | LABEL org.opencontainers.image.licenses="LicenseRef-apache-2.0" 96 | LABEL org.opencontainers.image.version="${RESOURCE_VERSION}" 97 | 98 | COPY ./assets/* /opt/resource/ 99 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![CI](https://github.com/cathive/concourse-sonarqube-resource/actions/workflows/ci.yml/badge.svg)](https://github.com/cathive/concourse-sonarqube-resource/actions/workflows/ci.yml) 2 | 3 | # [SonarQube](https://sonarqube.org/) Resource for [Concourse CI](https://concourse-ci.org/) 4 | 5 | Performs SonarQube analyses and tracks the state of SonarQube [quality gates](https://docs.sonarqube.org/display/SONAR/Quality+Gates). 6 | 7 | This resource works with [SonarCloud](https://sonarcloud.io/) and self-hosted instances of SonarQube. 8 | 9 | If you want to implement a real quality gate in your build pipeline, you might want to also use the [concourse-sonarqube-qualitygate-task](https://github.com/cathive/concourse-sonarqube-qualitygate-task) which can be used to break a build if certain quality goals (as reported by SonarQube) are not reached. 10 | 11 | ## Requirements 12 | 13 | * A running SonarQube instance (this resource was tested on v6.5–v7.1, but it should 14 | work with every version of SonarQube ≥ v5.3) 15 | * The base URL of your SonarQube server has to be configured correctly! Otherwise 16 | the resource will be unable to fetch analysis results when invoking it's `in` 17 | action. (`sonar.core.serverBaseURL` in `conf/sonar.properties`) 18 | 19 | ## Installation 20 | 21 | Add a new resource type to your Concourse CI pipeline: 22 | 23 | ```yaml 24 | resource_types: 25 | - name: sonar-runner 26 | type: docker-image 27 | source: 28 | repository: cathive/concourse-sonarqube-resource 29 | tag: latest # For reproducible builds use a specific tag and don't rely on "latest". 30 | ``` 31 | 32 | ## Source Configuration 33 | 34 | * `host_url`: *Required.* The address of the SonarQube instance, 35 | e.g. "https://sonarcloud.io/" (when using SonarCloud). Must end with a slash. 36 | 37 | * `organization`: The organization to be used when submitting stuff to a sonarqube 38 | instance. This field is *required* when using SonarCloud to perform the analysis 39 | of your code. 40 | 41 | * `login`: The login or authentication token of a SonarQube user with Execute Analysis 42 | permission. Can be left out if SonarQube instance does not require any authentication. 43 | 44 | * `password`: The password that goes with the sonar.login username. This should be left blank if an 45 | authentication token is being used. 46 | 47 | * `maven_settings`: Maven settings to be used when performing SonarQube analysis. 48 | Only used if the scanner_type during the out phase has been set to / determined to use 49 | Maven. 50 | 51 | * `__debug`: This flag is used to debug any problems that might occur when using the resource 52 | itself. It enables extra debug output on the console and sets the `-x` flag during shell 53 | execution. It is usually not a good idea to set this flag to `true` in a production environment, 54 | because it might leak passwords and access key credentials to the console where it might 55 | be accessed by unauthorized / anonymous users. 56 | 57 | ## Behavior 58 | 59 | The resource implements all three actions (check, in and out). 60 | The analysis is triggered by the out action and check/in will be used to wait for 61 | the result of the analysis and pull in the project status. Tasks can use this 62 | information to break the build (if desired) if any of the criteria of the 63 | quality gate associated with a project are not met. 64 | 65 | ### out: Trigger SonarQube analysis 66 | 67 | #### Parameters 68 | 69 | * `project_path`: *Required* Path to the resource that shall be analyzed. 70 | If the path contains a file called "sonar-project.properties" it will be picked 71 | up during analysis. 72 | 73 | * `scanner_type`: Type of scanner to be used. Possible values are: 74 | * `auto` (default) Uses the maven-Scanner if a pom.xml is found in the directory 75 | specified by sources, cli otherwise. 76 | * `cli` Forces usage of the command line scanner, even if a Maven project object 77 | model (pom.xml) is found in the sources directory. 78 | * `maven` Forces usage of the Maven plugin to perform the scan. 79 | 80 | * `project_key`: Project key (default value is read from sonar-project.properties) 81 | 82 | * `project_key_file`: File to be used to read the Project key. 83 | When this option has been specified, it has precedence over the `project_key` parameter. 84 | 85 | * `project_name`: Project name (default value is read from sonar-project.properties) 86 | 87 | * `project_description`: Project description (default value is read from sonar-project.properties) 88 | 89 | * `project_version`: Project version (default value is read from sonar-project.properties) 90 | 91 | * `project_version_file`: File to be used to read the Project version. 92 | When this option has been specified, it has precedence over the `project_version` parameter. 93 | 94 | * `autodetect_branch_name`: Try to figure out the branch automatically. 95 | This works if the `project_path` contains recognized SCM metadata from a supported 96 | revision control system. (Currently: only Git is supported!) 97 | 98 | * `branch_name`: Name of the branch. Overrides `autodetect_branch_name` if it has been set. 99 | 100 | * `branch_name_file`: File to be used to read the branch name. 101 | When this option has been specified, it has precedence over the `branch_name` parameter. 102 | 103 | * `branch_target`: Name of the branch where you intend to merge your short-lived branch at the end of its life. 104 | If left blank, this defaults to the master branch. It can also be used while initializing a long-lived 105 | branch to sync the issues from a branch other than the Main Branch. 106 | (See [Branch Plugin documentation](https://docs.sonarqube.org/display/PLUG/Branch+Plugin) for further 107 | details) 108 | 109 | * `branch_target_file`: File to be used to read the branch target. 110 | When this option has been specified, it has precedence over the `branch_target` parameter. 111 | 112 | * `decorate_pr`: If set to `true` it will try to fetch the pull request id, the head branch name and the base branch name from 113 | the pull request resource. It will enable `sonar.pullrequest.key`, `sonar.pullrequest.branch` and `sonar.pullrequest.base` flags when performing your analysis. 114 | 115 | It works for: 116 | * `telia-oss/github-pr-resource` 117 | * `zarplata/concourse-git-bitbucket-pr-resource` 118 | * `jtarchie/github-pullrequest-resource` 119 | 120 | >_In order to use this feature you must be using `SonarCloud` or `SonarQube Developer` edition._ 121 | 122 | * `sources`: A list of paths to directories containing source files. 123 | 124 | * `tests`: A list of paths to directories containing source files. 125 | 126 | * `additional_sonar_scanner_opts`: Optional values to be passed in to the $SONAR_SCANNER_OPTS env variable. 127 | Can be used to provide parameters to Sonar before the scanner process starts. This is at the moment 128 | essentially necessary for HTTP proxy settings. 129 | 130 | * `additional_properties`: Optional object/dictionary that may contain any additional properties 131 | that one might want to pass when running the sonar-scanner. 132 | 133 | * `additional_properties_file`: Optional path to a file containing properties 134 | that should be passed to the sonar-scanner. 135 | 136 | * `maven_settings_file`: Path to a Maven settings file that shall be used. 137 | Only used if the scanner_type during has been set to / determined to use Maven. 138 | If the resource itself has a maven_settings configuration, this key will override 139 | it's value. 140 | 141 | * `sonar_maven_plugin_version`: sonar-maven-plugin version (default is empty and using the latest version) 142 | 143 | #### Wildcards Support 144 | 145 | Support convert wildcards to comma-separated paths. 146 | 147 | * `sources` 148 | * `tests` 149 | * Any key with the suffix `.reportPaths` in `additional_properties` 150 | 151 | ### in: Fetch result of SonarQube analysis 152 | 153 | The action will place two JSON files into the resource's folder which are fetched from 154 | the SonarQube Web API: 155 | 156 | #### Parameters 157 | 158 | * `quality_gate`: *Optional* *JSON* Enable quality_gate checker and control `get` step success/failure. 159 | * `ignore_all_warn`: *bool* Ignore all `WARN` metrics and let `get` step success 160 | * `ignore_all_error`: *bool* Ignore all `ERROR` metrics and let `get` step success 161 | * `ignore_warns`: *array* A list of metric keys for `WARN` metric to ignore while quality_gate checking. 162 | * `ignore_errors`: *array* A list of metric keys for `ERROR` metric to ignore while quality_gate checking. 163 | 164 | Note: for `ignore_warns`/`ignore_errors`, possible value could be found through 165 | * `https:///quality_gates/show/` 166 | * `https:///api/qualitygates/show?id=` 167 | 168 | ### Outputs 169 | 170 | * qualitygate_project_status.json 171 | Quality gate status of the compute engine task that was triggered by the resource 172 | during the out action. 173 | Format: https://next.sonarqube.com/sonarqube/web_api/api/qualitygates/project_status 174 | * ce_task_info.json 175 | Information about the compute engine task that performed the analysis. 176 | Format: https://next.sonarqube.com/sonarqube/web_api/api/ce/task 177 | 178 | ## Full example 179 | 180 | The following example pipeline shows how to use the resource to break the build if 181 | a project doesn't meet the requirements of the associated quality gate. 182 | 183 | ```yaml 184 | resource_types: 185 | 186 | - name: sonar-runner 187 | type: docker-image 188 | source: 189 | repository: cathive/concourse-sonarqube-resource 190 | tag: latest # For reproducible builds use a specific tag and don't rely on "latest". 191 | 192 | resources: 193 | 194 | - name: sources 195 | type: git 196 | source: 197 | uri: https://github.com/example/example.git 198 | 199 | - name: artifact 200 | type: s3 201 | # ... configuration omitted 202 | 203 | - name: code-analysis 204 | type: sonar-runner 205 | source: 206 | host_url: https://sonarqube.example.com/ 207 | login: ((sonarqube-auth-token)) 208 | 209 | jobs: 210 | 211 | # The build job performs fetches stuff from the "sources" resource 212 | # and executes a task that builds and tests everything. Once compilation, 213 | # test execution and has been performed, we copy the whole 214 | # working directory into the output folder "sonarqube-analysis-input" 215 | # and push the package that has been created by the "build" task to the 216 | # artifact resource and utilize the sonarqube-resource to perform static 217 | # code analysis. 218 | - name: build-and-analyze 219 | plan: 220 | - get: sources 221 | trigger: true 222 | - task: build 223 | config: 224 | platform: linux 225 | image_resource: 226 | type: docker-image 227 | source: 228 | repository: debian 229 | tag: 'jessie' 230 | inputs: 231 | - name: sources 232 | outputs: 233 | # Hint: The sonar-runner needs more than just the 234 | # sources to perform a full analysis. Line coverage reports, unit test reports, 235 | # Java class files and mutation test results should also be present. 236 | # Therefore, you'll have to make sure that your build script provides the sources 237 | # and the compilation/test results in your Concourse CI build plan. 238 | # (And that is the reason, why we need the following output) 239 | - name: sonarqube-analysis-input 240 | run: 241 | path: build.sh 242 | dir: sources 243 | - in_parallel: 244 | - put: code-analysis 245 | params: 246 | project_path: sonarqube-analysis-input 247 | project_key: com.example.my_project 248 | sources: ["."] 249 | tests: ["."] 250 | additional_properties: 251 | # Will be passed as "-Dsonar.javascript.lcov.reportPaths="coverage/lcov.info" to the scanner. 252 | sonar.javascript.lcov.reportPaths: coverage/lcov.info 253 | get_params: 254 | quality_gate: 255 | ignore_errors: ['new_coverage', 'violations'] 256 | ignore_warns: ['new_duplicated_lines_density', 'violations'] 257 | - put: artifact 258 | 259 | # The qualitygate task breaks the build if the analysis result from SonarQube 260 | # indicates that any of our quality metrics have not been met. 261 | - name: qualitygate 262 | plan: 263 | - in_parallel: 264 | - get: artifact 265 | passed: 266 | - build-and-analyze 267 | - get: code-analysis 268 | passed: 269 | - build-and-analyze 270 | trigger: true 271 | - task: check-sonarqube-quality-gate 272 | config: 273 | platform: linux 274 | image_resource: 275 | type: docker-image 276 | source: 277 | repository: cathive/concourse-sonarqube-qualitygate-task 278 | tag: latest # Use one of the versioned tags for reproducible builds! 279 | inputs: 280 | - name: code-analysis 281 | run: 282 | path: /sonarqube-qualitygate-check 283 | dir: code-analysis 284 | 285 | # We deploy only artifacts that have made it through our quality gate! 286 | - name: deploy 287 | plan: 288 | - get: artifact 289 | passed: 290 | - qualitygate 291 | 292 | ``` 293 | -------------------------------------------------------------------------------- /assets/check: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | exec 3>&1 # make stdout available as fd 3 for the result 6 | exec 1>&2 # redirect all output to stderr for logging 7 | 8 | root=$(dirname "${0}" | while read -r a; do cd "${a}" && pwd && break; done) 9 | export root 10 | # shellcheck source=./common.sh 11 | source "${root}/common.sh" 12 | 13 | payload=$(mktemp "${TMPDIR}/sonarqube-resource-check.XXXXXX") 14 | cat > "${payload}" <&0 15 | 16 | DEBUG="$(jq -r '.source.__debug // "false"' < "${payload}")" 17 | enable_debugging "${DEBUG}" 18 | 19 | latest_version=$(jq -r '.version.ce_task_id // ""' < "${payload}") 20 | if [[ -n "${latest_version}" ]]; then 21 | jq -n "[ 22 | { ce_task_id: \"${latest_version}\"} 23 | ]" >&3 24 | else 25 | jq -n "[]" >&3 26 | fi 27 | -------------------------------------------------------------------------------- /assets/common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function error() { 4 | JOB="${0}" # job name 5 | LASTLINE="${1}" # line of error occurrence 6 | LASTERR="${2}" # error code 7 | echo "ERROR in ${JOB} : line ${LASTLINE} with exit code ${LASTERR}" >&2 8 | exit 1 9 | } 10 | trap 'error ${LINENO} ${?}' ERR 11 | 12 | TMPDIR="${TMPDIR:-/tmp}" 13 | 14 | function enable_debugging { 15 | if [[ "${1}" == "true" ]]; then 16 | echo "WARNING: Enabling debug output." 17 | echo " You should *not* set this value in a production environment, because" 18 | echo " it might leak sensitive information (such as passwords or access key" 19 | echo " credentials to the console's output which might be accessible by un-" 20 | echo " authorized / anonymous users." 21 | set -x 22 | fi 23 | } 24 | 25 | # Adds a trailing slash to the specified base URL if it has not 26 | # already been added before and returns the sanitized URL. 27 | # $1 URL to be sanitized 28 | function sanitize_base_url { 29 | url="${1}" 30 | if [[ "${url:${#url}-1:1}" != "/" ]]; then 31 | url+="/" 32 | fi 33 | echo "${url}" 34 | } 35 | 36 | # Reads a properties file and returns a list of variable assignments 37 | # that can be used to re-use these properties in a shell scripting environment. 38 | function read_properties { 39 | if [[ "$2" == "shell" ]]; then 40 | awk -f "${root:?}/readproperties.awk" -v sv=1 < "${1}" 41 | else 42 | awk -f "${root:?}/readproperties.awk" -v sv=0 < "${1}" 43 | fi 44 | } 45 | 46 | # Checks on a compute engine task 47 | # Params: 48 | # $1 - Username or Access token, a colon and optional the password, e.g. "user:password" (required) 49 | # Pass an empty string to access SonarQube anonymously. 50 | # $2 - SonarQube URL. Must end with a slash (required) 51 | # $3 - CE Task ID (required) 52 | function sq_ce_task { 53 | flags="-s -L" 54 | if [[ -n "${1}" ]] && [[ "${1}" != "" ]]; then 55 | flags+=" -u ${1}" 56 | fi 57 | url="${2}api/ce/task?id=${3}&additionalField=stacktrace,scannerContext" 58 | cmd="curl ${flags} ${url}" 59 | ${cmd} 60 | } 61 | 62 | # Checks the quality gate status of a project 63 | # Params: 64 | # $1 - Username or Access token, a colon and optional the password, e.g. "user:password" (required) 65 | # Pass an empty string to access SonarQube anonymously. 66 | # $2 - SonarQube URL. Must end with a slash (required) 67 | # $3 - Analysis ID (required) 68 | function sq_qualitygates_project_status { 69 | flags="-s -L" 70 | if [[ -n "${1}" ]] && [[ "${1}" != "" ]]; then 71 | flags+=" -u ${1}" 72 | fi 73 | url="${2}api/qualitygates/project_status?analysisId=${3}" 74 | cmd="curl ${flags} ${url}" 75 | ${cmd} 76 | } 77 | 78 | # Retrieves the version of a SonarQube server instance 79 | # If the version cannot be determined due to an error, the string 80 | # "" will be echoed. 81 | # Params: 82 | # $1 - Username or Access token, a colon and optional the password, e.g. "user:password" (required) 83 | # Pass an empty string to access SonarQube anonymously. 84 | # $2 - SonarQube URL. Must end with a slash (required) 85 | function sq_server_version { 86 | flags="-s -L" 87 | if [[ -n "${1}" ]] && [[ "${1}" != "" ]]; then 88 | flags+=" -u ${1}" 89 | fi 90 | url="${2}api/server/version" 91 | cmd="curl ${flags} ${url}" 92 | ${cmd} 93 | } 94 | 95 | # Checking if error/warn conditions already ignored in params 96 | # $1 ignore_items: ignored conditions 97 | # $2 qg_status_path: quality_gate status file 98 | # $3 condition_status: WARN or ERROR 99 | function check_passed { 100 | local ignore_items="$1" 101 | local qg_status_path="$2" 102 | local condition_status="$3" 103 | 104 | echo "Checking for $condition_status..." 105 | 106 | jq --arg stat "$condition_status" -rc \ 107 | '.projectStatus.conditions[] | select(.status | contains($stat))' < "${qg_status_path}" |\ 108 | while IFS='' read -r item; do 109 | status=$(echo "$item" | jq .status) 110 | metricKey=$(echo "$item" | jq .metricKey) 111 | if [[ $ignore_items != *"${metricKey}"* ]]; then 112 | echo "$metricKey in $status and don't exist in 'ignore_errors'." 113 | exit 1 114 | fi 115 | done 116 | } 117 | 118 | # Parse and check if this task failed by configuration 119 | # $1 qg_settings: user configuration about quality_gate 120 | # $2 qg_status_path: quality_gate status file 121 | function parse_quality_gates { 122 | local qg_settings="$1" 123 | local qg_status_path="$2" 124 | 125 | echo "Start parseing quality_gates..." 126 | project_status=$(jq -r '.projectStatus.status // ""' < "$qg_status_path") 127 | if [[ "$project_status" == "OK" ]]; then 128 | return 0 129 | fi 130 | 131 | if [[ "$project_status" == "WARN" ]]; then 132 | ignore_all_warn=$(echo "${qg_settings}" | jq -r '.ignore_all_warn // false') 133 | if [[ "$ignore_all_warn" == "true" ]]; then 134 | return 0 135 | fi 136 | ignore_warns=$(echo "${qg_settings}" | jq -r '.ignore_warns // ""') 137 | if [[ $(echo "${ignore_warns}" | jq '. | length') -gt 0 ]]; then 138 | check_passed "${ignore_warns}" "${qg_status_path}" "WARN" 139 | else 140 | printf "quality gate check failed. \n==========" 141 | jq -r "." < "$qg_status_path" 142 | printf "\n==========" 143 | exit 1 144 | fi 145 | fi 146 | 147 | if [[ "$project_status" == "ERROR" ]]; then 148 | ignore_all_error=$(echo "${qg_settings}" | jq -r '.ignore_all_error // false') 149 | if [[ "$ignore_all_error" == true || "$ignore_all_error" == "true" ]]; then 150 | return 0 151 | fi 152 | ignore_errors=$(echo "${qg_settings}" | jq -r '.ignore_errors // ""') 153 | if [[ $(echo "${ignore_errors}" | jq '. | length') -gt 0 ]]; then 154 | check_passed "${ignore_errors}" "${qg_status_path}" "ERROR" 155 | else 156 | printf "quality gate check failed.\n==========" 157 | jq -r "." < "$qg_status_path" 158 | printf "\n==========" 159 | exit 1 160 | fi 161 | fi 162 | } 163 | 164 | # return "0" if $1 contains $2 165 | # return "1" if $1 not contains $2 166 | function contains { 167 | [[ $1 =~ (^|[[:space:]])$2($|[[:space:]]) ]] && echo "0" || echo "1" 168 | } 169 | 170 | # return "0" if $1 is exist 171 | # return "1" if $1 not exist 172 | function wildcard_exists { 173 | local wildcards="$1" 174 | 175 | for f in $wildcards; do 176 | ## Check if the glob gets expanded to existing files. 177 | ## If not, f here will be exactly the pattern above 178 | ## and the exists test will evaluate to false. 179 | [ -e "$f" ] && echo "0" || echo "1" 180 | ## This is all we needed to know, so we can break after the first iteration 181 | break 182 | done 183 | } 184 | 185 | # Convert wildcards to comma-separated paths 186 | # $1 param_key: sonar parameter key 187 | # $2 wildcards: potential wildcard string 188 | # $3 project_path: params.project_path 189 | function wildcard_convert { 190 | SUPPORT_PARAMS=( 191 | sonar.sources 192 | sonar.tests 193 | ) 194 | local param_key="$1" 195 | local wildcards="$2" 196 | local project_path="$3" 197 | 198 | # check if $wildcards is a wildcard string 199 | if [ "$wildcards" == "${wildcards//[\[\]|.? +*]/}" ] ; then 200 | echo "$wildcards"; 201 | return 0; 202 | fi 203 | 204 | # check if request $param_key is supported 205 | if [[ "$param_key" != *".reportPaths" ]]; then 206 | if [ "$( contains "${SUPPORT_PARAMS[*]}" "$param_key" )" -ne "0" ]; then 207 | echo "$wildcards"; 208 | return 0; 209 | fi 210 | fi 211 | 212 | convert_res="" 213 | IFS=','; 214 | for wildcard in $wildcards; do 215 | for w in $wildcard; do 216 | if [ "$( wildcard_exists "$w" )" -ne "0" ]; then 217 | # Warning about path not exist, instead of fail/block the build. 218 | echo "Warning: path [$w] does not exist under $(pwd)" >&2 219 | fi 220 | # remove prefix "${project_path}/" since following step contains "cd $project_path/" 221 | convert_res+="${w/#${project_path}\/}," 222 | done 223 | done; unset IFS; 224 | 225 | echo "${convert_res/%,/}" 226 | } 227 | 228 | 229 | # Generate metadata from conditions 230 | # $1 qg_status_path: quality_gate status file 231 | function metadata_from_conditions { 232 | local qg_status_path="$1" 233 | 234 | conditions=$(jq -r ".projectStatus.conditions // []" < "$qg_status_path") 235 | echo "$conditions" | jq -r 'map({"name": .metricKey, "value": .actualValue})' 236 | } 237 | -------------------------------------------------------------------------------- /assets/in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | exec 3>&1 # make stdout available as fd 3 for the result 6 | exec 1>&2 # redirect all output to stderr for logging 7 | 8 | root=$(dirname "${0}" | while read -r a; do cd "${a}" && pwd && break; done) 9 | export root 10 | # shellcheck source=./common.sh 11 | source "${root}/common.sh" 12 | 13 | dest="${1}" 14 | 15 | if [[ -z "${dest}" ]]; then 16 | echo "usage: ${0} " 17 | exit 1 18 | fi 19 | if [[ ! -d "${dest}" ]]; then 20 | echo "error: Destination path (${dest}) does not exist or is not a directory." 21 | exit 1 22 | fi 23 | 24 | payload=$(mktemp "${TMPDIR}/sonarqube-resource-out.XXXXXX") 25 | cat > "${payload}" <&0 26 | 27 | DEBUG="$(jq -r '.source.__debug // "false"' < "${payload}")" 28 | enable_debugging "${DEBUG}" 29 | 30 | sonar_host_url=$(jq -r '.source.host_url // ""' < "${payload}") 31 | if [[ -z "${sonar_host_url}" ]]; then 32 | echo "host_url param has not been specified." 33 | exit 1 34 | fi 35 | sonar_host_url=$(sanitize_base_url "${sonar_host_url}") 36 | 37 | sonar_login=$(jq -r '.source.login // ""' < "${payload}") 38 | 39 | sonar_password=$(jq -r '.source.password // ""' < "${payload}") 40 | 41 | if [[ -n "${sonar_login}" ]] && [[ "${sonar_login}" != "" ]]; then 42 | sonar_token="${sonar_login}:" 43 | if [[ -n "${sonar_password}" ]] && [[ "${sonar_password}" != "" ]]; then 44 | sonar_token+="${sonar_password}" 45 | fi 46 | fi 47 | 48 | ce_task_id=$(jq -r '.version.ce_task_id // ""' < "${payload}") 49 | if [[ -z "${ce_task_id}" ]]; then 50 | echo "version to fetch cannot be determined: ce_task_id not set?" 51 | exit 1 52 | fi 53 | 54 | cd "${dest}" 55 | 56 | ce_task_info="./ce_task.json" 57 | ce_error="./ce_error" 58 | ce_task_status="PENDING" 59 | ce_task_error="" 60 | attempt=0 61 | max_attempts=2 62 | 63 | until [[ "${ce_task_status}" != "PENDING" ]] && [[ "${ce_task_status}" != "IN_PROGRESS" ]] && [[ -n "${ce_task_status}" ]]; do 64 | attempt=$(( attempt + 1 )) 65 | set +e 66 | sq_ce_task "${sonar_token}" "${sonar_host_url}" "${ce_task_id}" > "${ce_task_info}" 2>"${ce_error}" || { ce_task_error=$(<"${ce_error}"); } 67 | set -e 68 | ce_task_status=$(jq -r '.task.status // ""' < "${ce_task_info}") 69 | if [[ ${attempt} -gt ${max_attempts} ]] && [[ -z "${ce_task_status}" ]] ; then 70 | jq -n "{ 71 | version: { ce_task_id: \"${ce_task_id}\"}, 72 | metadata: [ 73 | { name: \"ce_task_status\", value: \"error: ${ce_task_error}\" } 74 | ] 75 | }" >&3 76 | exit 1 77 | fi 78 | if [[ "${ce_task_status}" != "PENDING" ]] && [[ "${ce_task_status}" != "IN_PROGRESS" ]]; then 79 | echo "Waiting for compute engine result (sleep: 5s)..." 80 | sleep 5 # Poll SonarQube compute engine task every 5 seconds. 81 | fi 82 | done 83 | 84 | analysis_id="" 85 | if [[ "${ce_task_status}" == "SUCCESS" ]]; then 86 | analysis_id=$(jq -r '.task.analysisId // ""' < "${ce_task_info}") 87 | if [[ -z "${analysis_id}" ]]; then 88 | echo "error: No analysis ID could be fetched from compute engine task result" 89 | exit 1 90 | fi 91 | fi 92 | 93 | project_status_file="./qualitygate_project_status.json" 94 | sq_qualitygates_project_status "${sonar_token}" "${sonar_host_url}" "${analysis_id}" > "${project_status_file}" 95 | 96 | quality_gate=$(jq -r '.params.quality_gate // ""' < "${payload}") 97 | if [[ -n "${quality_gate}" ]]; then 98 | parse_quality_gates "${quality_gate}" "${project_status_file}" 99 | fi 100 | 101 | metadata=$(metadata_from_conditions $project_status_file) 102 | project_status=$(jq -r '.projectStatus.status // ""' < "${project_status_file}") 103 | 104 | 105 | 106 | jq -n "{ 107 | version: { ce_task_id: \"${ce_task_id}\"}, 108 | metadata: [ 109 | { name: \"ce_task_status\", value: \"${ce_task_status}\" }, 110 | { name: \"project_status\", value: \"${project_status}\" } 111 | ] 112 | }" | jq --argjson m "$metadata" -r '.metadata += $m' >&3 113 | -------------------------------------------------------------------------------- /assets/out: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | exec 3>&1 # make stdout available as fd 3 for the result 6 | exec 1>&2 # redirect all output to stderr for logging 7 | 8 | # enable globstar to support wildcard conversion 9 | shopt -s globstar 10 | 11 | root=$(dirname "${0}" | while read -r a; do cd "${a}" && pwd && break; done) 12 | export root 13 | # shellcheck source=./common.sh 14 | source "${root}/common.sh" 15 | 16 | source="${1}" 17 | 18 | if [[ -z "${source}" ]]; then 19 | echo "usage: $0 " 20 | exit 1 21 | fi 22 | if [[ ! -d "${source}" ]]; then 23 | echo "error: Source path (${source}) does not exist or is not a directory." 24 | exit 1 25 | fi 26 | 27 | cd "${source}" 28 | 29 | payload=$(mktemp "${TMPDIR}/sonarqube-resource-out.XXXXXX") 30 | cat > "${payload}" <&0 31 | 32 | DEBUG="$(jq -r '.source.__debug // "false"' < "${payload}")" 33 | enable_debugging "${DEBUG}" 34 | 35 | echo "Preparing SonarQube scanner..." 36 | 37 | scanner_opts="" 38 | 39 | project_path=$source/$(jq -r '.params.project_path // ""' < "${payload}") 40 | if [[ -z "${project_path}" ]]; then 41 | echo "error: params.project_path has not been specified." 42 | exit 1 43 | fi 44 | if [[ ! -d "${project_path}" ]]; then 45 | echo "error: Project path (${project_path}) not found or not a directory." 46 | exit 1 47 | fi 48 | 49 | cd "${project_path}" 50 | 51 | sonar_host_url=$(jq -r '.source.host_url // ""' < "${payload}") 52 | if [[ -z "${sonar_host_url}" ]]; then 53 | echo "error: source.host_url has not been specified." 54 | exit 1 55 | fi 56 | sonar_host_url=$(sanitize_base_url "${sonar_host_url}") 57 | scanner_opts+=" -Dsonar.host.url=${sonar_host_url}" 58 | 59 | 60 | sonar_organization=$(jq -r '.source.organization // ""' < "${payload}") 61 | if [[ -n "${sonar_organization}" ]]; then 62 | scanner_opts+=" -Dsonar.organization=\"${sonar_organization}\"" 63 | fi 64 | 65 | sonar_login=$(jq -r '.source.login // ""' < "${payload}") 66 | if [[ -n "${sonar_login}" ]]; then 67 | scanner_opts+=" -Dsonar.login=\"${sonar_login}\"" 68 | fi 69 | 70 | sonar_password=$(jq -r '.source.password // ""' < "${payload}") 71 | if [[ -n "${sonar_password}" ]]; then 72 | scanner_opts+=" -Dsonar.password=\"${sonar_password}\"" 73 | fi 74 | 75 | # Try to determine Maven settings configuration. 76 | # If they have been defined inline, they take precedence over a possibly specified 77 | # maven settings file. 78 | maven_settings=$(jq -r '.source.maven_settings // ""' < "${payload}") 79 | if [[ -n "${maven_settings}" ]]; then 80 | maven_settings_file=$(mktemp "${TMPDIR}/sonarqube-resource-maven-settings.xml.XXXXXX") 81 | echo "${maven_settings}" > "${maven_settings_file}" 82 | unset maven_settings 83 | else 84 | maven_settings_file=$(jq -r '.params.maven_settings_file // ""' < "${payload}") 85 | if [[ -n "${maven_settings}" ]]; then 86 | maven_settings_file="$(realpath "${maven_settings_file}")" 87 | fi 88 | fi 89 | 90 | if [[ -n "${maven_settings_file}" ]]; then 91 | if [[ ! -f "${maven_settings_file}" ]]; then 92 | echo "error: Maven settings file not found: \"${maven_settings_file}\"." 93 | exit 1 94 | else 95 | echo "Using Maven settings file: \"${maven_settings_file}\"..." 96 | scanner_opts+=" -s \"${maven_settings_file}\"" 97 | fi 98 | fi 99 | 100 | sonar_project_key=$(jq -r '.params.project_key // ""' < "${payload}") 101 | if [[ -n "${sonar_project_key}" ]]; then 102 | scanner_opts+=" -Dsonar.projectKey=\"${sonar_project_key}\"" 103 | fi 104 | 105 | sonar_project_key_file=$(jq -r '.params.project_key_file // ""' < "${payload}") 106 | if [[ -n "${sonar_project_key_file}" ]]; then 107 | if [[ ! -f "${sonar_project_key_file}" ]]; then 108 | echo "error: Project key file not found: ${sonar_project_key_file}" 109 | exit 1 110 | else 111 | sonar_project_key=$(cat "${sonar_project_key_file}") 112 | scanner_opts+=" -Dsonar.projectKey=\"${sonar_project_key}\"" 113 | fi 114 | fi 115 | 116 | sonar_project_name=$(jq -r '.params.project_name // ""' < "${payload}") 117 | if [[ -n "${sonar_project_name}" ]]; then 118 | scanner_opts+=" -Dsonar.projectName=\"${sonar_project_name}\"" 119 | fi 120 | 121 | sonar_project_description=$(jq -r '.params.project_description // ""' < "${payload}") 122 | if [[ -n "${sonar_project_description}" ]]; then 123 | scanner_opts+=" -Dsonar.projectDescription=\"${sonar_project_description}\"" 124 | fi 125 | 126 | sonar_project_version=$(jq -r '.params.project_version // ""' < "${payload}") 127 | if [[ -n "${sonar_project_version}" ]]; then 128 | scanner_opts+=" -Dsonar.projectVersion=\"${sonar_project_version}\"" 129 | fi 130 | 131 | sonar_project_version_file=$(jq -r '.params.project_version_file // ""' < "${payload}") 132 | if [[ -n "${sonar_project_version_file}" ]]; then 133 | if [[ ! -f "${sonar_project_version_file}" ]]; then 134 | echo "error: Version file not found: ${sonar_project_version_file}" 135 | exit 1 136 | else 137 | sonar_project_version=$(cat "${sonar_project_version_file}") 138 | scanner_opts+=" -Dsonar.projectVersion=\"${sonar_project_version}\"" 139 | fi 140 | fi 141 | 142 | sonar_branch_name_file=$(jq -r '.params.branch_name_file // ""' < "${payload}") 143 | if [[ -n "${sonar_branch_name_file}" ]]; then 144 | if [[ ! -f "${sonar_branch_name_file}" ]]; then 145 | echo "error: Branch name file not found: ${sonar_branch_name_file}" 146 | exit 1 147 | else 148 | sonar_branch_name=$(cat "${sonar_branch_name_file}") 149 | fi 150 | else 151 | # branch name file has NOT been specified, we'll check if branch name has been set. 152 | sonar_branch_name=$(jq -r '.params.branch_name // ""' < "${payload}") 153 | if [[ -z "${sonar_branch_name}" ]]; then 154 | # If the branch name has NOT been specified, we'll check if autodetect_branch_name 155 | # has been set to true and try to figure out the branch by using installed 156 | # SCM tools. 157 | autodetect_branch_name=$(jq -r '.params.autodetect_branch_name // "false"' < "${payload}") 158 | if [[ "${autodetect_branch_name}" == "true" ]]; then 159 | echo "Trying to detect branch name automatically..." 160 | if [[ -d "${project_path}/.git" ]]; then 161 | sonar_branch_name=$(git --git-dir="${project_path}/.git" name-rev --name-only HEAD) 162 | fi 163 | echo "Auto-detected branch name: \"${sonar_branch_name:-}\"" 164 | fi 165 | fi 166 | fi 167 | 168 | 169 | # So... if the branch name has been either specified manually or we have been able 170 | # to figure it out automatically using our SCM tools, we can pass sonar.branch.name 171 | # to the sonar-scanner. Yay!! 172 | if [[ -n "${sonar_branch_name}" ]]; then 173 | scanner_opts+=" -Dsonar.branch.name=\"${sonar_branch_name}\"" 174 | fi 175 | 176 | sonar_branch_target=$(jq -r '.params.branch_target // ""' < "${payload}") 177 | if [[ -n "${sonar_branch_target}" ]]; then 178 | scanner_opts+=" -Dsonar.branch.target=\"${sonar_branch_target}\"" 179 | fi 180 | 181 | sonar_branch_target_file=$(jq -r '.params.branch_target_file // ""' < "${payload}") 182 | if [[ -n "${sonar_branch_target_file}" ]]; then 183 | if [[ ! -f "${sonar_branch_target_file}" ]]; then 184 | echo "error: Branch target file not found: ${sonar_branch_target_file}" 185 | exit 1 186 | else 187 | sonar_branch_target=$(cat "${sonar_branch_target_file}") 188 | scanner_opts+=" -Dsonar.branch.target=\"${sonar_branch_target}\"" 189 | fi 190 | fi 191 | 192 | decorate_pr=$(jq -r '.params.decorate_pr // ""' < "${payload}") 193 | if [[ -n "${decorate_pr}" ]]; then 194 | if [ -f "${project_path}/.git/resource/metadata.json" ]; then 195 | pr_id=$( jq -r '.pr' "${project_path}/.git/resource/version.json" ) 196 | branch_name=$( jq -r '.[] | select (.name == "head_name") | .value' "${project_path}/.git/resource/metadata.json" ) 197 | base_branch_name=$( jq -r '.[] | select (.name == "base_name") | .value' "${project_path}/.git/resource/metadata.json" ) 198 | elif [ -f "${project_path}/pull-request-info" ]; then 199 | pr_id=$( jq -r '.id' "${project_path}/pull-request-info" ) 200 | branch_name=$( jq -r '.feature_branch' "${project_path}/pull-request-info" ) 201 | base_branch_name=$( jq -r '.upstream_branch | ltrimstr("refs/heads/")' "${project_path}/pull-request-info" ) 202 | else 203 | pr_id=$(git config --get pullrequest.id) 204 | branch_name=$(git config --get pullrequest.branch) 205 | base_branch_name=$(git config --get pullrequest.basebranch) 206 | fi 207 | 208 | scanner_opts+=" -Dsonar.pullrequest.key=${pr_id} -Dsonar.pullrequest.branch="${branch_name}" -Dsonar.pullrequest.base=\"${base_branch_name}\"" 209 | echo "Decorating PR: ${pr_id} for branch ${branch_name}" 210 | fi 211 | 212 | sonar_sources=$(jq -r '.params.sources // [] | join(",")' < "${payload}") 213 | if [[ -n "${sonar_sources}" ]]; then 214 | if ! sonar_sources=$(wildcard_convert "sonar.sources" "${sonar_sources}" "${project_path}"); then 215 | echo "error: while setting params.sources, $sonar_sources." 216 | exit 1 217 | fi 218 | scanner_opts+=" -Dsonar.sources=\"${sonar_sources}\"" 219 | fi 220 | 221 | sonar_tests=$(jq -r '.params.tests // [] | join(",")' < "${payload}") 222 | if [[ -n "${sonar_tests}" ]]; then 223 | if ! sonar_tests=$(wildcard_convert "sonar.tests" "${sonar_tests}" "${project_path}"); then 224 | echo "error: while setting params.tests, $sonar_tests." 225 | exit 1 226 | fi 227 | scanner_opts+=" -Dsonar.tests=\"${sonar_tests}\"" 228 | fi 229 | 230 | scanner_type=$(jq -r '.params.scanner_type // ""' < "${payload}") 231 | 232 | 233 | # If no scanner type has been specified, we'll try to figure it out on our own. 234 | # (E.g. if pom.xml exists in the root directory, we are probalby dealing with a 235 | # Maven project,...) 236 | if [[ -z "${scanner_type}" ]] || [[ "${scanner_type}" == "auto" ]]; then 237 | if [[ -f "${project_path}/pom.xml" ]]; then 238 | scanner_type="maven" 239 | else 240 | scanner_type="cli" 241 | fi 242 | fi 243 | 244 | # We now build the command line for the sonar-scanner. 245 | # It depends upon the scanner type how the command line is being constructed. 246 | if [[ "${scanner_type}" == "cli" ]]; then 247 | scanner_bin="sonar-scanner" 248 | scanner_report_file="./.scannerwork/report-task.txt" 249 | elif [[ "${scanner_type}" == "maven" ]]; then 250 | mvn="mvn" 251 | if [[ "${DEBUG}" == "true" ]]; then 252 | mvn+=" -X" 253 | fi 254 | if [[ -n "${maven_settings_file}" ]]; then 255 | mvn+=" -s ${maven_settings_file}" 256 | fi 257 | 258 | scanner_bin="${mvn}" 259 | if [[ "${DEBUG}" != "true" ]]; then 260 | scanner_bin="${mvn} -q" 261 | fi 262 | 263 | sonar_maven_plugin_version=$(jq -r '.params.sonar_maven_plugin_version // ""' < "${payload}") 264 | if [[ -n "${sonar_maven_plugin_version}" ]]; then 265 | scanner_bin="${scanner_bin} org.sonarsource.scanner.maven:sonar-maven-plugin:${sonar_maven_plugin_version}:sonar" 266 | else 267 | # Default using the latest version of sonar-maven-plugin 268 | scanner_bin="${scanner_bin} sonar:sonar" 269 | fi 270 | 271 | # shellcheck disable=SC2016 272 | maven_project_build_directory=$(${mvn/-X} -q -f "${project_path}/pom.xml" -Dexec.executable="echo" -Dexec.args='${project.build.directory}' --non-recursive exec:exec) 273 | scanner_report_file="${maven_project_build_directory}/sonar/report-task.txt" 274 | unset maven_project_build_directory 275 | fi 276 | 277 | additional_sonar_scanner_opts=$(jq -r '.params.additional_sonar_scanner_opts // ""' < "${payload}") 278 | echo "additional_sonar_scanner_opts=${SONAR_SCANNER_OPTS}" 279 | if [[ -n "${additional_sonar_scanner_opts}" ]]; then 280 | export SONAR_SCANNER_OPTS="${SONAR_SCANNER_OPTS} ${additional_sonar_scanner_opts}" 281 | fi 282 | 283 | # If any additional properties have been specified, we'll just append them to the 284 | # command line. We don't check for any duplicates that might have been created due to 285 | # the fact that some "basic" properties might have specified a second time as 286 | # "additional" property. 287 | additional_properties=$(jq -r '.params.additional_properties // ""' < "${payload}") 288 | if [[ -n "${additional_properties}" ]]; then 289 | while read -r name value; do 290 | if ! value=$(wildcard_convert "${name}" "${value}" "${project_path}"); then 291 | echo "error: while setting additional_properties.$name, $value." 292 | exit 1 293 | fi 294 | prop_kv="$name=\"$value\"" 295 | scanner_opts+=" -D${prop_kv}" 296 | done < <(jq -r 'to_entries[] | "\(.key) \(.value)"' <<< "${additional_properties}") 297 | fi 298 | 299 | additional_properties_file=$(jq -r '.params.additional_properties_file // ""' < "${payload}") 300 | if [[ -n "${additional_properties_file}" ]]; then 301 | props=$(read_properties "${additional_properties_file}") 302 | while read -r p; do 303 | scanner_opts+=" -D${p}" 304 | done <<< "${props}" 305 | fi 306 | 307 | echo "Starting sonar-scanner (type: ${scanner_type})..." 308 | eval "${scanner_bin} ${scanner_opts}" 309 | 310 | echo "Reading SonarQube scanner report (${scanner_report_file})..." 311 | if [[ -f "${scanner_report_file}" ]]; then 312 | eval "$(read_properties "${scanner_report_file}" "shell")" 313 | if [[ -z "${serverVersion:-}" ]]; then 314 | # Older versions of SonarQube don't store the serverVersion in 315 | # report-task.txt. There is a REST API though, that can be used 316 | # to fetch the version. 317 | sonar_token="" 318 | if [[ -n "${sonar_login}" ]] && [[ "${sonar_login}" != "" ]]; then 319 | sonar_token="${sonar_login}" 320 | if [[ -n "${sonar_password}" ]] && [[ "${sonar_password}" != "" ]]; then 321 | sonar_token+=":${sonar_password}" 322 | fi 323 | fi 324 | serverVersion="$(sq_server_version "${sonar_token}" "${sonar_host_url}")" 325 | fi 326 | else 327 | echo "error: SonarQube report could not be located." 328 | exit 1 329 | fi 330 | 331 | jq -n "{ 332 | version: {ce_task_id: \"${ceTaskId:?}\"}, 333 | metadata: [ 334 | { name: \"project_key\", value: \"${projectKey:?}\" }, 335 | { name: \"server_url\", value: \"${serverUrl:?}\" }, 336 | { name: \"server_version\", value: \"${serverVersion:?}\" }, 337 | { name: \"dashboard_url\", value: \"${dashboardUrl:?}\" }, 338 | { name: \"ce_task_url\", value: \"${ceTaskUrl:?}\" }, 339 | { name: \"scanner_type\", value: \"${scanner_type}\" } 340 | ] 341 | }" >&3 342 | -------------------------------------------------------------------------------- /assets/readproperties.awk: -------------------------------------------------------------------------------- 1 | BEGIN { 2 | FS="="; 3 | #print "# BEGIN"; 4 | n=""; 5 | v=""; 6 | c=0; # Not a line continuation. 7 | } 8 | /^#/ { # The line is a comment. Breaks line continuation. 9 | c=0; 10 | next; 11 | } 12 | /\\$/ && (c==0) && (NF>=2) { # Name value pair with a line continuation... 13 | e=index($0,"="); 14 | n=substr($0,1,e-1); 15 | v=substr($0,e+1,length($0) - e - 1); # Trim off the backslash. 16 | c=1; # Line continuation mode. 17 | next; 18 | } 19 | /^[^\\]+\\$/ && (c==1) { # Line continuation. Accumulate the value. 20 | v= "" v substr($0,1,length($0)-1); 21 | next; 22 | } 23 | ((c==1) || (NF>=2)) && !/^[^\\]+\\$/ { # End of line continuation, or a single line name/value pair 24 | if (c==0) { # Single line name/value pair 25 | e=index($0,"="); 26 | n=substr($0,1,e-1); 27 | v=substr($0,e+1,length($0) - e); 28 | } else { # Line continuation mode - last line of the value. 29 | c=0; # Turn off line continuation mode. 30 | v= "" v $0; 31 | } 32 | # Make sure the name is a legal shell variable name 33 | if (sv==1) { 34 | gsub(/[^A-Za-z0-9_]/,"_",n); 35 | } 36 | # Remove newlines from the value. 37 | gsub(/[\n\r]/,"",v); 38 | print n "=\"" v "\""; 39 | n = ""; 40 | v = ""; 41 | } 42 | END { 43 | #print "# END"; 44 | } 45 | -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | sonar.host.url = https://sonarcloud.io/ 2 | sonar.sources = ./assets 3 | sonar.exclusions = 4 | sonar.sourceEncoding = UTF-8 5 | sonar.organization = cathive 6 | sonar.projectKey = concourse-sonarqube-resource 7 | sonar.projectName = Concourse CI SonarQube Resource 8 | sonar.projectDescription = A resource for Concourse CI that performs SonarQube analyses and reports the state of a project`s quality goals. 9 | sonar.projectVersion = 0.14.0 10 | sonar.links.homepage = https://github.com/cathive/concourse-sonarqube-resource 11 | sonar.links.issue = https://github.com/cathive/concourse-sonarqube-resource/issues 12 | sonar.links.ci = https://ci.cathive.com/ 13 | sonar.links.scm = https://github.com/cathive/concourse-sonarqube-resource.git 14 | sonar.links.scm_dev = ssh://git@github.com:cathive/concourse-sonarqube-resource.git 15 | sonar.scm.provider = git 16 | -------------------------------------------------------------------------------- /structure-test/tests.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: '2.0.0' 2 | 3 | metadataTest: 4 | env: 5 | - key: 'JAVA_HOME' 6 | value: '/usr/java/openjdk-11' 7 | - key: 'M2_HOME' 8 | value: '/opt/apache-maven' 9 | - key: 'NODE_PATH' 10 | value: '/usr/local/lib/node_modules' 11 | 12 | fileExistenceTests: 13 | - name: 'Java Runtime must be installed' 14 | path: '/usr/local/bin/java' 15 | shouldExist: true 16 | isExecutableBy: 'owner' 17 | - name: 'Maven must be installed' 18 | path: '/usr/local/bin/mvn' 19 | shouldExist: true 20 | isExecutableBy: 'owner' 21 | - name: 'TypeScript compiler must be installed' 22 | path: '/usr/local/bin/tsc' 23 | shouldExist: true 24 | isExecutableBy: 'owner' 25 | - name: '/opt/resource/check must exist' 26 | path: '/opt/resource/check' 27 | shouldExist: true 28 | isExecutableBy: 'owner' 29 | - name: '/opt/resource/in must exist' 30 | path: '/opt/resource/in' 31 | shouldExist: true 32 | isExecutableBy: 'owner' 33 | - name: '/opt/resource/out must exist' 34 | path: '/opt/resource/out' 35 | shouldExist: true 36 | isExecutableBy: 'owner' 37 | - name: 'sonar-scanner JRE must be fully functional' 38 | path: '/opt/sonar-scanner/jre/bin/java' 39 | shouldExist: true 40 | isExecutableBy: 'owner' 41 | 42 | 43 | commandTests: 44 | - name: '"java" executable works' 45 | command: 'java' 46 | args: 47 | - '-version' 48 | exitCode: 0 49 | - name: '"mvn" executable works' 50 | command: 'mvn' 51 | args: 52 | - '-version' 53 | exitCode: 0 54 | - name: '"tsc" executable works' 55 | command: 'tsc' 56 | args: 57 | - '-version' 58 | exitCode: 0 59 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Test script for my local machine... 4 | 5 | cat ./test/out_cli_project.json | ./assets/out ./test/workspace/ 6 | 7 | mvn -f ./test/workspace/maven_project/pom.xml clean package 8 | cat ./test/out_maven_project.json | ./assets/out ./test/workspace/ -------------------------------------------------------------------------------- /test/cli_projects.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | setup() { 4 | export PATH="${BATS_TEST_DIRNAME}/mocks:${PATH}" 5 | } 6 | 7 | @test "Valid CLI project" { 8 | 9 | # Variables 10 | WORKSPACE=$(mktemp -d "${BATS_TMPDIR}/test-project.XXXXXX") 11 | PROJECT_ROOT="${WORKSPACE}/cli_project" 12 | OUT_RESULT_EXPECTED="${BATS_TEST_DIRNAME}/workspace/cli_project/out_result.json" 13 | OUT_RESULT_FILE="${PROJECT_ROOT}/out_result.json" 14 | 15 | # Mock configuration 16 | export SONAR_SCANNER_REPORT_FILE_MOCK="${PROJECT_ROOT}/report-task.mock.txt" 17 | export SONAR_SCANNER_REPORT_FILE="${PROJECT_ROOT}/.scannerwork/report-task.txt" 18 | 19 | # Workspace preparation 20 | cp -a "${BATS_TEST_DIRNAME}/workspace/cli_project" "${WORKSPACE}/" 21 | mkdir -p "${PROJECT_ROOT}/.scannerwork" 22 | 23 | # Perform mock SonarQube analysis 24 | cat ./test/out_cli_project.json | ./assets/out "${WORKSPACE}" > "${OUT_RESULT_FILE}" 25 | eval $(awk -f "${BATS_TEST_DIRNAME}/../assets/readproperties.awk" < "${SONAR_SCANNER_REPORT_FILE}") 26 | 27 | version__ce_task_id_actual="$(jq -r '.version.ce_task_id' < "${OUT_RESULT_FILE}")" 28 | version__ce_task_id_expected="${ceTaskId}" 29 | [ "${version__ce_task_id_actual}" == "${version__ce_task_id_expected}" ] 30 | 31 | } 32 | -------------------------------------------------------------------------------- /test/mocks/qualitygates_project_status.json: -------------------------------------------------------------------------------- 1 | { 2 | "projectStatus": { 3 | "status": "ERROR", 4 | "ignoredConditions": false, 5 | "conditions": [ 6 | { 7 | "status": "ERROR", 8 | "metricKey": "new_coverage", 9 | "comparator": "LT", 10 | "periodIndex": 1, 11 | "errorThreshold": "85", 12 | "actualValue": "82.50562381034781" 13 | }, 14 | { 15 | "status": "ERROR", 16 | "metricKey": "new_blocker_violations", 17 | "comparator": "GT", 18 | "periodIndex": 1, 19 | "errorThreshold": "0", 20 | "actualValue": "14" 21 | }, 22 | { 23 | "status": "ERROR", 24 | "metricKey": "new_critical_violations", 25 | "comparator": "GT", 26 | "periodIndex": 1, 27 | "errorThreshold": "0", 28 | "actualValue": "1" 29 | }, 30 | { 31 | "status": "OK", 32 | "metricKey": "new_sqale_debt_ratio", 33 | "comparator": "GT", 34 | "periodIndex": 1, 35 | "errorThreshold": "5", 36 | "actualValue": "0.6562109862671661" 37 | }, 38 | { 39 | "status": "OK", 40 | "metricKey": "reopened_issues", 41 | "comparator": "GT", 42 | "periodIndex": 1, 43 | "actualValue": "0" 44 | }, 45 | { 46 | "status": "ERROR", 47 | "metricKey": "open_issues", 48 | "comparator": "GT", 49 | "periodIndex": 1, 50 | "actualValue": "17" 51 | }, 52 | { 53 | "status": "OK", 54 | "metricKey": "skipped_tests", 55 | "comparator": "GT", 56 | "periodIndex": 1, 57 | "actualValue": "0" 58 | } 59 | ], 60 | "periods": [ 61 | { 62 | "index": 1, 63 | "mode": "last_version", 64 | "date": "2000-04-27T00:45:23+0200", 65 | "parameter": "2015-12-07" 66 | } 67 | ] 68 | } 69 | } -------------------------------------------------------------------------------- /test/mocks/sonar-scanner: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | if [[ ! -f "${SONAR_SCANNER_REPORT_FILE_MOCK}" ]]; then 3 | echo "!! ERROR DURING INVOCATION OF sonar-scanner MOCK FUNCTION !!" 4 | echo "The variable SONAR_SCANNER_REPORT_FILE_MOCK points to a non-existent file location or" >&2 5 | echo "the file at the specified location cannot be read:" >&2 6 | echo "--> \"${SONAR_SCANNER_REPORT_FILE_MOCK}\"" >&2 7 | exit 1 8 | fi 9 | cat "${SONAR_SCANNER_REPORT_FILE_MOCK}" > "${SONAR_SCANNER_REPORT_FILE}" 10 | -------------------------------------------------------------------------------- /test/out_cli_project.json: -------------------------------------------------------------------------------- 1 | { 2 | "params": { 3 | "project_path": "cli_project", 4 | "project_key": "com.example.cli_project", 5 | "sources": [ 6 | "src1", 7 | "src2" 8 | ], 9 | "additional_properties": { 10 | "param.foo": "bar" 11 | } 12 | }, 13 | "source": { 14 | "host_url": "https://sonar.example.com/", 15 | "login": "$$ACCESS_TOKEN$$" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/out_maven_project.json: -------------------------------------------------------------------------------- 1 | { 2 | "params": { 3 | "project_path": "maven_project", 4 | "sonar_maven_plugin_version": "3.5.0.1254" 5 | }, 6 | "source": { 7 | "host_url": "https://sonar.example.com/", 8 | "login": "$$ACCESS_TOKEN$$" 9 | } 10 | } -------------------------------------------------------------------------------- /test/workspace/cli_project/report-task.mock.txt: -------------------------------------------------------------------------------- 1 | projectKey=project_key 2 | ceTaskId=12345678 3 | ceTaskUrl=http://sonar.local/task/TODO 4 | serverUrl=http://sonar.local/ 5 | serverVersion=7.0.0 6 | dashboardUrl=TODO 7 | -------------------------------------------------------------------------------- /test/workspace/cli_project/src1/test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /test/workspace/cli_project/src2/noop.ts: -------------------------------------------------------------------------------- 1 | export default function noop() { 2 | const x = 1 + 1; 3 | // And we do nothing at all... 4 | } 5 | -------------------------------------------------------------------------------- /test/workspace/maven_project/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ -------------------------------------------------------------------------------- /test/workspace/maven_project/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4.0.0 5 | Maven Test Project 6 | com.example 7 | maven_project 8 | 1.0.0-SNAPSHOT 9 | 10 | 1.8 11 | 1.8 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/workspace/maven_project/src/main/java/com/example/Main.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | public class Main { 4 | /** 5 | * @param argx Parameter with typo 6 | * @return 7 | * Actually nothing, but we want to test SonarQube. 8 | */ 9 | public static void main(String ... args) { 10 | // TODO Fix something. Let's see if SonarQube finds this marker. 11 | 12 | args = null; // Should trigger yet another warning. 13 | if (args != null) { 14 | System.out.println("Impossible!!!1"); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test_common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source assets/common.sh 4 | 5 | project_status="test/mocks/qualitygates_project_status.json" 6 | metadata=$(metadata_from_conditions $project_status) 7 | echo $metadata 8 | 9 | --------------------------------------------------------------------------------