tao.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. <?php
  2. /**
  3. * The tao file of repo module of ZenTaoPMS.
  4. *
  5. * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
  6. * @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
  7. * @author Zeng Gang<zenggang@easycorp.ltd>
  8. * @package repo
  9. * @link https://www.zentao.net
  10. */
  11. class repoTao extends repoModel
  12. {
  13. /**
  14. * 获取最后一次提交信息。
  15. * Get last revision.
  16. *
  17. * @param int $repoID
  18. * @access protected
  19. * @return string|false
  20. */
  21. protected function getLastRevision($repoID)
  22. {
  23. return $this->dao->select('time')->from(TABLE_REPOHISTORY)->where('repo')->eq($repoID)->orderBy('time_desc')->fetch('time');
  24. }
  25. /**
  26. * 根据id删除版本库信息。
  27. * Delete repo info by id.
  28. *
  29. * @param int $repoID
  30. * @access protected
  31. * @return void
  32. */
  33. protected function deleteInfoByID($repoID)
  34. {
  35. $this->dao->delete()->from(TABLE_REPOHISTORY)->where('repo')->eq($repoID)->exec();
  36. $this->dao->delete()->from(TABLE_REPOFILES)->where('repo')->eq($repoID)->exec();
  37. $this->dao->delete()->from(TABLE_REPOBRANCH)->where('repo')->eq($repoID)->exec();
  38. }
  39. /**
  40. * 处理版本库搜索查询。
  41. * Process repo search query.
  42. *
  43. * @param int $queryID
  44. * @access protected
  45. * @return string
  46. */
  47. protected function processSearchQuery($queryID)
  48. {
  49. $queryName = 'repoQuery';
  50. if($queryID)
  51. {
  52. $query = $this->loadModel('search')->getQuery($queryID);
  53. if($query)
  54. {
  55. $this->session->set($queryName, $query->sql);
  56. $this->session->set('repoForm', $query->form);
  57. }
  58. }
  59. if($this->session->$queryName == false) $this->session->set($queryName, ' 1 = 1');
  60. return $this->session->$queryName;
  61. }
  62. /**
  63. * 获取代码库分支的最后提交时间。
  64. * Get the last commit time of repo branch.
  65. *
  66. * @param int $repoID
  67. * @param string $revision
  68. * @param string $branch
  69. * @access protected
  70. * @return string
  71. */
  72. protected function getLatestCommitTime($repoID, $revision, $branch)
  73. {
  74. return $this->dao->select('time')->from(TABLE_REPOHISTORY)->alias('t1')
  75. ->beginIF($branch)->leftJoin(TABLE_REPOBRANCH)->alias('t2')->on('t1.id=t2.revision')->fi()
  76. ->where('t1.repo')->eq($repoID)
  77. ->beginIF($revision != 'HEAD')->andWhere('t1.revision')->eq($revision)->fi()
  78. ->beginIF($branch)->andWhere('t2.branch')->eq($branch)->fi()
  79. ->orderBy('time desc')
  80. ->fetch('time');
  81. }
  82. /**
  83. * 解析提交信息中的任务信息。
  84. * Parse task info from commit message.
  85. *
  86. * @param string $comment
  87. * @param array $rules
  88. * @param array $actions
  89. * @access protected
  90. * @return array
  91. */
  92. protected function parseTaskComment($comment, $rules, &$actions)
  93. {
  94. $tasks = array();
  95. preg_match_all("/{$rules['startTaskReg']}/i", $comment, $matches);
  96. if($matches[0])
  97. {
  98. foreach($matches[4] as $i => $idList)
  99. {
  100. preg_match_all('/\d+/', $idList, $idMatches);
  101. foreach($idMatches[0] as $id)
  102. {
  103. $tasks[$id] = $id;
  104. $actions['task'][$id]['start']['consumed'] = $matches[11][$i];
  105. $actions['task'][$id]['start']['left'] = $matches[17][$i];
  106. }
  107. }
  108. }
  109. preg_match_all("/{$rules['effortTaskReg']}/i", $comment, $matches);
  110. if($matches[0])
  111. {
  112. foreach($matches[4] as $i => $idList)
  113. {
  114. preg_match_all('/\d+/', $idList, $idMatches);
  115. foreach($idMatches[0] as $id)
  116. {
  117. $tasks[$id] = $id;
  118. $actions['task'][$id]['effort']['consumed'] = $matches[11][$i];
  119. $actions['task'][$id]['effort']['left'] = $matches[17][$i];
  120. }
  121. }
  122. }
  123. preg_match_all("/{$rules['finishTaskReg']}/i", $comment, $matches);
  124. if($matches[0])
  125. {
  126. foreach($matches[4] as $i => $idList)
  127. {
  128. preg_match_all('/\d+/', $idList, $idMatches);
  129. foreach($idMatches[0] as $id)
  130. {
  131. $tasks[$id] = $id;
  132. $actions['task'][$id]['finish']['consumed'] = $matches[11][$i];
  133. }
  134. }
  135. }
  136. return $tasks;
  137. }
  138. /**
  139. * 解析提交信息中的Bug信息。
  140. * Parse bug info from commit message.
  141. *
  142. * @param string $comment
  143. * @param array $rules
  144. * @param array $actions
  145. * @access protected
  146. * @return array
  147. */
  148. protected function parseBugComment($comment, $rules, &$actions)
  149. {
  150. $bugs = array();
  151. preg_match_all("/{$rules['resolveBugReg']}/i", $comment, $matches);
  152. if($matches[0])
  153. {
  154. foreach($matches[4] as $idList)
  155. {
  156. preg_match_all('/\d+/', $idList, $idMatches);
  157. foreach($idMatches[0] as $id)
  158. {
  159. $bugs[$id] = $id;
  160. $actions['bug'][$id]['resolve'] = array();
  161. }
  162. }
  163. }
  164. return $bugs;
  165. }
  166. /**
  167. * 构造文件树结构。
  168. * Build file tree.
  169. *
  170. * @param array $allFiles
  171. * @access public
  172. * @return array
  173. */
  174. public function buildFileTree($allFiles = array())
  175. {
  176. $files = array();
  177. foreach($allFiles as $file)
  178. {
  179. $fileName = explode('/', $file);
  180. $parent = '';
  181. foreach($fileName as $path)
  182. {
  183. if($path === '') continue;
  184. $parentID = $parent == '' ? '0' : $files[$parent]['id'];
  185. $parent .= $parent == '' ? $path : '/' . $path;
  186. if(!isset($files[$parent]))
  187. {
  188. $id = $this->encodePath($parent);
  189. $files[$parent] = array(
  190. 'id' => $id,
  191. 'parent' => $parentID,
  192. 'name' => $path,
  193. 'path' => $parent,
  194. 'key' => $id,
  195. );
  196. }
  197. }
  198. }
  199. sort($files);
  200. return $this->buildTree($files);
  201. }
  202. /**
  203. * Build tree.
  204. *
  205. * @param array $files
  206. * @param string $parent
  207. * @access public
  208. * @return array
  209. */
  210. public function buildTree($files = array(), $parent = '0')
  211. {
  212. $treeList = array();
  213. $key = 0;
  214. $pathName = array();
  215. $fileName = array();
  216. foreach($files as $key => $file)
  217. {
  218. if ($file['parent'] === $parent)
  219. {
  220. $treeList[$key] = $file;
  221. $fileName[$key] = $file['name'];
  222. /* Default value is '~', because his ascii code is large in string. */
  223. $pathName[$key] = '~';
  224. $children = $this->buildTree($files, $file['id']);
  225. if($children)
  226. {
  227. $treeList[$key]['children'] = $children;
  228. $fileName[$key] = '';
  229. $pathName[$key] = $file['path'];
  230. }
  231. $key++;
  232. }
  233. }
  234. array_multisort($pathName, SORT_ASC, $fileName, SORT_ASC, $treeList);
  235. return $treeList;
  236. }
  237. /**
  238. * 根据url获取匹配得版本库。
  239. * Get matched repos by url.
  240. *
  241. * @param string $url
  242. * @access protected
  243. * @return array
  244. */
  245. protected function getMatchedReposByUrl($url)
  246. {
  247. /* Convert to id by url. */
  248. $this->loadModel('gitlab');
  249. $matches = array();
  250. $parsedUrl = parse_url($url);
  251. $isSSH = $parsedUrl['scheme'] == 'ssh';
  252. $baseURL = $parsedUrl['scheme'] . '://' . $parsedUrl['host'] . (isset($parsedUrl['port']) ? ":{$parsedUrl['port']}" : '');
  253. $url = str_replace('https://', 'http://', strtolower($url));
  254. $gitlabs = $this->loadModel('pipeline')->getList('gitlab');
  255. foreach($gitlabs as $gitlabID => $gitlab)
  256. {
  257. if((!$isSSH && $gitlab->url != $baseURL) || ($isSSH && strpos($gitlab->url, $parsedUrl['host']) === false))
  258. {
  259. unset($gitlabs[$gitlabID]);
  260. continue;
  261. }
  262. $projects = $this->gitlab->apiGetProjects($gitlabID);
  263. foreach($projects as $project)
  264. {
  265. $urlToRepo = str_replace('https://', 'http://', strtolower($project->http_url_to_repo));
  266. if((!$isSSH && $urlToRepo == $url) || ($isSSH && strtolower($project->ssh_url_to_repo) == $url)) $matches[] = array('gitlab' => $gitlabID, 'project' => $project->id);
  267. }
  268. }
  269. return $matches;
  270. }
  271. /**
  272. * Copy svn dir.
  273. *
  274. * @param int $repoID
  275. * @param string $copyfromPath
  276. * @param string $copyfromRev
  277. * @param string $dirPath
  278. * @access protected
  279. * @return void
  280. */
  281. protected function copySvnDir($repoID, $copyfromPath, $copyfromRev, $dirPath)
  282. {
  283. $copyFiles = $this->dao->select('t1.*')->from(TABLE_REPOFILES)->alias('t1')
  284. ->leftJoin(TABLE_REPOHISTORY)->alias('t2')->on('t1.revision = t2.id')
  285. ->where('t1.repo')->eq($repoID)
  286. ->andWhere('t2.revision+0')->le($copyfromRev)
  287. ->andWhere('t1.path')->like("{$copyfromPath}%")
  288. ->fetchAll();
  289. foreach($copyFiles as $copyFile)
  290. {
  291. unset($copyFile->id);
  292. $copyFile->path = substr_replace($copyFile->path, $dirPath, 0, strlen($copyfromPath));
  293. $copyFile->parent = substr_replace($copyFile->parent, $dirPath, 0, strlen($copyfromPath));
  294. if($copyFile->path == $dirPath) continue;
  295. $this->dao->insert(TABLE_REPOFILES)->data($copyFile)->exec();
  296. }
  297. }
  298. }