使用Gitlab CI和Gradle持续集成Spring MVC项目到Heroku

一直在实践持续集成相关的思想和工具,用过不少的持续集成工具,最近用到一种持续集成的pipeline,使用Gitlab和Heroku,可以通过简单的配置实现轻量级的持续集成,加速代码的开发。


简单的持续集成工作流

Github代码,目前在分支下进行开发:deploy分支链接

Gradle项目创建

首先要创建一个使用Gralde构建的Spring MVC项目,本地使用IDEA进行开发,创建一个项目之后,修改build.gradle。引入依赖的包。以下是部分重要的包

apply plugin: 'idea'
apply plugin: 'java'
apply plugin: 'war'

repositories {
    mavenLocal()
    mavenCentral()
}

dependencies {
    compile 'org.slf4j:slf4j-api:1.7.13'
    compile 'org.slf4j:slf4j-log4j12:1.7.13'
    compile 'org.slf4j:jcl-over-slf4j:1.7.13'
    compile 'org.slf4j:jul-to-slf4j:1.7.13'

    compile 'javax.servlet:javax.servlet-api:3.1.0'
    compile 'javax.servlet:jstl:1.2'
    compile 'taglibs:standard:1.1.2'
    compile 'javax.servlet.jsp:javax.servlet.jsp-api:2.3.1'

    compile('org.springframework:spring-core:4.1.8.RELEASE') {
        exclude module: 'commons-logging'
    }
    compile 'org.springframework:spring-beans:4.1.8.RELEASE'
    compile 'org.springframework:spring-context:4.1.8.RELEASE'
    compile 'org.springframework:spring-context-support:4.1.8.RELEASE'
    compile('org.springframework:spring-aop:4.1.8.RELEASE') {
        exclude module: 'commons-logging'
    }
    compile 'org.springframework:spring-tx:4.1.8.RELEASE'
    compile 'org.springframework:spring-orm:4.1.8.RELEASE'
    compile 'org.springframework:spring-jdbc:4.1.8.RELEASE'
    compile 'org.springframework:spring-web:4.1.8.RELEASE'
    compile 'org.springframework:spring-webmvc:4.1.8.RELEASE'

    compile 'com.fasterxml.jackson.core:jackson-core:2.6.3'
    compile 'com.fasterxml.jackson.core:jackson-databind:2.6.3'
    compile 'com.fasterxml.jackson.core:jackson-annotations:2.6.3'
    compile 'org.freemarker:freemarker:2.3.23'

    compile 'org.apache.commons:commons-lang3:3.4'

    testCompile group: 'junit', name: 'junit', version: '4.11'
    testCompile group: 'org.testng', name: 'testng', version: '6.9.8'
}

test {
    useTestNG{
        suites testngConfigPath
        useDefaultListeners = true
    }
}

为了方便进行开发还有最后在Heroku运行,使用Jetty Runner来运行web程序相应的配置为:

configurations {
    jettyServer
}

dependencies {
    jettyServer 'org.eclipse.jetty:jetty-runner:9.3.9.M1'
}

def jettyHttpPort = 8090
task jettyServerRun(type: JavaExec,dependsOn: build) {
    main = "org.eclipse.jetty.runner.Runner"
    args = ["--port",jettyHttpPort,war.archivePath]
    classpath configurations.jettyServer
}

配置最基本的SpringMVC应用

详细配置,参看GitHub代码。

  • 创建maven的默认目录结构。
  • 在src/main/webapp/WEB-INF下面创建web.xml。
  • 在src/main/resources/config下创建Spring的mvc和context配置文件。

编写简单的控制器代码

@RestController
@RequestMapping(value = "data")
public class DataController {
    private final Logger logger = LoggerFactory.getLogger(DataController.class);

    @Autowired
    private UserService userService;

    @RequestMapping(value = "success")//, method = RequestMethod.GET
    public Map success() {
        logger.debug("DataController.success[/data/success]");

        Map resultMap = new HashMap();
        resultMap.put("status",true);
        resultMap.put("code","success");
        resultMap.put("content","数据获取成功");
        return resultMap;
    }
}

编写基本的单元测试

首先创建testng的测试集配置文件src/test/resources

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="TestAll">
    <test name="TestMVC" enabled="true">
        <groups>
            <run>
                <include name="data" />
                <include name="mvc" />
                <include name="rest" />
            </run>
        </groups>

        <classes>
            <class name="com.liuwill.test.DataControllerTest"/>
        </classes>
    </test>
</suite>

然后,编写测试集成测试代码,检查Controller代码是否正确
@WebAppConfiguration(value = "src/main/webapp")
@ContextConfiguration(locations = {"/config/spring-mvc.xml","/config/spring-context.xml" })
public class DataControllerTest extends AbstractTestNGSpringContextTests {
@Autowired
private WebApplicationContext wac;

private static String URI = "/data/success";//RESTurl.searchPersonalFile;
private MockMvc mockMvc;

@BeforeClass(groups = {"context","data"})
public void setup() {
    this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}


@Test(groups = {"data"})
public void testSuccess() throws Exception {
    System.out.println("Load List Json");
    mockMvc.perform(MockMvcRequestBuilders.get("/data/success").accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value("success"))
            .andDo(print());
    System.out.println("测试控制器 DataController:");
}

}

创建Gitlab项目,并配置自动化构建

这里可以自己下载一个Gitlab社区版,搭建自己的git私有仓库,也可以使用gitlab提供的服务,这里使用gitlab提供的服务,首先需要创建Gitlab账户,如果不想从头注册,可以使用Google或者Gitbhub账号进行登录。

然后创建本地Git项目,然后将代码上传到gitlab:

git config --global user.name "liuwill"
git config --global user.email "liuwei_will@qq.com"

cd existing_folder
git init
git remote add origin 项目的git地址
git add .
git commit
git push -u origin master

完成以上步骤之后,代码就会添加到远程仓库,但是这个时候并不会开始自动化构建项目,还需要配置一个支持构建规则的Runner环境来运行构建。具体配置参看官方文档,如果像本例一样使用官方提供的Gitlab仓库的话,可以使用官方提供的默认Runner.

Runner的面板

有了构建环境的Runner之后,就可以添加Gitlab CI的配置文件.gitlab-ci.yml在代码库中,然后上传代码,开始构建

image: java:openjdk-8

stages:
  - test
  - deploy

before_script:
  - apt-get update -y
  - apt-get install gradle -y

test_async:
  stage: test
  script:
   - gradle test --info
  tags:
    - docker

staging:
  type: deploy
  script:
    - apt-get update -qy
    - apt-get install -y ruby-dev
    - gem install dpl
    - dpl --provider=heroku --app=$HEROKU_APP_NAME --api-key=$HEROKU_API_KEY
  only:
    - deploy
  tags:
    - docker

在执行git push之后,gitlab ci就会自动开始进行构建,通过配置deploy属性,还可以直接将代码部署到Heroku中,目前还没有集成测试过该功能。

构建的面板

将代码部署到Heroku

Heroku提供了非常方便的功能,只要通过简单的配置,就可以通过git push直接一键将代码部署到heroku应用中,而且可以非常方便的和其他的ci工具进行集成,下面先介绍一下如何在本地直接将代码部署到Heroku的步骤,然后在将Gitlab CI和Heroku集成起来实现完成的持续集成。部署基于Gradle构建的代码到Heroku的方法,可以参看官方提供的教程.

首先要下载安装Heroku的工具包,Windows版的下载地址
发布的步骤如下:

  • 在项目的根目录下执行heroku login,使用heroku注册的邮箱和密码登录;
  • 执行heroku create工具包会进行一些默认的配置的,包括添加远程仓库heroku,可以是执行heroku git:remote -a appName
  • 运行git push heroku master将要发布的分支推送到heroku提供的操作;如果要使用非master分支,那么执行git push heroku deploy:master
  • 设置web应用的规模,heroku ps:scale web=1
  • 执行heroku open就会在浏览器中打开部署好的页面
  • 开始运行之后,通过heroku log --tail可以查看日志

要在heroku上运行程序,还需要配置Procfile和专用的gradle task,告诉heroku怎样才能将程序运行起来

web: java $JAVA_OPTS -jar build/dist/jetty-runner-9.3.9.M1.jar --port $PORT build/libs/WebFrontTemplate-1.0.jar
task copyJettyJars(type: Copy) {
    from configurations.jettyServer
    into 'build/dist' // 目标位置
}

task stage{
    dependsOn "build","copyJettyJars"
}

另外,heroku可以支持直接link到github,然后直接从github抓取代码来运行.

集成Gitlab CI和Heroku

首先需要在Heroku的控制面板上创建一个新的app,然后从manage account获取账户的API KEY.
然后,在Gitlab的项目配置中,设置两个变量HEROKU_APP_NAME和HEROKU_APP_KEY,对应Heroku的api key和创建的应用的名称;

heroku-apikey.png

然后在yaml文件中增加一个新的Job:staging,push代码到gitlab仓库,然后等待构建完成,就可以从Heroku的app站点访问成功部署的应用。大功告成!

gitlab-success.png
heroku-success.png

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容