实现SVN向Zentao的打通,将原本由人推动的研发流程转变为机器流转,做到快速精准的价值流动。
1. 前言
DEVOPS中关于工具之间互通的重要性在 【DEVOPS】流程打通之快速实现SVN与Jenkins双向关联已经说明过了,这里不再多废话,直接进入正题。
2021/10/31更新: 新版本禅道的集成方式参见: 【DEVOPS】最新版本禅道实现基于配置文件的SVN集成
2. zentao端扩展
这里我们首先借鉴官网的集成禅道和svn,主要实践其中的第四步(代码提交注释格式:
)和第五步(执行svn同步命令
)。这一步操作的主要目的是为了:
- 验证zentao所提供的svn扩展功能正常。
- 熟悉SVN日志提交格式。
接着就是我们根据自身需求实现的自定义扩展了,这一步的主要目的是将上一步中配置在配置文件中的SVN仓库地址变更为命令行参数传入。于是便有了以下扩展。
# E:\xmapp\zentao\module\svn
│ config.php
│ control.php
│ model.php
│
├─ext
│ ├─config
│ │ svn.php
│ │
│ ├─control
│ │ syncLog.php # 核心扩展类
│ │
│ ├─css
│ ├─js
│ ├─lang
│ │ ├─en
│ │ ├─zh-cn
│ │ └─zh-tw
│ ├─model
│ └─view
├─lang
│ en.php
│ zh-cn.php
│ zh-tw.php
│
├─syncer
│ config.php
│ Makefile
│ syncer.php
│ VERSION
│
└─view
cat.html.php
diff.html.php
其中syncLog.php
扩展文件的内容如下:
<?php
// syncLog.php
include '../../control.php';
class mySvn extends svn
{
public function syncLog($svnReposUrl)
{
// 这里会出现str_replace的替换操作是因为如果svn路径中包含中文, base64编码后包含符号 +, 这将导致服务端无法正常接收请求
$svnReposUrl = base64_decode(str_replace("___","+",$svnReposUrl));
$repos = new stdClass();
$repos ->path = $svnReposUrl;
$repos ->username = "svnUsername";
$repos ->password = "svnPassword";
//$sizeOfRepos = sizeof($this->config->svn->repos);
$this->config->svn->repos[md5($svnReposUrl)] = $repos;
$this->run();
}
}
至此,zentao端的扩展结束,调用本API的URL地址为: http://127.0.0.1:port/svn-syncLog-{svnReposUrl}
。这里需要注意的是因为URL规范的要求,对于svnReposUrl
参数我们需要将其进行base64编码后传入,这也是为什么本扩展方法中有base64解码的操作。
3. svn端扩展
依然是类似 【DEVOPS】流程打通之快速实现SVN与Jenkins双向关联的操作,这里我们扩展出了TriggerZentao.py
文件。
from modules import Process
import collections
# `TriggerZentao.py`
def run(transaction, config):
check = config.getArray("TriggerZentao.CheckFiles", [".*\.*"])
ignore = config.getArray("TriggerZentao.IgnoreFiles", [])
files = transaction.getFiles(check, ignore)
java = config.getString("TriggerZentao.Java")
files = [transaction.getFile(oneFile[0]) for oneFile in files.iteritems() if oneFile[1] in ["A", "U", "UU"]]
filepath = files[0]
jenkinsInfo = getMatchedJenkinsInfo(filepath)
if jenkinsInfo is None:
return ("no matched Jenkins task", 1)
jenkinsJobName = jenkinsInfo[0]
svnPath = jenkinsInfo[1]
noteticedUser = transaction.getUserID() #.replace("zhengdandan","zhengdandan1")
command = "%s -jar {rootPath}/jenkins-cli.jar -s http://jenkinsIp:port/ -auth username:password build %s -p RESPO_URL=%s" % (java, jenkinsJobName, svnPath)
try:
Process.execute(command)
except Process.ProcessException, e:
msg = "Jenkins CLI trigger Zentao errors found:\n\n"
msg += e.output + "\n"
return (msg, 1)
return ("", 0)
def getMatchedJenkinsInfo(tempfileFullPath):
mappings = getMapping()
for k,v in mappings.items():
if k in tempfileFullPath:
return v
print tempfileFullPath
return None
def getMapping():
SVN_BASE_PATH = "https://ip:port/svn/"
d1=collections.OrderedDict()
d1["deployer"] = ["ADMIN_AUTO_TRIGGER_SVN_SYNC_TO_ZENTAO", SVN_BASE_PATH + "xxx/yyy"]
return d1
没错,这里我们依然采用的是Jenkins + Ansible的触发方式,至于为什么会多此一举,对于zentao提供的ztcli.bat
脚本,请看如下测试结果:
- 直接CMD/Powershell命令行调用执行触发 - 成功。
- python命令行调用执行触发 - 成功。
- Ansible执行触发 - 成功。
- python脚本执行触发 - 失败 。
最后附上 ansible脚本内容:
---
- hosts: windows_3
vars:
REPOS_URL_INNER: "{{ RESPO_URL | b64encode }}"
tasks:
- name: exec the exe of zentao, the respoUrl is {{ REPOS_URL_INNER }}
win_shell: |
cd E:/xmapp/zentao/bin
E:/xmapp/php/php.exe E:/xmapp/zentao/bin/ztcli http://127.0.0.1:port/svn-syncLog-{{ REPOS_URL_INNER }}