====== Gradle SonarQube ====== * https://plugins.gradle.org/plugin/org.sonarqube * https://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner+for+Gradle ===== 주의 ===== ''sonarRunner'' 태스크를 실행하면 곧바로 ''${buildDir}/sonar'' 디렉토리를 삭제한 뒤 새로 생성한다. 따라서 이 이전 태스크(특히 ''test'')에서 ''${buildDir}/sonar'' 디렉토리 아래에 ''jacoco.exec'' 처럼 분석용 파일을 생성하게 하면 해당 파일이 삭제돼 버려 아무런 분석도 이뤄지지 않게 된다. ===== 기본 프라퍼티 ===== * ''checkstyle.xml'', ''pmd.xml'' 등은 ''프로젝트디렉토리/.sonar/*'' 에 두는 것 같음. * 최신 SonarQube는 더이상 JDBC를 통한 저장을 지원하지 않는 듯 하다. 따라서 ''sonar.jdbc.*'' 프라퍼티는 무시된다. buildscript { dependencies { classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.2" } } apply plugin: "org.sonarqube" sonarqube { properties { property "sonar.host.url", "http://localhost:8080" property "sonar.sources", "src" property "sonar.language", "java" // 분석을 Java로 제한 property "sonar.sourceEncoding", "UTF-8" property "sonar.exclusions", "**/*Test*.*, **/Q*.JAVA" property "sonar.test.inclusions", "**/*Test.groovy, **/*Test.java" property "sonar.coverage.exclusions", "**/*Test*.*, **/Q*.java" property "sonar.java.junit.reportPaths", "${buildDir}/test-results" property "sonar.jacoco.reportPaths", "${buildDir}/jacoco/jacoco.exec" } } * ''sonar.projectKey'' 는 프로젝트명:모듈명으로 자동지정된다. 명시적 지정도 가능하다. * ''sonar.working.directory'' 함부로 지정하지 말고 기본값 ''$project.buildDir/sonar''으로 둘 것. 여기서 지정된 워킹 디렉토리는 자동으로 sonarRunner 실행시 전체 삭제를 한다. * 원칙적으로 ''sonar.host.url''은 시스템 프라퍼티 ''-Dsonar.host.url=http://sonar.mycompany.com''로 지정가능. systemProp.sonar.host.url=http://localhost:9000 ===== 분석에서 특정 클래스 제외 ===== * ''sonar.exclusions'' 프라퍼티를 ''*,**,?'' wild card를 이용해 지정한다. 여러개가 필요하면 쉼표로 구분한다. sonarRunner { sonarProperties { property 'sonar.exclusions', 'com/xxx/**/*_.java,com/**/QMyEntity.java,....' } } * 이를 함수로 만들어 두고, 각 프로젝트에서 호출하도록 한다. def excludeFromSonar(List exclusions) { project.sonarRunner { sonarProperties { property 'sonar.exclusions', exclusions.join(",") } } } // 배열 기반 호출 excludeFromSonar(['com/xxx/**/*_.java', 'com/**/QMyEntity.java']) ===== jacoco ===== * [[gradle:jacoco|Gradle JaCoCo Plugin]]를 설정해서 테스트 실행시 코드 커버리지 정보를 파일로 남겨둬야, SonarRunner가 그것을 분석하여 Sonar 데이터베이스에 넣어줄 수 있다. * jacoco가 생성한 코드 커버리지 파일(예) ''jacoco.exec'')가 생성이 안되면 sonar 도 코드 커버리지 정보를 분석하지 않는다. * ''Incompatible version 1007'' 오류 : jacoco ''0.7.5''부터 바이너리 파일 포맷이 변경되었음. sonarqube도 그에 맞는 버전을 사용하지 않으면 오류가 발생한다. * jacoco 분석파일 경로는 ''sonar.jacoco.reportPath'' 프라퍼티로 지정한다. 기본값은 자동으로 [[gradle:jacoco|Gradle JaCoCo Plugin]] 플러그인에 지정한 파일이다. * 단, 이 분석파일이 ''sonar.working.directory'' 디렉토리 아래이면 안된다. 따라서 이 프라퍼티를 기본값으로 사용시에는 ''$project.buildDir/sonar''아래에 두면 안된다. ===== 명령행 옵션 ===== * ''-Dsonar.verbose=true'' 상세 로그 gradle sonarRunner -Dsonar.host.url=http://sonar.mycompany.com -Dsonar.jdbc.password=myPassword -Dsonar.verbose=true ===== Multiple Module ===== * 멀티 모듈 프로젝트의 경우 root project에만 ''apply plugin: "org.sonarqube"''를 하고 subproject 에는 지정하지 않는다. * root 프로젝트 설정에 sonarqube 공통 설정을 하고, 각각의 소스 디렉토리등에 대한 설정은 ''subprojects'' 블록에서 한다. * root의 공통 설정 sonarqube { properties { // sonar.host.url 등 프로젝트별로 다르지 않은 모든 설정들... property "sonar.sourceEncoding", "UTF-8" } } * 각 subprojects별 설정 sonarqube { properties { // 프로젝트별로 달라지는 설정들 property "sonar.sources", "src/main/java" property "sonar.junit.reportPaths", "${buildDir}/test-results" property "sonar.jacoco.reportPaths", "${buildDir}/jacoco/jacoco.exec" } } * 일부 subproject skip project(":project2") { sonarqube { skipProject = true } } ===== 오류 대응 ===== ==== File not found, Resource not found 대량 발생 ==== * SonarQube가 멀티 언어를 지원하는데, java 분석이 완료된 뒤에 groovy 분석을 진행하면서 **아마도** Java와 동일 jacoco 결과로 groovy 쪽 클래스를 찾기 때문으로 예상됨. * Groovy는 테스트 코드용([[java:spock|Spock]])이라서 ''sonar.language=java''로 지정하니 해결 되었음.