美文网首页
android+jenkins+gradle+lint+chec

android+jenkins+gradle+lint+chec

作者: ReadyShow | 来源:发表于2017-10-11 10:25 被阅读184次

    打造最实用的Android持续集成(Continuous Integration以下简称CI)系统

    什么是CI

    纵览全局(打破职责界限)

    软件开发、运维和质量保证三个部门之间的沟通、协作和集成所采用的流程、方法和体系的一个集合。
    打破目前的rd->qa->op流水线的流程,而是将三者紧密的结合在一起。从实践的结果来看,rd每次提交代码都会触发一系列的自动化步骤,包括编译,单元测试,代码覆盖率,功能测试,部署测试,性能/容量测试(注:后两者受限与时间要求,实际实施不会每次提交代码都触发)。Rd,qa,op都在过程中做质量保障。

    代码树被管理起来——主干开发

    主干开发的好处是每个rd都知晓整体的变更,所有的feature作为一个整体发布,对OP的现实意义就是上线变得更有规律,非计划的、临时的上线最后消失。
    代码和周边(配置,数据,构建脚本,单元测试,测试用例)统一作为产品被管理起来——一键式产构建,测试,部署,完成产品的最终发布。
    大家都在一个平台上工作,所有的任务都在这个平台下,各角色间对互相的工作有更深入的了解,并且,工作状态也可以共享。
    少就是多,简洁就是美(用简单的方法解决问题)
    持续集成的解决方案是简洁的。产品由SVN去管理,构建过程由CI server负责,而构建过程包含了编译,测试,发布,部署过程

    容量测量(Capacity management)

    容量的变化体现在用户行为(流量)系统变更(软件性能)和资源(服务器数量,冗余度计划)等几个因素的变化上,将容量和这些变化挂钩,在每一个因素变化下重新得到系统的容量,从而在变更中控制容量不足造成的风险。有一个要点,我们需要的是系统的容量而不是单个模块的性能。

    质量反馈(Quality feedback)

    变更会导致质量变化,而质量变化体现在各种指标上,而测量这些指标(包括应用指标:平响,处理效率等和系统指标:负载,网络流量),发现指标之间的规律,将指标share给整个团队,从而有效的达成质量的反馈,控制变更(包括内部变更和外部条件的变化)造成的质量下降的风险。

    Jenkins能做什么

    在实施持续集成的过程中,并行实施的三个项目:
    持续部署/一键式部署(continuous deployment/one step deploy),
    容量测试/管理(Capacity Test/Management)
    质量反馈(Quality feedback)
    Jenkins将完成上面3个并行的项目工作

    安装与配置Jenkins

    gradle代码

    apply plugin: 'com.android.application'
    apply plugin: 'kotlin-android'
    apply plugin: 'kotlin-android-extensions'
    
    android {
        signingConfigs {
            mySign {
                keyAlias 'xxx'
                keyPassword 'xxx'
                storeFile file('hqyx.keystore')
                storePassword 'xxx'
                v2SigningEnabled false
            }
        }
        compileSdkVersion 26
    
        defaultConfig {
            applicationId "com.hqyxjy.word"
            minSdkVersion 19
            targetSdkVersion 21
            versionCode 7
            versionName "1.1.0"
            multiDexEnabled = true
    
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
            resValue('string', 'git_last_commit', 'git log --pretty=format:"%H:%ad:%an:%s" --date=short -1'.execute().text)
        }
    
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
                signingConfig signingConfigs.mySign
            }
            debug {
                signingConfig signingConfigs.mySign
            }
        }
    
        productFlavors {
            flavorDimensions 'channel', 'host', 'area'
    
            // 渠道
            hqyx {
                dimension 'channel'
                manifestPlaceholders.put('PACKAGE_CHANNEL_VALUE', 'hqyx')
            }
    
            develop {
                dimension 'host'
                buildConfigField('String', 'HOST', project.properties['environment.host.develop'])
                buildConfigField('String', 'H5_HOST', project.properties['environment.h5_host.develop'])
            }
    
            // host的值
            ttest {
                dimension 'host'
                buildConfigField('String', 'HOST', project.properties['environment.host.test'])
                buildConfigField('String', 'H5_HOST', project.properties['environment.h5_host.test'])
            }
    
            sim {
                dimension 'host'
                buildConfigField('String', 'HOST', project.properties['environment.host.sim'])
                buildConfigField('String', 'H5_HOST', project.properties['environment.h5_host.sim'])
            }
            beta {
                dimension 'host'
                buildConfigField('String', 'HOST', project.properties['environment.host.beta'])
                buildConfigField('String', 'H5_HOST', project.properties['environment.h5_host.beta'])
            }
            online {
                dimension 'host'
                buildConfigField('String', 'HOST', project.properties['environment.host.online'])
                buildConfigField('String', 'H5_HOST', project.properties['environment.h5_host.online'])
            }
            develop {
                dimension 'host'
                buildConfigField('String', 'HOST', project.properties['environment.host.develop'])
                buildConfigField('String', 'H5_HOST', project.properties['environment.h5_host.develop'])
            }
    
            // area
            outside {
                dimension 'area'
                buildConfigField('boolean', 'IS_INSIDE', 'false')
            }
            inside {
                dimension 'area'
                buildConfigField('boolean', 'IS_INSIDE', 'true')
            }
        }
        // 控制打包时输出的文件名
        android.applicationVariants.all { variant ->
            variant.outputs.all {
                if (!variant.buildType.debuggable) {
                    // 计算出新的文件名格式:NewName_v1.3.0_02051437_develop.apk
                    def fileName = "NewName_${defaultConfig.versionName}_${new Date().format("MMddHHmm")}_${variant.flavorName}.apk"
                    fileName = fileName.replace("_z_", "_")
                    outputFileName = fileName
                }
            }
        }
    
        // 配置多渠道时,去除没用的Variants
        android.variantFilter { variant ->
            if (variant.buildType.name.contains('debug')) {
                variant.getFlavors().each() { flavor ->
                    if (flavor.name.contains('z_')) {
                        variant.setIgnore(true)
                    }
                }
            } else {
                variant.getFlavors().each() { flavor ->
                    if (flavor.name.contains('develop')) {
                        variant.setIgnore(true)
                    }
                }
            }
        }
        lintOptions {
            //发生错误时停止构建
            abortOnError true
            //警告都提升为错误
            warningsAsErrors true
            //build release 版本 时 开启lint 检测
            checkReleaseBuilds true
            //规则位置
            lintConfig file("${project.rootDir}/../AndroidCoreLibrary/ci/ruleset/lint.xml")
            //不生成xml报告
            xmlReport false
            //忽略
            disable 'OldTargetApi'
            //设置报告位置
            htmlOutput file("${project.rootDir}/ci/report/app/lint_report.html")
        }
        compileOptions {
            targetCompatibility 1.8
            sourceCompatibility 1.8
        }
    }
    
    dependencies {
        implementation fileTree(include: ['*.jar'], dir: 'libs')
        implementation 'com.android.support:support-v4:26.1.0'
        implementation 'com.google.android.gms:play-services-plus:11.6.2'
        androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
            exclude group: 'com.android.support', module: 'support-annotations'
        })
        testImplementation files('powermocklibs/byte-buddy-1.2.1.jar')
        testImplementation files('powermocklibs/cglib-nodep-2.2.2.jar')
        testImplementation files('powermocklibs/hamcrest-core-1.3.jar')
        testImplementation files('powermocklibs/javassist-3.21.0-GA.jar')
        testImplementation files('powermocklibs/mockito-core-2.0.42-beta.jar')
        testImplementation files('powermocklibs/objenesis-2.4.jar')
        testImplementation files('powermocklibs/powermock-api-mockito-common-1.6.6.jar')
        testImplementation files('powermocklibs/powermock-mockito2-1.6.6-full.jar')
        debugImplementation 'com.amitshekhar.android:debug-db:1.0.1'
    
        implementation project(':AndroidCoreLibrary:core')
    
        implementation project(path: ':svprogresshud')
        testImplementation 'junit:junit:4.12'
        implementation 'com.android.support:appcompat-v7:26.1.0'
        implementation 'com.android.support:design:26.1.0'
        implementation 'com.android.support.constraint:constraint-layout:1.0.2'
        implementation 'com.android.support:multidex:1.0.1'
        implementation 'com.jakewharton:butterknife:8.4.0'
        implementation 'com.android.support:gridlayout-v7:26.1.0'
        implementation 'cn.yipianfengye.android:zxing-library:2.1'
        testCompile 'junit:junit:4.12'
        annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
        debugImplementation 'com.amitshekhar.android:debug-db:1.0.1'
        implementation 'org.greenrobot:eventbus:3.0.0'
        implementation 'com.github.traex.rippleeffect:library:1.3'
        implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
    
        dependencies {
            debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.4'
            releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
        }
    
        //友盟统计
        implementation 'com.umeng.analytics:analytics:latest.integration'
    }
    repositories {
        mavenCentral()
    }
    /*------------------------------------------------------------------------------------------------*/
    /*                                         CI TASK
    /*------------------------------------------------------------------------------------------------*/
    
    apply plugin: 'pmd'
    task pmd(type: Pmd) {
        ruleSetFiles = files("${project.rootDir}/../AndroidCoreLibrary/ci/ruleset/pmd_library_ruleset.xml",
                "${project.rootDir}/../AndroidCoreLibrary/ci/ruleset/pmd_custom_ruleset.xml",
                "${project.rootDir}/../AndroidCoreLibrary/ci/ruleset/pmd_single_ignore_ruleset_naming_VariableNamingConventions.xml")
        ignoreFailures = false
        ruleSets = []
    
        source 'src'
        include '**/*.java'
        exclude '**/gen/**'
    
        reports {
            xml.enabled = false
            html.enabled = true
            html {
                destination "${project.rootDir}/ci/report/app/pmd_report.html"
            }
        }
    }
    
    apply plugin: 'findbugs'
    task findbugs(type: FindBugs) {
        ignoreFailures = false
        effort = "default"
        reportLevel = "medium"
        //过滤器
        excludeFilter = new File("${project.rootDir}/../AndroidCoreLibrary/ci/ruleset/findbug_filter.xml")
        //这里填写项目classes目录
        classes = files("${project.buildDir}/intermediates/classes")
        source = fileTree('src/main/java')
        classpath = files()
        reports {
            //只能开启一个
            xml.enabled = false
            html.enabled = true
            html {
                destination "${project.rootDir}/ci/report/app/find_bugs_report.html"
            }
        }
    }
    
    apply plugin: 'checkstyle'
    
    checkstyle {
        toolVersion '7.1.2'
        showViolations false
    }
    
    task checkstyle(type: Checkstyle) {
        ignoreFailures = true
        def config = file("${project.rootDir}/ci/ruleset/checkstyle.xml")
        if (config.exists()) {
            ignoreFailures = false
            configFile = config
    
            classpath = files()
            source = android.sourceSets.main.java.srcDirs
            include '**/*.java'
            include '**/*.xml'
    
            reports {
                xml.enabled = false
                html.enabled = true
                html {
                    destination "${project.rootDir}/ci/report/app/check_style_report.html"
                }
            }
        }
    }
    

    代码分析

    运行效果

    自定义邮件报告格式

    相关文章

      网友评论

          本文标题:android+jenkins+gradle+lint+chec

          本文链接:https://www.haomeiwen.com/subject/naxvextx.html