一直在实践持续集成相关的思想和工具,用过不少的持续集成工具,最近用到一种持续集成的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之后,就可以添加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和创建的应用的名称;
然后在yaml文件中增加一个新的Job:staging,push代码到gitlab仓库,然后等待构建完成,就可以从Heroku的app站点访问成功部署的应用。大功告成!