diff --git a/config/filter.php b/config/filter.php index 1b2e6f2ec5..b0215c07eb 100644 --- a/config/filter.php +++ b/config/filter.php @@ -147,6 +147,7 @@ $filter->user->edit = new stdclass(); $filter->webhook->bind = new stdclass(); $filter->user->ajaxgetmore = new stdclass(); $filter->repo->ajaxsynccommit = new stdclass(); +$filter->repo->apigetrepobyurl = new stdclass(); $filter->search->index = new stdclass(); $filter->gitlab->webhook = new stdclass(); $filter->gitlab->importissue = new stdclass(); @@ -365,6 +366,8 @@ $filter->repo->default->get['repoPath'] = 'reg::base64'; $filter->repo->default->get['path'] = 'reg::base64'; $filter->repo->default->get['entry'] = 'reg::base64'; +$filter->repo->apigetrepobyurl->get['url'] = 'reg::any'; + $filter->repo->default->cookie['repoBranch'] = 'reg::any'; $filter->repo->diff->cookie['arrange'] = 'reg::word'; $filter->repo->diff->cookie['repoPairs'] = 'array'; diff --git a/db/update16.0.beta1.sql b/db/update16.0.beta1.sql index 102e159f6b..4146dd9522 100644 --- a/db/update16.0.beta1.sql +++ b/db/update16.0.beta1.sql @@ -8,4 +8,10 @@ ALTER TABLE `zt_bug` ADD `mr` mediumint(8) unsigned NOT NULL AFTER `repo`; UPDATE `zt_grouppriv` SET `method`='addReview' where `module`='mr' and `method`='addBug'; + +ALTER TABLE `zt_repo` ADD `preMerge` enum('0','1') COLLATE 'utf8_general_ci' NOT NULL DEFAULT '0' AFTER `extra`; +ALTER TABLE `zt_repo` ADD `job` mediumint unsigned NOT NULL AFTER `preMerge`; +ALTER TABLE `zt_job` ADD `buildDir` text COLLATE 'utf8_general_ci' NULL AFTER `lastTag`; +ALTER TABLE `zt_mr` ADD `synced` enum('0','1') COLLATE 'utf8_general_ci' NOT NULL DEFAULT '1'; +ALTER TABLE `zt_mr` ADD `diffs` longtext COLLATE 'utf8_general_ci' NULL AFTER `synced`; ALTER TABLE `zt_mr` ADD `removeSourceBranch` ENUM('0','1') NOT NULL DEFAULT '0' AFTER `compileStatus`; diff --git a/db/zentao.sql b/db/zentao.sql index 41ec30e1e5..70620b2195 100644 --- a/db/zentao.sql +++ b/db/zentao.sql @@ -747,6 +747,7 @@ CREATE TABLE IF NOT EXISTS `zt_mr` ( `jobID` mediumint(8) unsigned NOT NULL, `compileID` mediumint(8) unsigned NOT NULL, `compileStatus` char(30) NOT NULL, + `removeSourceBranch` enum('0','1') NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- DROP TABLE IF EXISTS `zt_mrapproval`; diff --git a/module/gitlab/control.php b/module/gitlab/control.php index ed6176c46e..d603e3c9ed 100644 --- a/module/gitlab/control.php +++ b/module/gitlab/control.php @@ -945,8 +945,12 @@ class gitlab extends control $this->session->set('gitlabTagList', $this->app->getURI(true)); $keyword = fixer::input('post')->setDefault('keyword', '')->get('keyword'); + /* Pager. */ + $this->app->loadClass('pager', $static = true); + $pager = new pager($recTotal, $recPerPage, $pageID); + $tagList = array(); - $result = $this->gitlab->apiGetTags($gitlabID, $projectID, $orderBy, $keyword); + $result = $this->gitlab->apiGetTags($gitlabID, $projectID, $orderBy, $keyword, $pager); foreach($result as $gitlabTag) { $tag = new stdClass(); @@ -957,12 +961,6 @@ class gitlab extends control $tagList[] = $tag; } - /* Pager. */ - $this->app->loadClass('pager', $static = true); - $recTotal = count($tagList); - $pager = new pager($recTotal, $recPerPage, $pageID); - $tagList = array_chunk($tagList, $pager->recPerPage); - $this->view->gitlab = $this->gitlab->getByID($gitlabID); $this->view->pager = $pager; $this->view->title = $this->lang->gitlab->common . $this->lang->colon . $this->lang->gitlab->browseTag; @@ -970,7 +968,7 @@ class gitlab extends control $this->view->projectID = $projectID; $this->view->keyword = $keyword; $this->view->project = $this->gitlab->apiGetSingleProject($gitlabID, $projectID); - $this->view->gitlabTagList = empty($tagList) ? $tagList: $tagList[$pageID - 1]; + $this->view->gitlabTagList = $tagList; $this->view->orderBy = $orderBy; $this->display(); } diff --git a/module/gitlab/model.php b/module/gitlab/model.php index 1a63acf70b..0743d6277c 100644 --- a/module/gitlab/model.php +++ b/module/gitlab/model.php @@ -1466,10 +1466,11 @@ class gitlabModel extends model * @param int $projectID * @param string $orderBy * @param string $keyword + * @param object $pager * @access public * @return object */ - public function apiGetTags($gitlabID, $projectID, $orderBy = '', $keyword = '') + public function apiGetTags($gitlabID, $projectID, $orderBy = '', $keyword = '', $pager = null) { $apiRoot = $this->getApiRoot($gitlabID); @@ -1482,8 +1483,24 @@ class gitlabModel extends model if($keyword) $apiRoot .= "&search={$keyword}"; - $url = sprintf($apiRoot, "/projects/{$projectID}/repository/tags"); - return json_decode(commonModel::http($url)); + if(!$pager) + { + $url = sprintf($apiRoot, "/projects/{$projectID}/repository/tags"); + return json_decode(commonModel::http($url)); + } + else + { + $apiRoot .= "&per_page={$pager->recPerPage}&page={$pager->pageID}"; + $url = sprintf($apiRoot, "/projects/{$projectID}/repository/tags"); + $result = commonModel::httpWithHeader($url); + + $header = $result['header']; + $pager->setRecTotal($header['X-Total']); + $pager->setPageTotal(); + if($pager->pageID > $pager->pageTotal) $pager->setPageID($pager->pageTotal); + + return json_decode($result['body']); + } } /** diff --git a/module/group/lang/resource.php b/module/group/lang/resource.php index fafd69beb0..9fb49c0a5e 100644 --- a/module/group/lang/resource.php +++ b/module/group/lang/resource.php @@ -1043,20 +1043,21 @@ $lang->resource->automation->browse = 'browse'; $lang->automation->methodOrder[0] = 'browse'; -$lang->resource->repo = new stdclass(); -$lang->resource->repo->browse = 'browseAction'; -$lang->resource->repo->view = 'view'; -$lang->resource->repo->log = 'log'; -$lang->resource->repo->revision = 'revisionAction'; -$lang->resource->repo->blame = 'blameAction'; -$lang->resource->repo->create = 'createAction'; -$lang->resource->repo->edit = 'editAction'; -$lang->resource->repo->delete = 'delete'; -$lang->resource->repo->showSyncCommit = 'showSyncCommit'; -$lang->resource->repo->diff = 'diffAction'; -$lang->resource->repo->download = 'downloadAction'; -$lang->resource->repo->maintain = 'maintain'; -$lang->resource->repo->setRules = 'setRules'; +$lang->resource->repo = new stdclass(); +$lang->resource->repo->browse = 'browseAction'; +$lang->resource->repo->view = 'view'; +$lang->resource->repo->log = 'log'; +$lang->resource->repo->revision = 'revisionAction'; +$lang->resource->repo->blame = 'blameAction'; +$lang->resource->repo->create = 'createAction'; +$lang->resource->repo->edit = 'editAction'; +$lang->resource->repo->delete = 'delete'; +$lang->resource->repo->showSyncCommit = 'showSyncCommit'; +$lang->resource->repo->diff = 'diffAction'; +$lang->resource->repo->download = 'downloadAction'; +$lang->resource->repo->maintain = 'maintain'; +$lang->resource->repo->setRules = 'setRules'; +$lang->resource->repo->apiGetRepoByUrl = 'apiGetRepoByUrl'; $lang->repo->methodOrder[5] = 'create'; $lang->repo->methodOrder[10] = 'edit'; @@ -1071,6 +1072,7 @@ $lang->repo->methodOrder[50] = 'revision'; $lang->repo->methodOrder[55] = 'blame'; $lang->repo->methodOrder[60] = 'download'; $lang->repo->methodOrder[65] = 'setRules'; +$lang->repo->methodOrder[70] = 'apiGetRepoByUrl'; $lang->resource->ci = new stdclass(); $lang->resource->ci->commitResult = 'commitResult'; diff --git a/module/mr/config.php b/module/mr/config.php index 15d15a4851..e3c53e3e05 100644 --- a/module/mr/config.php +++ b/module/mr/config.php @@ -12,6 +12,9 @@ $config->mr->edit->requiredFields = 'gitlabID,sourceProject,sourceBranch,targetP $config->mr->editor = new stdclass(); $config->mr->editor->diff = array('id' => 'commentText', 'tools' => 'simpleTools'); +$config->mr->apicreate = new stdclass(); +$config->mr->apicreate->requiredFields = 'repoID,sourceBranch,targetBranch,diffs,mergeStatus,hasNoConflict'; + $config->mr->maps = new stdclass; $config->mr->maps->sync = array(); $config->mr->maps->sync['title'] = 'title|field|'; diff --git a/module/mr/control.php b/module/mr/control.php index e8c2423a20..b62d4e450a 100644 --- a/module/mr/control.php +++ b/module/mr/control.php @@ -84,6 +84,21 @@ class mr extends control $this->display(); } + /** + * Create MR function by api. + * + * @access public + * @return void + */ + public function apiCreate() + { + if($_POST) + { + $result = $this->mr->apiCreate(); + return $this->send($result); + } + } + /** * Edit MR function. * diff --git a/module/mr/model.php b/module/mr/model.php index d934f051b7..c27f908279 100644 --- a/module/mr/model.php +++ b/module/mr/model.php @@ -178,6 +178,71 @@ class mrModel extends model return array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => helper::createLink('mr', 'browse')); } + /** + * Create MR function by api. + * + * @access public + * @return int|bool|object + */ + public function apiCreate() + { + $postData = fixer::input('post') + ->setDefault('url,sourceBranch,targetBranch,diff,mergeStatus,hasNoConflict', '') + ->get(); + + $repo = $this->loadModel('repo')->getRepoByUrl($postData->url); + if(!$repo || $repo->result != 'fail') return false; + $repo = (object)$repo->data; + + /* Process and insert mr data. */ + $MR = new stdClass(); + $MR->gitlabID = $repo->client; + $MR->sourceProject = $repo->path; + $MR->sourceBranch = $postData->sourceBranch; + $MR->targetProject = $repo->path; + $MR->targetBranch = $postData->taretBranch; + $MR->diffs = $postData->diff; + $MR->title = 'Merge request'; + $MR->repoID = $repo->id; + $MR->jobID = $postData->jobID; + $MR->synced = '0'; + $MR->needCI = '1'; + $MR->approvalStatus = 'approved'; + $MR->hasNoConflict = $postData->hasNoConflict ? '1' : '0'; + $MR->mergeStatus = $postData->mergeStatus ? 'can_be_merged' : 'cannot_be_merged'; + $MR->createdBy = $this->app->user->account; + $MR->createdDate = date('Y-m-d H:i:s'); + + $this->dao->insert(TABLE_MR)->data($MR, $this->config->mr->create->skippedFields) + ->batchCheck($this->config->mr->apicreate->requiredFields, 'notempty') + ->checkIF($MR->needCI, 'jobID', 'notempty') + ->autoCheck() + ->exec(); + if(dao::isError()) return false; + + /* Exec Job */ + if($MR->hasNoConflict == '1' && $MR->mergeStatus == 'can_be_merged' && $MR->jobID) + { + $MRID = $this->dao->lastInsertId(); + $pipeline = $this->loadModel('job')->exec($MR->jobID); + if(!empty($pipeline->queue)) + { + $newMR = new stdClass(); + $compile = $this->loadModel('compile')->getByQueue($pipeline->queue); + $newMR->compileID = $compile->id; + $newMR->compileStatus = $compile->status; + + /* Update MR in Zentao database. */ + $this->dao->update(TABLE_MR)->data($newMR) + ->where('id')->eq($MRID) + ->autoCheck() + ->exec(); + if(dao::isError()) return false; + } + } + return true; + } + /** * Edit MR function. * diff --git a/module/mr/view/view.html.php b/module/mr/view/view.html.php index 55f984cbaa..55bf2c2f1c 100644 --- a/module/mr/view/view.html.php +++ b/module/mr/view/view.html.php @@ -74,7 +74,8 @@ mr->MRHasConflicts; ?> - has_conflicts ? $lang->mr->hasConflicts : $lang->mr->hasNoConflict);?> + synced === '1' ? $rawMR->has_conflicts : (bool)$MR->hasNoConflict; ?> + mr->hasConflicts : $lang->mr->hasNoConflict);?> mr->description;?> @@ -96,10 +97,10 @@
- approvalStatus != 'approved' or ($MR->compileID !=0 and $MR->compileStatus != 'success')) ? ' disabled' : ''; ?> + approvalStatus != 'approved' or ($MR->compileID != 0 and $MR->compileStatus != 'success')) ? ' disabled' : ''; ?> state == 'opened' and !$rawMR->has_conflicts) common::printIcon('mr', 'accept', "mr=$MR->id", $MR, 'button', 'flow', 'hiddenwin', 'mergeButton btn', false, $acceptDisabled, $lang->mr->acceptMR);?> state == 'opened'): ?> - has_conflicts or ($MR->compileID !=0 and $MR->compileStatus != 'success') or $MR->approvalStatus == 'approved'):?> + has_conflicts or ($MR->compileID != 0 and $MR->compileStatus != 'success') or $MR->approvalStatus == 'approved'):?> id&action=approve", $MR, 'button', 'ok', 'hiddenwin', 'mergeButton', true, 'disabled', $lang->mr->approve);?> id&action=approve", $MR, 'button', 'ok', 'hiddenwin', 'mergeButton btn iframe showinonlybody', true, '', $lang->mr->approve);?> diff --git a/module/repo/control.php b/module/repo/control.php index f021d47d62..7875d8b64a 100644 --- a/module/repo/control.php +++ b/module/repo/control.php @@ -1177,4 +1177,24 @@ class repo extends control echo html::select('product', array('') + $productPairs, key($productPairs), "class='form-control chosen'"); } + /** + * API: get repo by url. + * + * @param string $type gitlab + * @access public + * @return void + */ + public function apiGetRepoByUrl() + { + $url = urldecode($this->post->repoUrl); + $result = $this->repo->getRepoByUrl($url); + if($result['result'] == 'fail') return $this->send($result); + + $repo = $result['data']; + $fileServer = new stdclass(); + $fileServer->fileServerUrl = $repo->fileServerUrl; + $fileServer->fileServerAccount = $repo->fileServerAccount; + $fileServer->fileServerPassword = $repo->fileServerPassword; + return $this->send($fileServer); + } } diff --git a/module/repo/lang/en.php b/module/repo/lang/en.php index e5fa02bbc2..75d213ae5e 100644 --- a/module/repo/lang/en.php +++ b/module/repo/lang/en.php @@ -24,6 +24,7 @@ $lang->repo->repo = 'Repository'; $lang->repo->parent = 'Parent File'; $lang->repo->branch = 'Branch'; $lang->repo->addWebHook = 'Add Webhook'; +$lang->repo->apiGetRepoByUrl = 'API: Get repo by URL'; $lang->repo->browseAction = 'Browse Repo'; $lang->repo->createAction = 'Create Repo'; diff --git a/module/repo/lang/zh-cn.php b/module/repo/lang/zh-cn.php index 5283beb6f4..301470e473 100644 --- a/module/repo/lang/zh-cn.php +++ b/module/repo/lang/zh-cn.php @@ -24,6 +24,7 @@ $lang->repo->repo = '代码库'; $lang->repo->parent = '父文件夹'; $lang->repo->branch = '分支'; $lang->repo->addWebHook = '添加Webhook'; +$lang->repo->apiGetRepoByUrl = '接口:通过URL获取版本库'; $lang->repo->browseAction = '浏览版本库'; $lang->repo->createAction = '创建版本库'; diff --git a/module/repo/model.php b/module/repo/model.php index a69ce07eab..df9beb7264 100644 --- a/module/repo/model.php +++ b/module/repo/model.php @@ -396,6 +396,76 @@ class repoModel extends model return $repo; } + /** + * Get repo by url. + * + * @param string $url + * @access public + * @return array + */ + public function getRepoByUrl($url) + { + if(empty($url)) return array('result' => 'fail', 'message' => 'Url is empty.'); + + $parsedUrl = parse_url($url); + + $isSSH = $parsedUrl['scheme'] == 'ssh'; + $baseURL = $parsedUrl['scheme'] . '://' . $parsedUrl['host'] . (isset($parsedUrl['port']) ? ":{$parsedUrl['port']}" : ''); + + /* Get gitlabs by URL. */ + $gitlabs = $this->dao->select('*')->from(TABLE_PIPELINE)->where('type')->eq('gitlab') + ->beginIF($isSSH)->andWhere('url')->like("%{$parsedUrl['host']}%")->fi() + ->beginIF(!$isSSH)->andWhere('url')->eq($baseURL)->fi() + ->orderBy('id_desc') + ->fetchAll('id'); + + /* Convert to id by url. */ + $this->loadModel('gitlab'); + $matched = new stdclass(); + $matched->gitlab = 0; + $matched->project = 0; + foreach($gitlabs as $gitlabID => $gitlab) + { + $projects = $this->gitlab->apiGetProjects($gitlabID); + foreach($projects as $project) + { + if((!$isSSH and $project->http_url_to_repo == $url) or ($isSSH and $project->ssh_url_to_repo == $url)) + { + $matched->gitlab = $gitlabID; + $matched->project = $project->id; + break; + } + } + } + if(empty($matched->gitlab) or empty($matched->project)) return array('result' => 'fail', 'message' => 'No matched gitlab.'); + + $matchedRepos = $this->dao->select('*')->from(TABLE_REPO)->where('SCM')->eq('Gitlab') + ->andWhere('client')->eq($matched->gitlab) + ->andWhere('path')->eq($matched->project) + ->andWhere('deleted')->eq('0') + ->orderBy('id_desc') + ->fetchAll(); + if(empty($matchedRepos)) return array('result' => 'fail', 'message' => 'No matched gitlab.'); + + $matchedRepo = ''; + foreach($matchedRepos as $repo) + { + if(!empty($repo->preMerge)) + { + $matchedRepo = $repo; + break; + } + } + if(empty($matchedRepo)) return array('result' => 'fail', 'message' => 'Matched gitlab is not open pre merge.'); + if(empty($matchedRepo->job)) return array('result' => 'fail', 'message' => 'No linked job.'); + + $job = $this->dao->select('*')->from(TABLE_JOB)->where('id')->eq($matchedRepo->job)->andWhere('deleted')->eq(0)->fetch(); + if(empty($job)) return array('result' => 'fail', 'message' => 'Linked job is not exists.'); + + $matchedRepo->job = $job; + return array('result' => 'success', 'data' => $matchedRepo); + } + /** * Get by id list. *