公共脚本

公共脚本

Gradle 中公共脚本抽取与共享

要解决冗余代码和通用配置的问题,最简单的做法就是抽取出共同部分,作为其它所有项目的 parent/common 项目。

使用 git submodule

将所有系统中公共的类库和通用的配置,放到独立的仓库 Common 中。因为我们用 git 来管理代码,而 git 本身提倡多 branch,多仓库,所以采用 git submodule 方式,其它项目需要添加 Common 这个 submodule:

git submodule add yourGitRepo deps/Common

最后的”deps/Common”是自定义的,意思就是在当前的 deps 目录下用 Common 名字来当作 submodule 的 clone。

如果你 clone 别的带有 submodule 的项目时,默认情况下,当前的 project 并不会把 submodule 的代码都 clone 下来,可以执行:

git submodule foreach git pull

以下这段一般大家经常会遇到:当你 clone 项目时,submodule 会以最新的 master 分支上的 commit id 作为本次的 tag 下载,类似一个副本,因为一般大家都是用 submodule,而不是修改它。所以当你的 submodule 需要更新的时候,需要先执行这段代码:

git submodule foreach git checkout master

让 submodule 切换到 master 分支了,然后就可以用上面的 submodule pull 来更新了。

Gradle 构建

鉴于上文对 gradle 优点的描述,我们采用 gradle 来构建。我们的项目最初都是基于 maven 来构建的,从 maven 切换到 gradle 很简单,在项目根目录下,先执行(假设你的机器已经安装了 gradle 环境,一般负责构建的人首次需要安装,开发人员可以不安装):

gradle init wrapper

这样,就会自动生成相关的 gradlew,build.gradle,settings.gradle 等文件和相关目录,并会自动下载对应版本的 gradle binary 包(所以以后不需要安装)。Gradle 会自动识别 Maven 里的配置,并相应的导入进来,有少量部分配置可能需要修改。

注:在已有的 gradle 项目里,尽量使用生成的 gradlew 这个 wrapper,因为它会自动下载对应版本的 Gradle,也就是说团队合作的其他人开发机上是不需要手动安装 Gradle 的,并且 wrapper 也让大家的 Gradle 版本一致,避免问题。

Gradle 脚本修改

上面执行完之后,环境已经准备好了,现在要做的就是修改构建脚本:因为已经通过 git submodule 把公共项目放到独立目录(deps/Common)了,并且它本身也是独立可构建的项目,那么也就是说当前有两个项目了,一个是当前 project,一个是 Common 项目,要做的就是告诉 gradle,要多项目构建,编辑 settings.gradle,增加项目配置:

include "deps:Common"

以上就是把 Common 引入到当前项目了。根据项目的不同,然后对应修改 build.gradle,就大功告成了。看一个例子:

// 这一段主要是把公共库Common的构建脚本引入,因为一般会有通用的配置在里面
def userGradleScript = file("deps/Common/build.gradle")
if (userGradleScript.exists()) {
    apply from: userGradleScript
}
// 使用war插件,这样就默认引入了java插件
apply plugin: 'war'
// for jetty
apply plugin: 'jetty'
stopKey = 'yourStopKey' // 自定义的stopkey
stopPort = xxxx     // 停止端口
httpPort = xxxx     // 启动http端口

// 项目属性
group = 'yourApp'
version = '1.0.0'
description = """这里描述你的项目"""


// checkstyle config文件地址
checkstyle {
    configFile = file("deps/Common/config/checkstyle/checkstyle.xml")
}
// lib依赖
dependencies {
    // 依赖公共库Common,compile是和maven里的compile scope一样
    compile project(':deps:Common')
    compile 'commons-validator:commons-validator:1.4.0'
    compile('javax.servlet.jsp.jstl:jstl-api:1.2') {
        exclude(module: 'servlet-api')      // 防止版本冲突
    }
    compile 'javax.persistence:persistence-api:1.0.2'
    runtime 'mysql:mysql-connector-java:5.1.26'
    providedCompile 'org.apache.tomcat:tomcat-servlet-api:7.0.30'
    // providedCompile 这个conf在java插件里是报错的,war里是正确的
    providedCompile 'javax.servlet.jsp:jsp-api:2.1'
    ...
}

我们再来简单看下公共项目 Common 的构建脚本:

// 定义一堆基础插件
apply plugin: 'java'
apply plugin: 'maven'
apply plugin: "jacoco"
apply plugin: 'checkstyle'
apply plugin: 'pmd'
apply plugin: 'findbugs'
apply plugin: 'eclipse'
apply plugin: 'idea'

// 定义项目属性
group = 'Common'
version = '1.0.0'
description = """Giant common library"""

// 定义依赖仓库
repositories {
    mavenCentral()
}
// project的额外属性,这里用于定义profile属性,模拟maven的profile
ext {
    if (project.hasProperty('profile')) {
        profile = project['profile']
    } else {
        profile = "dev"
    }
    println "profile:" + profile
}
// 额外增加source path
sourceSets {
    main {
        resources {
            srcDir "src/main/profiles/${profile}"
        }
    }
}

// project依赖
dependencies {
    compile 'ch.qos.logback:logback-core:1.0.13'
    compile 'ch.qos.logback:logback-classic:1.0.13'
    compile 'ch.qos.logback:logback-access:1.0.13'
    compile 'commons-io:commons-io:2.0.1'
    compile 'commons-lang:commons-lang:2.6'
    compile 'joda-time:joda-time:1.6.2'
    compile 'org.testng:testng:6.8.7'
    compile 'com.googlecode.jmockit:jmockit:1.5'
    ...
}

// task 配置
checkstyle {
    ignoreFailures = true
    sourceSets = [sourceSets.main]
}

findbugs {
    ignoreFailures = true
    sourceSets = [sourceSets.main]
}

pmd {
    ruleSets = ["basic", "braces", "design"]
    ignoreFailures = true
    sourceSets = [sourceSets.main]
}

jacocoTestReport {
    reports {
        xml.enabled true
        html.enabled true
        csv.enabled false
    }
    sourceSets sourceSets.main
}

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

test {
    useTestNG()
    jacoco {
        excludes = ["org.*"]
    }
}

这样,就可以在公共项目里配置好一堆基础的 task,dependencies 等等,而使用这个公共项目的其它项目则可以直接使用,无需再额外配置。脚本修改完了,就可以开始构建了(不需要安装 gradle,直接使用生成的 gradlew 就行):

./gradlew build

// 基于profile构建
./gradlew -Pprofile=dev build

常用构建命令:clean:清除之前的构建 test:执行测试 compileJava:编译 java check:在 test 之后做一个 check,一般代码检查插件,都是在这个阶段做的 build:构建打包

下一页