“从禅道开源版12.1版本开始,配置SVN代码库方法是:请使用管理员登录禅道,在集成 - 代码库 中进行配置(具体方法在 https://www.zentao.net/book/zentaopmshelp/393.html集成版本库、集成Jenkins,并进行构建),无须再按步骤三操作,配置好后看步骤四。” — Zentao官方文档:集成禅道和svn
1. 前言
笔者曾经写过一篇关于SVN实现与禅道关联,向禅道中写入对应SVN提交日志的博客,不过这种方式在部门内部将禅道进行升级之后,发现失效了。一番探究之下发现是禅道将相关实现逻辑改了——现在需要你预先在禅道上进行界面化的仓库地址配置。
为了复用之前的成果,笔者决定为新版本禅道将原本基于配置文件的svn集成方式补充回来,于是就有了本文。
2. 实现
思路如下:
- 下载旧有版本的zentao开源版,笔者这里使用的是Zentao开源8.1.3版本发布。
- 借助zentao提供的扩展机制,将上面获取到的相关代码移植到相应的扩展代码存放位置,以避免后期再次进行禅道升级时候功能失效。
- 借鉴SVN实现与禅道关联,向禅道中写入对应SVN提交日志博客中的打通逻辑,优化为借助zentao官方提供的扩展方式 - 在第三方应用中集成禅道,这样能省却了之前实现方式中对于Jenkins + Ansible的依赖,让实现链路更短。
2.1 获取旧版本的相关实现代码
需要从旧版本禅道中获取的核心文件只有一个,也就是zentao\module\svn\model.php
。将其以禅道提供的对模型层(model)扩展方式进行存放,再补上相关的调用逻辑,于是就有了如下目录结构:
2.2 扩展文件存放
X:\XAMPP\ZENTAO\MODULE\SVN\EXT
├─config
│ svn.php
│
├─control
│ run2.php
│ syncLog.php
│
└─model
│ xxxSvn.php
│
└─class
xxxSvn.class.php
####### 为了方便读者,这里将相关代码全部贴一遍
# svn.php 这一步对于我们的调用链其实是不生效的,这里的配置主要是为了调试阶段进行命令行调用,以快速验证问题
<?php
$svnClient = substr(__FILE__, 0, strpos(__FILE__, 'zentao')) . 'sliksvn\svn.exe';
$config->svn->client = $svnClient;
$i = 1;
# 如果SVN路径中有中文,就用 mb_convert_encoding('https://xxx.xx.xx.xx:804/svn/DJ/yyy/zz/中文/ZZSH','GB2312', 'UTF-8');
$config->svn->repos[$i]['path'] = 'https://xxx.xx.xx.xx:804/svn/DJ/yyy/zz' ;
$config->svn->repos[$i]['username'] = 'svnUserName';
$config->svn->repos[$i]['password'] = 'svnPassword';
$i ++;
####### run2.php 这个方法主要是提供命令行调用的
<?php
include '../../control.php';
class mySvn extends svn
{
/**
* Sync svn.
*
* @access public
* @return void
*/
public function run2()
{
$this->svn->run2();
}
}
####### syncLog.php
<?php
// syncLog.php
include '../../control.php';
class mySvn extends svn
{
public function syncLog($svnReposUrl)
{
// base64_decode的出现是因为url作为参数时需要处理下
$svnReposUrl = base64_decode(str_replace("___","+",$svnReposUrl));
// 这里的一系列处理依然是针对中文, 所以强烈推荐不要在svn路径中整啥中文,哪怕你用个拼音的全拼呢, 而且这里还不算完,本文下方的参考链接可以看到为了这中文编码问题还坑在哪里
$svnReposUrl = mb_convert_encoding($svnReposUrl,'GB2312', 'UTF-8');
$repos = new stdClass();
$repos ->path = $svnReposUrl;
$repos ->username = "svnUsername";
$repos ->password = "svnPassword";
$this->config->svn->repos[md5($svnReposUrl)] = $repos;
// 这里就时调用我们的model扩展,下面马上给出
$this->svn->run2();
}
}
####### xxxSvn.php
<?php
public function run2()
{
$this->loadExtension('xxxSvn')->run();
}
####### xxxSvn.class.php
class kanqSvnSvn extends svnModel
{
// 这里面的内容就是我们从旧版本中拷贝来的 model.php, 除了类名,啥都不用改
}
2.3 关联Zentao + SVN
首先是zentao官方提供的打通方式:
# 这里的svn-run2 正是我们上面的定义
# 借助这个命令行调用,我们可以快速进行错误验证
# 以下脚本内容其实就是 D:\xampp\zentao\bin\syncsvn.bat 中的
D:\xampp\php\php.exe D:\xampp\zentao\bin\ztcli "http://127.0.0.1:82/svn-run2"
然后是我们借助svnChecker的 postCommit核心代码实现:
# svnChecker的 postCommit 实现原理和配置方式这里就不重复了;
# 下面这些常量就不给出了,名字已经很清晰表明了意义
# 下面这三行依然是中文导致的
import sys
reload(sys)
sys.setdefaultencoding('utf8')
def run(transaction, config):
commitMsg = transaction.getCommitMsgWithLinesep() # getCommitMsg
userId = transaction.getUserID()
reversion = transaction.getRevision()
# fullUrlPath ---> https://xxx.57.yyy.ccc:804/svn/XX/trunk/XYZ
# filename ---> trunk/CCC/XXX.txt
filename = transaction.getFiles().items()[0][0]
# transaction.getReposPath() ---> /home/XX/
fullRespoPath = path.join(SVN_BASE_URL, transaction.getReposPath().replace("/home/", ""), path.dirname(filename))
# call zentao
time1 = int(time.time())
token = hashlib.md5((ZENTAO_CODE+ZENTAO_KEY+str(time1)).encode(encoding='UTF-8')).hexdigest()
# 这里就和上面的 ___ 替换呼应上了
svnReposUrl = str(base64.b64encode(bytes(fullRespoPath))).replace("+", "___")
response = urlopen('{}/api.php?m=svn&f=syncLog&svnReposUrl={}&code={}&time={}&token={}'.format(ZENTAO_BASE_URL, svnReposUrl, ZENTAO_CODE, time1, token))
# TODO 验证response
return (fullRespoPath, 0)
3. 效果
当用户提交代码之后,postCommit钩子将触发,进行SVN日志同步。
而因为我们之前已经实现了preCommit钩子进行日志提交格式校验(例如:【DEVOPS】借助SvnChecker实现SVN提交日志规范的落地和【DEVOPS】借助GitLab全局Hook规范化提交日志),因此这一步是能够保证成功的。
4. 补充
其实如果公司项目数量稳定,或者有着清晰的管理职责,还是推荐先将相关svn地址录入禅道,然后就可以流畅使用禅道内置提供提供的集成方式,笔者这种方式只适用于管理比较混乱,职责不清晰,且新项目不断涌现的情况。