NO END FOR LEARNING

Writing blog if you feel tired | 学海无涯 苦写博客

配置Jenkins运行Github的仓库代码构建

| Comments

用了这么久的CI服务应用,Jenkins, Go pipeline,还没有自己尝试搭建一个。今天花点时间在本地搭建了Jenkins。

安装

以Mac版本为例:

打开: https://wiki.jenkins-ci.org/display/JENKINS/Installing+Jenkins ,下载Mac版本。

安装完成之后,会直接启动 http://localhost:8080 ,也就是说,Jenkins会默认启动8080端口作为服务端口。

在mac下,如果你想要切换端口,你需要这么做:

1
2
3
sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist
sudo defaults write /Library/Preferences/org.jenkins-ci httpPort 8443
sudo launchctl load /Library/LaunchDaemons/org.jenkins-ci.plist

如果切换成https,如下:

1
2
3
sudo defaults write /Library/Preferences/org.jenkins-ci httpPort 8443
sudo defaults write /Library/Preferences/org.jenkins-ci httpsKeyStore /path/to/your/keystore/file
sudo defaults write /Library/Preferences/org.jenkins-ci httpsKeyStorePassword <keystore password>

你会发现,它们都有下面的两个命令,它们用来在mac中启动和关闭Jenkins服务:

1
2
sudo launchctl load /Library/LaunchDaemons/org.jenkins-ci.plist
sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist

安装Github插件和配置项目第一个项目

安装完成之后,你可以点击new item来新建一个构建项目,选择Freestyle project。

在Source Code Management中,你会发现,它CVS和Subversion的支持。没错,Jenkins默认并不支持Git配置。你需要安装Github Plugin。

回到Jenkins服务器的首页,打开Manage Jenkins,里面有Manage Plugins。在Available Plugin中搜索GitHub plugin,安装并重启Jenkins(页面上又重启的checkbox,点击一下即可)。

安装完成后,再次新建item,可以看GitHub project字段,Source Code Management中多了Git,Build Triggers中多了Build when a change is pushed to GitHub(但简单配置这个,还不能实现自动trigger,后面讲)。

在Build那一栏,选择添加Build Step,在本例中选择python。

我的项目是一个NodeJS项目,所以第一步是npm install。

保存项目,回到项目栏,点击Schedule a build。

构建执行失败和Jenkins用户

正如这个小标题,构建执行失败了,你会发现失败的原因是command npm not found。

NPM这个命令不存在,原因是Jenkins在执行该shell脚本的时候是以jenkins这个用户身份去执行,所以命令的PATH配置是不正确的。

Prepare Env Before Run

在运行前配置Jenkins运行命令的环境,有两种方式:

1.直接在Prepare an environment for the run中配置
2.安装Environment Inject插件,在Inject environment variables to the build process中配置

我这里配置了下node的bin,npm中的bin。

1
PATH=$PATH:/usr/local/bin:/usr/local/Cellar/node/0.12.5/libexec/npm/bin/

A Blue Ball Appear,一个蓝色灯泡的故事

配置完成之后,再次执行,构建成功。但是构建的提示是一个蓝颜色的球。为什么是蓝色球呢?请看: http://jenkins-ci.org/content/why-does-jenkins-have-blue-balls

当然我不太习惯,好在要换成绿色球也很简单,安装插件:Green Ball Plugin。

Pipeline插件

根据现代软件的开发方式,我们更习惯于构建CI以pipeline的方式呈现,pipeline中有不同的step,有可以自动的trigger,也有可以手动trigger,比如:部署到Test或者Production环境,理论上应该是手动的触发。

这个时候,你需要安装Jenkins的pipeline插件。安装完成之后,回到首页,点击tab上的加号,添加一个tab,你就可以看到pipeline选项。

新建一个pipeline的tab,需要你填写一些信息,比如:在pipeline页面一次显示多少个构建的pipeline,配置完成之后,你就可以看到pipeline页面了。

在pipeline页面,你可以添加一个step,其实也就是新建一个item,选项可以是free style的,也可以从别现有项目copy生成。

配置方式和新建一个item一样。

配置完成之后,你可以在前一个项目的Post-build Actions中添加Build Other Projects,选择Trigger only if build is stable或者其他,填写被trigger的项目。

这样就可以自动触发后续的step。

Clone Workspace

你肯定会发现,既然新的step就是一个新的item,那么不是要重新check out一次代码,而且之前build的archive也不在了。

没错,这是个问题,这个时候,你需要安装Clone Workspace SCM Plugin,安装完成之后,你需要做两件事情:

1.在upstream的项目中的Post-Build Actions中添加Achieve for Clone Workspace SCM
2.在downstream的项目的Source Code Management中选择Clone Workspace

关于Build when a change is pushed to GitHub

简单的添加这个选项还不行,需要你在github的webhook中进行配置,方法在下面的链接中,但是前提是,需要配置的jenkins有url,如果是像我这样在本地配置的,可能就会有问题。 http://thepracticalsysadmin.com/setting-up-a-github-webhook-in-jenkins/

Spring4.0中通过ActiveProfiles和SpringActiveProfileResolver为不同环境下的集成测试指定不同的Properties配置

| Comments

场景

在运行集成测试的时候,很可能会遇到这样一种情况:

本地的测试环境和持续集成服务器上的运行环境不同,最可能不同的的一种场景就是数据库服务器的配置不同,比如:host,端口,instance。

解决方案

这个时候,我希望,不同的环境下,使用不同的application.properties文件配置。

如果你熟悉Spring Boot中profile的概念,那么,你一定会想到指定不同的profile,于是就有了两个不同的配置文件application-local.properties和application-ci.properties。

如果是启动Spring Boot,可以通过–spring.active.profile=dev来指定不同的profile。

如果是测试呢?通过注解@ActiveProfiles。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@Transactional
@ActiveProfiles("test")
public abstract class AbstractControllerIntegrationTest {

    protected MockMvc mockMvc;

    @Autowired
    private WebApplicationContext webApplicationContext;

    @Before
    public void setUp() throws Exception {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    }
}

可是,这样做还有一个问题,通过@ActiveProfiles(“test”),是硬编码该测试使用test这个profile,那本地环境和集成测试环境要使用不同的profile,应该怎么办呢?

Spring 4中提供了一个接口:ActiveProfilesResolver,以可编程的方式提供active profile的解析。

1
2
3
4
5
6
7
8
9
import org.springframework.test.context.ActiveProfilesResolver;

public class SpringActiveProfileResolver implements ActiveProfilesResolver {
    @Override
    public String[] resolve(Class<?> testClass) {
        final String activeProfile = System.getProperty("spring.profiles.active");
        return new String[]{activeProfile == null ? "test" : activeProfile};
    }
}

使用方式很简单,在ActiveProfiles中指定resolver。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@Transactional
@ActiveProfiles(resolver = SpringActiveProfileResolver.class)
public abstract class AbstractControllerIntegrationTest {

    protected MockMvc mockMvc;

    @Autowired
    private WebApplicationContext webApplicationContext;

    @Before
    public void setUp() throws Exception {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    }
}

根据上面ActiveProfileResolver的实现方式,你只需要在运行集成测试时,指定一个系统变量spring.profiles.active。

以Gradle为例: 如果运行集成测试的任务是test,那么你只需要这样写:

1
2
3
test {
    systemProperty "spring.profiles.active", "ci"
}

但是如果,你希望通过命令行参数传递,来决定active的profile,那么你还需要获取Gradle的命令参数:

1
2
3
4
5
test {
    if (project.hasProperty('profile')) {
        systemProperty "spring.profiles.active", "$profile"
    }
}

运行时的命令是:

1
./gradlew test -Pprofile=ci

结束语

通过这样的配置,在集成测试环境中,配置执行的命令就可以通过传递参数来指定激活的profile,而开发环境使用默认值(即不同在命令行指定参数)。

参考资料:
1.http://stackoverflow.com/questions/20551681/spring-integration-tests-with-profile 作答人:Sam (author of the Spring TestContext Framework)