前段时期我负责部门内部主干开发落地相关事宜,这个过程中,也真真切切的体会到了多人开发过程中,面对特性分支管理中,大家遇到的一些困扰,尤其面对敏捷迭代的开发方式,合并冲突,集成测试,代码重用等方面,都与高效两个字背离。当然,我在推进主干开发过程中,也遇到了一些问题和坎坷,在这里,集中的做一次分享。

1. 概述

主干开发,是指开发人员直接向主干(习惯上主干分支通常为:trunk 或 master)提交 / 推送代码。通常,开发团队的成员 1 天至少 1 次地将代码提交到主干分支。在到达发布条件时,从主干拉出发布分支(通常为 release),用于发布。若发现缺陷,直接在主干上修复,并根据需要 cherry pick 到对应版本的发布分支。

优点:

缺点:

适用环境:

2. 整体架构

2.1 衡量主干开发的效果

可以通过执行以下操作来衡量主干开发的效果。

测试的因素 衡量的指标 目标
应用代码库中的活跃分支数。 衡量应用代码库版本控制系统中的活跃分支数,让所有团队都能看到此数字。然后跟踪目标状态的增量式进度。 不超过三个活跃分支。
代码冻结期。 衡量团队的代码冻结数及冻结时长。这些衡量指标还可以对合并冲突、代码冻结、稳定等方面所耗费的时间进行分类。 无人提交代码时,没有代码会被冻结。
将分支合并到主干的频率。 衡量合并的每个分支的二进制(是/否)值,或者衡量每天合并的分支的百分比。 每天至少合并一次。
查看审批代码更改所需的时间。 如果您异步执行代码审核,请衡量审批更改请求所需的平均时间,并特别关注所需时间大大超过平均值的请求。 设法使代码审核成为在开发过程中执行的同步活动。

2.2 常见误区

如需全面采用主干开发,需要避免以下常见障碍:

2.3 改进主干开发的 Tip

2.4 主干开发流程说明

如图所示,研发小伙伴基于 master 分支开发,当每次 merge 时,都会触发流水线验证过程。在流水线验证中:

1.EOS 代码扫描,该扫描会扫描代码中不规范的情况,按照代码规约不同,会有不同的级别,包括 WARNING, MAJOR, CRITICAL, BLOCKER 四种级别,基于不同级别可以设置拦截规则,如果代码不符合设定的拦截规则,将不予 merge。

2.代码评审会触发代码评审邀请,可以根据设定,邀请组内研发,leader,或者测试人员参与代码评审,通过设定规则,如果代码评审通过,才允许 merge。

3.现在自动进行 maven 打包和单元测试工作,如果单元测试不通过,将不予 merge。

4.流水线会自动将单元测试通过的 jar 包发布到测试的 JOS 分组进行部署,部署完成后自动调取线上自动化测试流程,只有所有接口通过自动化测试,才允许 merge。

3. 落地方案

3.1 单元测试

应用架构: 基于 spring boot junit 编写单元测试。

我们可以将测试按照模块划分,放在不同的目录之下,可以分为集成测试和单元测试。这样做的原因是,当我们的项目边的越来越大的时候,写的测试会越来越多,当所有测试都放在一个目录下的时候,跑一次集成测试时间会很长。具体目录如下:

主开发目录 测试开发目录 测试模块 描述 测试父类命名
src/ test/ init 初始化测试模块 InitTestBase
unit service 单元测试模块 UnitTestBase    
jpa 持久化层测试模块 JPATestBase    
mvc controller 层测试 MvcTestBase    

所有测试模块集成对应的父类,然后类名必须以对应模块 +Test 结尾,例如:ShipperStatisticUnitTest

  1. 引入单元测试依赖 spring-boot-starter-test
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
</dependency>


2. 引入 surefile 插件

 <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.2</version>
                <configuration>
                    <skip>false</skip>
                    <includes>
                        <include>**/unit/*Test.java</include>
                    </includes>
                </configuration>
</plugin>


3. 配置测试配置文件路径

<resources>
       <testResources>
           <testResource>
               <directory>src/test/resources</directory>
               <!--①-->
               <excludes>
                   <exclude>application*.properties</exclude>
               </excludes>
           </testResource>
           <testResource>
               <directory>src/test/resources</directory>
               <filtering>true</filtering>
               <includes>
                   <include>application.properties</include>
                   <include>important.properties</include>
                   <include>application-${activatedProperties}.properties</include>
               </includes>
           </testResource>

       </testResources>


3.2 JaCoCo 代码覆盖率扫描

该处可以先串联到流水线中,但不做门禁设置,等后期确定标准后,再打开门禁设置。

3.3 EOS 静态代码扫描

在主干开发模式中,因为 EOS 静态代码扫描,配置代码合并门禁,确保代码编码规范。配置如下图所示例子:

3.4 代码线上评审

代码评审通过 Coding 内置的评审规则实现,规则设定如下:

1.评审分支为 master 分支,并在 push 时创建代码评审,并阻塞代码直接合入目标分支。

2.评审人需要达到两人及以上通过后,才能触发随后的操作。

3.不允许自评。

4.不允许特定成员跳过自动化检查。

3.5 特性开关

遇到此情况,一般是多版本同时开发的情况

此处跟业务强相关,需要具体问题具体分析。不过保证如下几个原则:

3.6 流水线配置

在行云流水线中,主要包括如下几个节点:

其中有一个配置上有一个小坑就是下载代码。为什么这么说呢?

因为我们流水线的触发条件是跟 coding 上的代码评审配合使用,当主干分支发生 merge 请求时,这个时候会触发流水线,但拉取的代码并不能直接填写主干分支名称(如:master), 原因是当前的 commit 快照并没有合并到 master 上,而是处于等待状态,只有当流水线通过后才会真正合并到主干分支,这是如果下载代码里拉取的主干分支就是不包含当前提交内容的快照,并不能满足我们的诉求。

那么,我们该如何配置呢?

好在 Webhook 中会带一些系统内置全局参数,其中 globalParams.user.WEBHOOK_ATTR_COMMIT_ID,代表的就是当前提交请求所包含的 commit 快照,所以,我们只需要配置这个全局参数即可,如图所示:

配合如上配置,我们在触发设置中,只需要设置 MR created/Updated 事件即可。如下图所示:

4. 总结

于许多开发者而言,主干开发是一项重大变革,您很可能会遇到一些阻碍。许多开发者根本无法想像如何采用这种方式工作。一项好的做法是找到曾采用这种方式工作的开发者,让他们指导其他开发者。让一些团队转为采用主干开发方式工作也很重要。实现此目标的一种方法是将大量具有主干开发经验的开发者召集到一起,这样至少有一个团队遵循主干开发做法。然后,如果您确信遵循此做法的团队发挥预期的作用,则可以将其他团队转换为这种风格。

当然主干开发也不是银弹,他也会有一些自己的弊端,比如在处理需求变更,或者同时多版本并行开发时,也需要建立多个临时分支支持,想做到纯粹的主干开发,也是过于理想化的结果。

作者:京东物流 赵勇萍

来源:京东云开发者社区


↙↙↙阅读原文可查看相关链接,并与作者交流