Gradle + Springboot + Jacoco offline模式+ SonarQube搭建

文章目录

    • 1.先新建一个常规web项目,有三个子模块:
    • 2.主要文件:gradle.properties,build.gradle,jacoco.gradle
      • gradle.properties文件:
      • build.gradle文件:
      • jacoco.gradle文件:
      • 运行命令和依赖的版本
        • 当前系统使用的是jacoco的offline离线模式,不使用online在线模式的原因如下
        • 整个系统使用的技术和版本
        • 扫描代码覆盖率
        • 构建+扫描
    • 3.Demo的Github地址

1.先新建一个常规web项目,有三个子模块:

Gradle + Springboot + Jacoco offline模式+ SonarQube搭建_第1张图片

2.主要文件:gradle.properties,build.gradle,jacoco.gradle

Gradle + Springboot + Jacoco offline模式+ SonarQube搭建_第2张图片

gradle.properties文件:

定义了一些全局变量,如项目版本,springboot版本,sonar的账号密码等一些内容。

springbootVersion=2.3.2.RELEASE
projectVersion=1.0-SNAPSHOT

#sonarQube 配置
systemProp.sonar.host.url=http://192.168.16.173:9000
systemProp.sonar.login=账号
systemProp.sonar.password=密码
sonar.pdf.username=上传pdf文件账号
sonar.pdf.password=上传pdf文件密码

build.gradle文件:

定义gradle的构建脚本内容,包含springboot,单元测试,jacoco插件,sonar插件,powerMock的依赖。

buildscript {
    repositories {
        maven { url "https://plugins.gradle.org/m2/" }
        maven { url "https://mvnrepository.com/artifact/" }
    }
    dependencies {
        classpath("org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.7.1")
    }
}

plugins{
    id 'java'
}

apply plugin: "org.sonarqube"
apply from: "${rootDir}/jacoco.gradle"

sonarqube {
    properties {
        property "sonar.sourceEncoding", "UTF-8"
    }
}

subprojects{
    group = 'com.example'
    sourceCompatibility = '1.8'
    apply plugin: 'java'

    //sonar扫描的路径
    sonarqube {
        properties {
            property "sonar.sources", "src/main/java"
            property "sonar.jacoco.reportPaths","${projectDir.path}/build/jacoco/tests.exec"
        }
    }

    tasks.withType(JavaCompile) {
        options.encoding = "UTF-8"
    }

    repositories {
        mavenCentral()
        maven {url "https://maven.aliyun.com/nexus/content/groups/public/"}
        maven {url "http://192.168.9.39:8081/repository/maven-public/"}
    }
    dependencies {

        //单元测试集成
        testImplementation("org.springframework.boot:spring-boot-starter-test:${springbootVersion}") {
            //exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
        }

        //powerMock依赖
        testImplementation("org.powermock:powermock-api-mockito2:2.0.2")
        testImplementation("org.powermock:powermock-module-junit4:2.0.2")
    }
    configurations {
        compileOnly {
            extendsFrom annotationProcessor
        }
    }
    test {
        useJUnitPlatform()
    }
}


jacoco.gradle文件:

jacoco离线模式需要的一些自定义task内容。

apply plugin: 'java'

group 'org.example'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
    jcenter()
}

configurations {
    jacoco
    jacocoRuntime
}

dependencies {
    jacoco group: 'org.jacoco', name: 'org.jacoco.ant', version: '0.8.4', classifier: 'nodeps'
    jacocoRuntime group: 'org.jacoco', name: 'org.jacoco.agent', version: '0.8.4', classifier: 'runtime'
}

subprojects {
    apply plugin: 'java'
    sourceCompatibility = 1.8

    configurations {
        jacoco
        jacocoRuntime
        jacocoInstrumented
    }

    dependencies {
        testImplementation 'junit:junit:4.12'
        jacoco group: 'org.jacoco', name: 'org.jacoco.ant', version: '0.8.4', classifier: 'nodeps'
        jacocoRuntime group: 'org.jacoco', name: 'org.jacoco.agent', version: '0.8.4', classifier: 'runtime'
    }

    task preprocessClassesForJacoco(dependsOn: ['classes']) {
        ext.outputDir = buildDir.path + '/classes-instrumented'
        doLast {
            ant.taskdef(name: 'instrument',
                    classname: 'org.jacoco.ant.InstrumentTask',
                    classpath: configurations.jacoco.asPath)
            ant.instrument(destdir: outputDir) {
                fileset(dir: sourceSets.main.java.outputDir, includes: '**/*.class', erroronmissingdir: false)
            }
        }
    }

    gradle.taskGraph.whenReady { graph ->
        if (graph.hasTask(preprocessClassesForJacoco)) {
            tasks.withType(Test) {
                doFirst {
                    systemProperty 'jacoco-agent.destfile', buildDir.path + '/jacoco/tests.exec'
                    classpath -= files(sourceSets.main.java.outputDir)
                    classpath += files(preprocessClassesForJacoco.outputDir) + configurations.jacocoRuntime

                    def modulesDependencies = moduleDependencies(project)
                    classpath -= files(modulesDependencies.jar.outputs.files)
                    classpath += files(modulesDependencies.jacocoInstrumentedJar.outputs.files)
                }
            }
        }
    }

    task jacocoInstrumentedJar(type: Jar, dependsOn: [preprocessClassesForJacoco]) {
        baseName "${project.name}-instrumented"
        from preprocessClassesForJacoco.outputDir
    }

    test.dependsOn preprocessClassesForJacoco
    test.dependsOn jacocoInstrumentedJar

    artifacts {
        jacocoInstrumented jacocoInstrumentedJar
    }
}

def moduleDependencies(Project project) {
    ConfigurationContainer configurations = project.configurations
    Configuration configuration = configurations.compile

    DomainObjectSet<ProjectDependency> projectDependencies = configuration.dependencies.withType ProjectDependency
    def modules = []
    projectDependencies.forEach {
        modules += it.dependencyProject
        modules += moduleDependencies(it.dependencyProject)
    }
    return modules
}

task report() {
    doLast {
        ant.taskdef(name: 'report',
                classname: 'org.jacoco.ant.ReportTask',
                classpath: configurations.jacoco.asPath)
        ant.report() {
            executiondata {
                subprojects.buildDir.path.collect { file(it + '/jacoco/tests.exec') }.findAll { it.exists() }.each {
                    ant.file(file: it.path)
                }
            }
            structure(name: 'Example') {
                classfiles {
                    files(subprojects.sourceSets.main.output.classesDirs).each {
                        fileset(dir: it)
                    }
                }
                sourcefiles {
                    files(subprojects.sourceSets.main.java.srcDirs).each {
                        fileset(dir: it)
                    }
                }
            }
            html(destdir: buildDir.path + '/reports/jacoco')
        }
    }
}

report.dependsOn += subprojects.test

运行命令和依赖的版本

当前系统使用的是jacoco的offline离线模式,不使用online在线模式的原因如下

原因:因为如果要使用powerMock进行mock静态方法的话,powerMock和jacoco在线模式一起使用会出现冲突,
具体冲突原因可以参考链接
所以,如果你要使用powerMock的某些强大的功能的话,那么你需要使用jacoco的离线模式

整个系统使用的技术和版本
  • gradle 6.5
  • springboot 2.3.2.RELEASE
  • org.jacoco.ant 0.8.4

  • org.jacoco.agent 0.8.4

  • sonarqube-gradle-plugin 2.7.1
扫描代码覆盖率
./gradlew clean report sonarqube
构建+扫描
./gradlew clean build report sonarqube

执行完命令后,可以在build/reports文件夹下查看覆盖率

3.Demo的Github地址

https://github.com/liushuyu1/jacoco_sonar_demo/blob/master/README.md

你可能感兴趣的:(jacoco,sonar,gradle,1024程序员节)