From 3f63404953650aa7f79d80bb05dc1b2845cf5d4e Mon Sep 17 00:00:00 2001 From: liumengyi Date: Mon, 6 Mar 2023 06:09:13 +0000 Subject: [PATCH 1/8] * Finish task #86258. --- module/common/lang/de.php | 1 + module/common/lang/en.php | 1 + module/common/lang/fr.php | 1 + module/common/lang/menu.php | 6 ++++-- module/common/lang/zh-cn.php | 1 + module/execution/lang/de.php | 1 - module/execution/lang/en.php | 1 - module/execution/lang/fr.php | 1 - module/execution/lang/zh-cn.php | 1 - module/project/config.php | 2 +- module/project/model.php | 2 +- 11 files changed, 10 insertions(+), 8 deletions(-) diff --git a/module/common/lang/de.php b/module/common/lang/de.php index 8c4350fb04..1908d37e7e 100644 --- a/module/common/lang/de.php +++ b/module/common/lang/de.php @@ -209,6 +209,7 @@ $lang->stage->type = 'Stage Type'; $lang->stage->list = 'Stage List'; $lang->stage->percent = 'Workload Ratio'; $lang->execution->list = "{$lang->executionCommon} List"; +$lang->execution->CFD = "Cumulative Flow Diagrams"; $lang->kanban->common = 'Kanban'; $lang->backup->common = 'Backup'; $lang->action->trash = 'Recycle'; diff --git a/module/common/lang/en.php b/module/common/lang/en.php index 296662eff4..9ea5255c9b 100644 --- a/module/common/lang/en.php +++ b/module/common/lang/en.php @@ -209,6 +209,7 @@ $lang->stage->type = 'Stage Type'; $lang->stage->list = 'Stage List'; $lang->stage->percent = 'Workload Ratio'; $lang->execution->list = "{$lang->executionCommon} List"; +$lang->execution->CFD = "Cumulative Flow Diagrams"; $lang->kanban->common = 'Kanban'; $lang->backup->common = 'Backup'; $lang->action->trash = 'Recycle'; diff --git a/module/common/lang/fr.php b/module/common/lang/fr.php index 03d20b96d7..d85242c5c6 100644 --- a/module/common/lang/fr.php +++ b/module/common/lang/fr.php @@ -209,6 +209,7 @@ $lang->stage->type = 'Stage Type'; $lang->stage->list = 'Stage List'; $lang->stage->percent = 'Workload Ratio'; $lang->execution->list = "{$lang->executionCommon} List"; +$lang->execution->CFD = "Cumulative Flow Diagrams"; $lang->kanban->common = 'Kanban'; $lang->backup->common = 'Backup'; $lang->action->trash = 'Recycle'; diff --git a/module/common/lang/menu.php b/module/common/lang/menu.php index 35a2ae034c..c9904f160c 100644 --- a/module/common/lang/menu.php +++ b/module/common/lang/menu.php @@ -418,6 +418,7 @@ $lang->project->noMultiple->scrum->menu->settings = $lang->scrum->menu->settin $lang->project->noMultiple->kanban = new stdclass(); $lang->project->noMultiple->kanban->menu = new stdclass(); $lang->project->noMultiple->kanban->menu->kanban = array('link' => "{$lang->kanban->common}|execution|kanban|executionID=%s"); +$lang->project->noMultiple->kanban->menu->CFD = array('link' => "{$lang->execution->CFD}|execution|cfd|executionID=%s"); $lang->project->noMultiple->kanban->menu->build = $lang->kanbanProject->menu->build; $lang->project->noMultiple->kanban->menu->settings = $lang->kanbanProject->menu->settings; @@ -438,8 +439,9 @@ $lang->project->noMultiple->scrum->menuOrder[50] = 'dynamic'; $lang->project->noMultiple->scrum->menuOrder[55] = 'settings'; $lang->project->noMultiple->kanban->menuOrder[5] = 'kanban'; -$lang->project->noMultiple->kanban->menuOrder[10] = 'build'; -$lang->project->noMultiple->kanban->menuOrder[15] = 'settings'; +$lang->project->noMultiple->kanban->menuOrder[10] = 'CFD'; +$lang->project->noMultiple->kanban->menuOrder[15] = 'build'; +$lang->project->noMultiple->kanban->menuOrder[20] = 'settings'; /* QA menu.*/ $lang->qa->menu = new stdclass(); diff --git a/module/common/lang/zh-cn.php b/module/common/lang/zh-cn.php index 35824d6254..6e5df849d5 100644 --- a/module/common/lang/zh-cn.php +++ b/module/common/lang/zh-cn.php @@ -209,6 +209,7 @@ $lang->stage->type = '阶段类型'; $lang->stage->list = '阶段列表'; $lang->stage->percent = '工作量占比'; $lang->execution->list = "{$lang->executionCommon}列表"; +$lang->execution->CFD = "累积流图"; $lang->kanban->common = '看板'; $lang->backup->common = '备份'; $lang->action->trash = '回收站'; diff --git a/module/execution/lang/de.php b/module/execution/lang/de.php index 993b5092e6..b8858ca746 100644 --- a/module/execution/lang/de.php +++ b/module/execution/lang/de.php @@ -227,7 +227,6 @@ $lang->execution->build = 'Builds'; $lang->execution->testtask = 'Testaufgaben'; $lang->execution->burn = 'Burndown'; $lang->execution->computeBurn = 'Aktualisieren'; -$lang->execution->CFD = 'Cumulative Flow diagrams'; $lang->execution->computeCFD = 'Compute Cumulative Flow diagrams'; $lang->execution->burnData = 'Burndown Daten'; $lang->execution->fixFirst = 'Bearbeite Mannstunden des ersten Tags'; diff --git a/module/execution/lang/en.php b/module/execution/lang/en.php index 4a54020911..78b9afe79a 100644 --- a/module/execution/lang/en.php +++ b/module/execution/lang/en.php @@ -227,7 +227,6 @@ $lang->execution->build = 'Build List'; $lang->execution->testtask = 'Request'; $lang->execution->burn = 'Burndown'; $lang->execution->computeBurn = 'Update'; -$lang->execution->CFD = 'Cumulative Flow diagrams'; $lang->execution->computeCFD = 'Compute Cumulative Flow diagrams'; $lang->execution->burnData = 'Burndown Data'; $lang->execution->fixFirst = 'Edit 1st-Day Estimates'; diff --git a/module/execution/lang/fr.php b/module/execution/lang/fr.php index edb6d956ed..968f605828 100644 --- a/module/execution/lang/fr.php +++ b/module/execution/lang/fr.php @@ -227,7 +227,6 @@ $lang->execution->build = 'Build List'; $lang->execution->testtask = 'Request'; $lang->execution->burn = 'Burndown'; $lang->execution->computeBurn = 'Update'; -$lang->execution->CFD = 'Cumulative Flow diagrams'; $lang->execution->computeCFD = 'Compute Cumulative Flow diagrams'; $lang->execution->burnData = 'Burndown Data'; $lang->execution->fixFirst = 'Edit 1st-Day Estimates'; diff --git a/module/execution/lang/zh-cn.php b/module/execution/lang/zh-cn.php index ed2fcaab23..8fae721ad2 100644 --- a/module/execution/lang/zh-cn.php +++ b/module/execution/lang/zh-cn.php @@ -227,7 +227,6 @@ $lang->execution->build = '所有版本'; $lang->execution->testtask = '测试单'; $lang->execution->burn = '燃尽图'; $lang->execution->computeBurn = '更新燃尽图'; -$lang->execution->CFD = '累积流图'; $lang->execution->computeCFD = '更新累积流图'; $lang->execution->burnData = '燃尽图数据'; $lang->execution->fixFirst = '修改首天工时'; diff --git a/module/project/config.php b/module/project/config.php index bb8ff5e92d..d8222aed4f 100644 --- a/module/project/config.php +++ b/module/project/config.php @@ -33,7 +33,7 @@ $config->project->sortFields->status = 'status'; $config->project->sortFields->budget = 'budget'; $config->project->multiple['project'] = ',qa,devops,doc,build,release,dynamic,settings,'; -$config->project->multiple['execution'] = ',task,kanban,burn,view,story,'; +$config->project->multiple['execution'] = ',task,kanban,burn,view,story,CFD,'; global $lang; $config->project->datatable = new stdclass(); diff --git a/module/project/model.php b/module/project/model.php index ce5b643326..790b51238d 100644 --- a/module/project/model.php +++ b/module/project/model.php @@ -2899,7 +2899,7 @@ class projectModel extends model $executionID = $this->dao->select('id')->from(TABLE_EXECUTION) ->where('project')->eq($projectID) ->andWhere('multiple')->eq('0') - ->andWhere('type')->eq('sprint') + ->andWhere('type')->in('kanban,sprint') ->andWhere('deleted')->eq('0') ->fetch('id'); } From 0a49668a08b7f36c0335ece380d12fee893baac1 Mon Sep 17 00:00:00 2001 From: liumengyi Date: Mon, 6 Mar 2023 06:44:26 +0000 Subject: [PATCH 2/8] * Finish task #86281. --- module/projectrelease/control.php | 1 + module/projectrelease/view/view.html.php | 10 +++++----- module/release/control.php | 1 + module/release/view/view.html.php | 10 +++++----- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/module/projectrelease/control.php b/module/projectrelease/control.php index 024a02e135..c80f2d03bc 100644 --- a/module/projectrelease/control.php +++ b/module/projectrelease/control.php @@ -326,6 +326,7 @@ class projectrelease extends control $this->view->bugPager = $bugPager; $this->view->leftBugPager = $leftBugPager; $this->view->builds = $this->loadModel('build')->getBuildPairs($release->product, 'all', 'withbranch|hasproject', 0, 'execution', '', false); + $this->view->summary = $this->product->summary($stories); if($this->app->getViewType() == 'json') { diff --git a/module/projectrelease/view/view.html.php b/module/projectrelease/view/view.html.php index 4276f1c144..040df9ab14 100644 --- a/module/projectrelease/view/view.html.php +++ b/module/projectrelease/view/view.html.php @@ -36,13 +36,13 @@
diff --git a/module/release/control.php b/module/release/control.php index dadffe8111..e5c264912a 100644 --- a/module/release/control.php +++ b/module/release/control.php @@ -254,6 +254,7 @@ class release extends control $this->view->bugPager = $bugPager; $this->view->leftBugPager = $leftBugPager; $this->view->builds = $this->loadModel('build')->getBuildPairs($release->product, 'all', 'withbranch|hasproject', 0, 'execution', '', false); + $this->view->summary = $this->product->summary($stories); if($this->app->getViewType() == 'json') { diff --git a/module/release/view/view.html.php b/module/release/view/view.html.php index cf7abb2bc2..583cc3eb2f 100644 --- a/module/release/view/view.html.php +++ b/module/release/view/view.html.php @@ -38,13 +38,13 @@
From f99fba7c50952ffdfd3d1d7e198fb68ae778699a Mon Sep 17 00:00:00 2001 From: wangyidong Date: Thu, 9 Mar 2023 14:12:13 +0800 Subject: [PATCH 3/8] * fix bug. --- module/editor/control.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/editor/control.php b/module/editor/control.php index 4186dee101..13d392ddd0 100644 --- a/module/editor/control.php +++ b/module/editor/control.php @@ -22,7 +22,7 @@ class editor extends control public function __construct($module = '', $method = '') { parent::__construct($module, $method); - if($this->app->getMethodName() != 'switch' and empty($this->config->global->editor)) $this->locate($this->createLink('dev', 'editor')); + if($this->app->getMethodName() != 'turnon' and empty($this->config->global->editor)) $this->locate($this->createLink('dev', 'editor')); } /** From cad1498860bc1956a71057b7e6fec83b40995a79 Mon Sep 17 00:00:00 2001 From: wangyidong Date: Thu, 9 Mar 2023 14:50:22 +0800 Subject: [PATCH 4/8] * fix bug for module list. --- module/editor/view/index.html.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/module/editor/view/index.html.php b/module/editor/view/index.html.php index 17fdfa33b9..0fd6e4e40a 100644 --- a/module/editor/view/index.html.php +++ b/module/editor/view/index.html.php @@ -39,7 +39,18 @@
- dev->tableList, $module, $module);?> + dev->tableList[$module])) + { + $moduleName = $lang->dev->tableList[$module]; + } + else + { + if(!isset($lang->{$module}->common)) $app->loadLang($module); + $moduleName = isset($lang->{$module}->common) ? $lang->{$module}->common : $module; + } + ?> From f28595bbac00cee0b84ad95cfbd0b1dcd112c4aa Mon Sep 17 00:00:00 2001 From: guofeilong Date: Thu, 9 Mar 2023 14:51:19 +0800 Subject: [PATCH 5/8] * Adjust code . --- www/js/my.full.js | 113 +++++++++++++++++++++++----------------------- 1 file changed, 57 insertions(+), 56 deletions(-) diff --git a/www/js/my.full.js b/www/js/my.full.js index 481bda0289..98f0533a10 100755 --- a/www/js/my.full.js +++ b/www/js/my.full.js @@ -8,12 +8,13 @@ */ function handleSaveFormDraft() { - if(config.currentMethod === 'login' || config.currentMethod.indexOf('edit') != -1 || config.currentMethod.indexOf('import') != -1) return; - setTimeout(function() { + if(config.currentMethod === 'login' || config.currentModule === 'repo' || config.currentMethod.indexOf('edit') != -1 || config.currentMethod.indexOf('import') != -1) return; + setTimeout(function() + { var form = $('.table-form').parent(); if(form.length) { - if($(form).attr('target') == 'hiddenwin') return; + if($(form).attr('target') == 'hiddenwin' && config.currentModule != 'program') return; var formDataID = config.currentMethod + '-' + config.currentModule + '-' + $(form).attr("id"); var formDataStored = $.zui.store.get(formDataID); if(formDataStored) @@ -29,7 +30,8 @@ name: 'undo', icon: 'undo', text: lang.resume, - action: function() { + action: function() + { var valueMultiple = {}; for(var i = 0; i < formDataStored.length; i++) { @@ -48,39 +50,39 @@ } else if((item.name.indexOf(']') != -1) && (item.name.indexOf('[') != -1)) { - var formItem = $('[id^=' + item.name.replace('[', '').replace(']', '') + ']'); + var formItem = $('[id^=' + item.name.replace('[', '').replace(']', '') + ']'); } else { /* var formItem = $('#' + item.name);*/ - var formItem = $('[id^=' + item.name + ']'); + var formItem = $('[id^=' + item.name + ']'); } var tagName = formItem.prop('tagName'); if(tagName === 'SELECT') { - formItem.val(item.value); - if($(formItem).hasClass('chosen')) - { - $(formItem).trigger('chosen:updated'); - } - else if($(formItem).hasClass('picker-select')) - { - if($(formItem).attr('multiple')) - { - var value = []; - if(!valueMultiple[item.name]) valueMultiple[item.name] = []; - valueMultiple[item.name].push(item.value); - $(formItem).data('zui.picker').setValue(valueMultiple[item.name]); - } - else - { - $(formItem).data('zui.picker').setValue(item.value); - } - } - } - else if(tagName === 'INPUT') - { + formItem.val(item.value); + if($(formItem).hasClass('chosen')) + { + $(formItem).trigger('chosen:updated'); + } + else if($(formItem).hasClass('picker-select')) + { + if($(formItem).attr('multiple')) + { + var value = []; + if(!valueMultiple[item.name]) valueMultiple[item.name] = []; + valueMultiple[item.name].push(item.value); + $(formItem).data('zui.picker').setValue(valueMultiple[item.name]); + } + else + { + $(formItem).data('zui.picker').setValue(item.value); + } + } + } + else if(tagName === 'INPUT') + { if($(formItem).attr('type') === 'checkbox') { $(formItem).prop('checked', true).trigger('change'); @@ -93,38 +95,37 @@ { formItem.val(item.value); } - } - else if(tagName === 'TEXTAREA' && $(formItem).hasClass('kindeditor')) - { + } + else if(tagName === 'TEXTAREA' && $(formItem).hasClass('kindeditor')) + { KindEditor.remove('#' + item.name); formItem.val(item.value); $(formItem).kindeditor(); - } - } - $.zui.store.remove(formDataID); - } - } - ], - onAction: function(name, action, messager) - { - $.zui.store.remove(formDataID); - } - }).show(); - } - form.on('input', function() - { + } + } + $.zui.store.remove(formDataID); + } + } + ], + onAction: function(name, action, messager) + { + $.zui.store.remove(formDataID); + } + }).show(); + } + form.on('input', function() + { $.zui.store.set(formDataID, $(form).serializeArray()); - - }).on('change', function() - { - $.zui.store.set(formDataID, $(form).serializeArray()); - }).on('success.form.zui', function(event, res) - { - if(res.result === 'success' || res.status === 'success') $.zui.store.remove(formDataID); - }) - } - }, 500); - } + }).on('change', function() + { + $.zui.store.set(formDataID, $(form).serializeArray()); + }).on('success.form.zui', function(event, res) + { + if(res.result === 'success' || res.status === 'success') $.zui.store.remove(formDataID); + }) + } + }, 500); + } handleSaveFormDraft(); /* Tab session */ From ff028238042ab25c52b416a466600a42b4f9dd38 Mon Sep 17 00:00:00 2001 From: guofeilong Date: Thu, 9 Mar 2023 15:50:20 +0800 Subject: [PATCH 6/8] * Adjust Code . --- module/dev/css/langitem.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/dev/css/langitem.css b/module/dev/css/langitem.css index 0feb0d824b..23aee1c77d 100644 --- a/module/dev/css/langitem.css +++ b/module/dev/css/langitem.css @@ -8,7 +8,7 @@ .flex-center {display: flex; justify-content: center; align-items: center;} /* menu-tree */ -.menu-tree {flex: 0 0 200px; background: #fff; padding: 10px 10px; overflow: hidden;} +.menu-tree {flex: 0 0 180px; background: #fff; padding: 10px 10px; overflow: hidden;} .menu-tree > .tree {padding-top: 20px;} .tree ul {margin-bottom: 0;} #menuTree > li.has-list > ul > li {padding-left: 10px;} From 2da060b17184bc5bf3e44a9c61011171ed3074e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9B=BE=E5=88=9A?= Date: Thu, 9 Mar 2023 08:05:10 +0000 Subject: [PATCH 7/8] Gitlab optimize --- lib/scm/gitlab.class.php | 86 ++++++++--- module/common/model.php | 53 ++++--- module/compile/model.php | 18 ++- module/gitlab/model.php | 52 ++++++- module/jenkins/control.php | 6 +- module/jenkins/model.php | 62 +++++++- .../jenkins/view/ajaxgetjenkinstasks.html.php | 96 +++++++++++++ module/job/control.php | 6 +- module/job/css/create.css | 5 + module/job/js/create.js | 40 +++--- module/job/view/create.html.php | 8 +- module/mr/control.php | 35 ++++- module/mr/model.php | 19 ++- module/repo/control.php | 43 +++++- module/repo/css/log.css | 1 + module/repo/js/log.js | 2 +- module/repo/model.php | 134 +++++++++++++++++- module/repo/view/:w | 104 ++++++++++++++ module/repo/view/log.html.php | 9 ++ 19 files changed, 684 insertions(+), 95 deletions(-) create mode 100644 module/jenkins/view/ajaxgetjenkinstasks.html.php create mode 100644 module/repo/view/:w diff --git a/lib/scm/gitlab.class.php b/lib/scm/gitlab.class.php index 200bf61b15..799b674608 100644 --- a/lib/scm/gitlab.class.php +++ b/lib/scm/gitlab.class.php @@ -549,10 +549,11 @@ class gitlab * @param string $version * @param int $count * @param string $branch + * @param bool $getFile * @access public * @return array */ - public function getCommits($version = '', $count = 0, $branch = '') + public function getCommits($version = '', $count = 0, $branch = '', $getFile = false) { if(!scm::checkRevision($version)) return array(); $api = "commits"; @@ -620,7 +621,7 @@ class gitlab $log->time = date('Y-m-d H:i:s', strtotime($commit->created_at)); $commits[$commit->id] = $log; - $files[$commit->id] = $this->getFilesByCommit($log->revision); + if($getFile) $files[$commit->id] = $this->getFilesByCommit($log->revision); } return array('commits' => $commits, 'files' => $files); @@ -653,10 +654,12 @@ class gitlab * @param string $fromRevision * @param string $toRevision * @param int $perPage + * @param int $page + * @param bool $getUrl * @access public * @return array */ - public function getCommitsByPath($path, $fromRevision = '', $toRevision = '', $perPage = 0) + public function getCommitsByPath($path, $fromRevision = '', $toRevision = '', $perPage = 0, $page = 1, $getUrl = false) { $path = ltrim($path, DIRECTORY_SEPARATOR); $api = "commits"; @@ -683,6 +686,18 @@ class gitlab if($until) $param->until = $until; if($perPage) $param->per_page = $perPage; + if($page) $param->page = $page; + + if($getUrl) + { + $params = (array) $param; + $params['private_token'] = $this->token; + $params['per_page'] = isset($params['per_page']) ? $params['per_page'] : 100; + + $api = ltrim($api, '/'); + $api = $this->root . $api . '?' . http_build_query($params); + return $api; + } return $this->fetch($api, $param); } @@ -736,10 +751,11 @@ class gitlab * * @param string $path * @param bool $recursive + * @param bool $loop * @access public * @return mixed */ - public function tree($path, $recursive = 1) + public function tree($path, $recursive = 1, $loop = false) { $api = "tree"; @@ -747,17 +763,20 @@ class gitlab $params['path'] = ltrim($path, '/'); $params['ref'] = $this->branch; $params['recursive'] = (int) $recursive; - return $this->fetch($api, $params); + return $this->fetch($api, $params, $loop, $loop ? true : false); } /** * Fetch data from gitlab api. * * @param string $api + * @param array $params + * @param bool $needToLoop + * @param bool $multi * @access public * @return mixed */ - public function fetch($api, $params = array(), $needToLoop = false) + public function fetch($api, $params = array(), $needToLoop = false, $multi = false) { $params = (array) $params; $params['private_token'] = $this->token; @@ -768,19 +787,49 @@ class gitlab if($needToLoop) { $allResults = array(); - for($page = 1; true; $page++) + if($multi) { - $results = json_decode(commonModel::http($api . "&page={$page}")); - if(!is_array($results)) break; - if(!empty($results)) $allResults = array_merge($allResults, $results); - if(count($results) < 100) break; + $results = commonModel::httpWithHeader($api . "&page=1"); + if(empty($results['header']['X-Total-Pages'])) return array(); + + $totalPages = $results['header']['X-Total-Pages']; + if($totalPages == 1) + { + $allResults = json_decode($results['body']); + } + else + { + $requests = array(); + for($page = 1; $page <= $totalPages; $page++) + { + $requests[$page]['url'] = $api . "&page={$page}"; + } + + $results = requests::request_multiple($requests, array('timeout' => 60)); + foreach($results as $result) + { + if(empty($result->body)) continue; + $data = json_decode($result->body); + $allResults = array_merge($allResults, $data); + } + } + } + else + { + for($page = 1; true; $page++) + { + $results = json_decode(commonModel::http($api . "&page={$page}", null, array(), array(), 'data', 'POST', 30, true, false)); + if(!is_array($results)) break; + if(!empty($results)) $allResults = array_merge($allResults, $results); + if(count($results) < 100) break; + } } return $allResults; } else { - list($response, $httpCode) = commonModel::http($api, null, array(), array(), 'data', 'Post', 30, true); + list($response, $httpCode) = commonModel::http($api, null, array(), array(), 'data', 'POST', 30, true, false); if(!empty(commonModel::$requestErrors)) { commonModel::$requestErrors = array(); @@ -828,12 +877,15 @@ class gitlab $parsedLog->time = date('Y-m-d H:i:s', strtotime($commit->committed_date)); $parsedLog->comment = $commit->message; $parsedLog->change = array(); - foreach($commit->diffs as $diff) + if(!empty($commit->diffs)) { - $parsedLog->change[$diff->path] = array(); - $parsedLog->change[$diff->path]['action'] = $diff->action; - $parsedLog->change[$diff->path]['kind'] = $diff->type; - $parsedLog->change[$diff->path]['oldPath'] = $diff->oldPath; + foreach($commit->diffs as $diff) + { + $parsedLog->change[$diff->path] = array(); + $parsedLog->change[$diff->path]['action'] = $diff->action; + $parsedLog->change[$diff->path]['kind'] = $diff->type; + $parsedLog->change[$diff->path]['oldPath'] = $diff->oldPath; + } } $parsedLogs[] = $parsedLog; } diff --git a/module/common/model.php b/module/common/model.php index 3bf311ce61..f895006831 100644 --- a/module/common/model.php +++ b/module/common/model.php @@ -3181,18 +3181,21 @@ EOD; curl_close($curl); - $logFile = $app->getLogRoot() . 'saas.'. date('Ymd') . '.log.php'; - if(!file_exists($logFile)) file_put_contents($logFile, ''); - - $fh = @fopen($logFile, 'a'); - if($fh) + if($app->config->debug) { - fwrite($fh, date('Ymd H:i:s') . ": " . $app->getURI() . "\n"); - fwrite($fh, "url: " . $url . "\n"); - if(!empty($data)) fwrite($fh, "data: " . print_r($data, true) . "\n"); - fwrite($fh, "results:" . print_r($response, true) . "\n"); - if(!empty($errors)) fwrite($fh, "errors: " . $errors . "\n"); - fclose($fh); + $logFile = $app->getLogRoot() . 'saas.'. date('Ymd') . '.log.php'; + if(!file_exists($logFile)) file_put_contents($logFile, ''); + + $fh = @fopen($logFile, 'a'); + if($fh) + { + fwrite($fh, date('Ymd H:i:s') . ": " . $app->getURI() . "\n"); + fwrite($fh, "url: " . $url . "\n"); + if(!empty($data)) fwrite($fh, "data: " . print_r($data, true) . "\n"); + fwrite($fh, "results:" . print_r($response, true) . "\n"); + if(!empty($errors)) fwrite($fh, "errors: " . $errors . "\n"); + fclose($fh); + } } if($errors) commonModel::$requestErrors[] = $errors; @@ -3211,11 +3214,12 @@ EOD; * @param string $method POST|PATCH|PUT * @param int $timeout * @param bool $httpCode + * @param bool $log * @static * @access public * @return string */ - public static function http($url, $data = null, $options = array(), $headers = array(), $dataType = 'data', $method = 'POST', $timeout = 30, $httpCode = false) + public static function http($url, $data = null, $options = array(), $headers = array(), $dataType = 'data', $method = 'POST', $timeout = 30, $httpCode = false, $log = true) { global $lang, $app; if(!extension_loaded('curl')) @@ -3265,18 +3269,21 @@ EOD; if($httpCode) $httpCode = curl_getinfo($curl,CURLINFO_HTTP_CODE); curl_close($curl); - $logFile = $app->getLogRoot() . 'saas.'. date('Ymd') . '.log.php'; - if(!file_exists($logFile)) file_put_contents($logFile, ''); - - $fh = @fopen($logFile, 'a'); - if($fh) + if($log or $app->config->debug) { - fwrite($fh, date('Ymd H:i:s') . ": " . $app->getURI() . "\n"); - fwrite($fh, "url: " . $url . "\n"); - if(!empty($data)) fwrite($fh, "data: " . print_r($data, true) . "\n"); - fwrite($fh, "results:" . print_r($response, true) . "\n"); - if(!empty($errors)) fwrite($fh, "errors: " . $errors . "\n"); - fclose($fh); + $logFile = $app->getLogRoot() . 'saas.'. date('Ymd') . '.log.php'; + if(!file_exists($logFile)) file_put_contents($logFile, ''); + + $fh = @fopen($logFile, 'a'); + if($fh) + { + fwrite($fh, date('Ymd H:i:s') . ": " . $app->getURI() . "\n"); + fwrite($fh, "url: " . $url . "\n"); + if(!empty($data)) fwrite($fh, "data: " . print_r($data, true) . "\n"); + fwrite($fh, "results:" . print_r($response, true) . "\n"); + if(!empty($errors)) fwrite($fh, "errors: " . $errors . "\n"); + fclose($fh); + } } if($errors) commonModel::$requestErrors[] = $errors; diff --git a/module/compile/model.php b/module/compile/model.php index ba7b64cf8e..619de7cf6b 100644 --- a/module/compile/model.php +++ b/module/compile/model.php @@ -129,7 +129,14 @@ class compileModel extends model $url = new stdclass(); $url->userPWD = "$jenkinsUser:$jenkinsPassword"; - $url->url = sprintf('%s/job/%s/buildWithParameters/api/json', $jenkinsServer, $jenkins->pipeline); + if(strpos($jenkins->pipeline, '/job/') !== false) + { + $url->url = sprintf('%s%sbuildWithParameters/api/json', $jenkinsServer, $jenkins->pipeline); + } + else + { + $url->url = sprintf('%s/job/%s/buildWithParameters/api/json', $jenkinsServer, $jenkins->pipeline); + } return $url; } @@ -261,7 +268,14 @@ class compileModel extends model $jenkinsPassword = $jenkins->token ? $jenkins->token : base64_decode($jenkins->password); /* Get build list by API. */ - $url = sprintf('%s/job/%s/api/json?tree=builds[id,number,result,queueId,timestamp]', $jenkins->url, $job->pipeline); + if(strpos($job->pipeline, '/job/') !== false) + { + $url = sprintf('%s%sapi/json?tree=builds[id,number,result,queueId,timestamp]', $jenkins->url, $job->pipeline); + } + else + { + $url = sprintf('%s/job/%s/api/json?tree=builds[id,number,result,queueId,timestamp]', $jenkins->url, $job->pipeline); + } $response = common::http($url, '', array(CURLOPT_USERPWD => "$jenkinsUser:$jenkinsPassword")); if(!$response) return false; diff --git a/module/gitlab/model.php b/module/gitlab/model.php index c0052aab6d..8413708a3c 100644 --- a/module/gitlab/model.php +++ b/module/gitlab/model.php @@ -20,6 +20,8 @@ class gitlabModel extends model public $developerAccess = 30; public $maintainerAccess = 40; + protected $projects = array(); + /** * Get a gitlab by id. * @@ -385,6 +387,45 @@ class gitlabModel extends model return $branches; } + /** + * Get Gitlab commits. + * + * @param object $repo + * @param string $entry + * @param string $revision + * @param string $type + * @param object $pager + * @param string $begin + * @param string $end + * @access public + * @return array + */ + public function getCommits($repo, $entry, $revision = 'HEAD', $type = 'dir', $pager = null, $begin = 0, $end = 0) + { + $scm = $this->app->loadClass('scm'); + $scm->setEngine($repo); + $comments = $scm->engine->getCommitsByPath($entry, '', '', isset($pager->recPerPage) ? $pager->recPerPage : 10, isset($pager->pageID) ? $pager->pageID : 1); + + $designNames = $this->dao->select("commit, name")->from(TABLE_DESIGN)->where('deleted')->eq(0)->fetchPairs(); + $designIds = $this->dao->select("commit, id")->from(TABLE_DESIGN)->where('deleted')->eq(0)->fetchPairs(); + $commitIds = array(); + foreach($comments as $comment) + { + $comment->revision = $comment->id; + $comment->originalComment = $comment->title; + $comment->comment = $this->loadModel('repo')->replaceCommentLink($comment->title); + $comment->committer = $comment->committer_name; + $comment->time = date("Y-m-d H:i:s", strtotime($comment->committed_date)); + $comment->designName = zget($designNames, $comment->revision, ''); + $comment->designID = zget($designIds, $comment->revision, ''); + $commitIds[] = $comment->id; + } + $commitCounts = $this->dao->select('revision,commit')->from(TABLE_REPOHISTORY)->where('revision')->in($commitIds)->fetchPairs(); + foreach($comments as $comment) $comment->commit = !empty($commitCounts[$comment->id]) ? $commitCounts[$comment->id] : ''; + + return $comments; + } + /** * Create a gitlab. * @@ -424,7 +465,7 @@ class gitlabModel extends model if(strpos($host, 'http://') !== 0 and strpos($host, 'https://') !== 0) return false; $url = sprintf($host, $api); - return json_decode(commonModel::http($url, $data, $options)); + return json_decode(commonModel::http($url, $data, $options, $headers = array(), $dataType = 'data', $method = 'POST', $timeout = 30, $httpCode = false, $log = false)); } /** @@ -461,7 +502,7 @@ class gitlabModel extends model $gitlab = $this->loadModel('gitlab')->getByID($gitlabID); if(!$gitlab) return ''; $url = rtrim($gitlab->url, '/') . "/api/v4/todos?project_id=$projectID&type=MergeRequest&state=pending&private_token={$gitlab->token}&sudo={$sudo}"; - return json_decode(commonModel::http($url)); + return json_decode(commonModel::http($url, $data = null, $optionsi = array(), $headers = array(), $dataType = 'data', $method = 'POST', $timeout = 30, $httpCode = false, $log = false)); } /** @@ -708,7 +749,7 @@ class gitlabModel extends model $allResults = array(); for($page = 1; true; $page++) { - $results = json_decode(commonModel::http($url . "&simple={$simple}&page={$page}&per_page=100")); + $results = json_decode(commonModel::http($url . "&simple={$simple}&page={$page}&per_page=100", $data = null, $optionsi = array(), $headers = array(), $dataType = 'data', $method = 'POST', $timeout = 30, $httpCode = false, $log = false)); if(!is_array($results)) break; if(!empty($results)) $allResults = array_merge($allResults, $results); if(count($results) < 100) break; @@ -986,8 +1027,11 @@ class gitlabModel extends model */ public function apiGetSingleProject($gitlabID, $projectID) { + if(isset($this->projects[$gitlabID][$projectID])) return $this->projects[$gitlabID][$projectID]; + $url = sprintf($this->getApiRoot($gitlabID, false), "/projects/$projectID"); - return json_decode(commonModel::http($url)); + $this->projects[$gitlabID][$projectID] = json_decode(commonModel::http($url, $data = null, $optionsi = array(), $headers = array(), $dataType = 'data', $method = 'POST', $timeout = 30, $httpCode = false, $log = false)); + return $this->projects[$gitlabID][$projectID]; } /** diff --git a/module/jenkins/control.php b/module/jenkins/control.php index 3bb59632bb..d6e0a4d275 100644 --- a/module/jenkins/control.php +++ b/module/jenkins/control.php @@ -125,9 +125,9 @@ class jenkins extends control */ public function ajaxGetJenkinsTasks($id) { - if(empty($id)) return print(json_encode(array('' => ''))); + if(empty($id)) return print(''); - $tasks = $this->jenkins->getTasks($id); - echo json_encode($tasks); + $this->view->tasks = $this->jenkins->getTasks($id, 3); + $this->display(); } } diff --git a/module/jenkins/model.php b/module/jenkins/model.php index 485e0bf897..4261f464e9 100644 --- a/module/jenkins/model.php +++ b/module/jenkins/model.php @@ -51,10 +51,11 @@ class jenkinsModel extends model * Get jenkins tasks. * * @param int $id + * @param int $depth * @access public * @return array */ - public function getTasks($id) + public function getTasks($id, $depth = 0) { $jenkins = $this->getById($id); @@ -63,14 +64,67 @@ class jenkinsModel extends model $jenkinsPassword = $jenkins->token ? $jenkins->token : $jenkins->password; $userPWD = "$jenkinsUser:$jenkinsPassword"; - $response = common::http($jenkinsServer . '/api/json/items/list', '', array(CURLOPT_USERPWD => $userPWD)); + $response = common::http($jenkinsServer . '/api/json/items/list' . ($depth ? "?depth=1" : ''), '', array(CURLOPT_USERPWD => $userPWD), $headers = array(), $dataType = 'data', $method = 'POST', $timeout = 30, $httpCode = false, $log = false); $response = json_decode($response); $tasks = array(); - if(isset($response->jobs)) + if($depth) { - foreach($response->jobs as $job) $tasks[basename($job->url)] = $job->name; + /* Support up to 4 levels. */ + if(isset($response->jobs)) $tasks = $this->getDepthJobs($response->jobs, $userPWD, 1); } + else + { + if(isset($response->jobs)) + { + foreach($response->jobs as $job) $tasks[basename($job->url)] = $job->name; + } + } + return $tasks; + } + + /** + * Get jobs by depth. + * + * @param object $jobs + * @param string $userPWD + * @param int $depth + * @access protected + * @return array + */ + protected function getDepthJobs($jobs, $userPWD, $depth = 1) + { + if($depth > 4) return array(); + + $tasks = array(); + foreach($jobs as $job) + { + if(empty($job->url)) continue; + + $isJob = true; + if(stripos($job->_class, '.multibranch') !== false or stripos($job->_class, '.folder') !== false or stripos($job->_class, '.OrganizationFolder') !== false) $isJob = false; + if(!empty($job->buildable) and $job->buildable == true) $isJob = true; + + if($isJob) + { + $parms = parse_url($job->url); + $tasks[$parms['path']] = $job->name; + } + else + { + if($depth > 1) + { + $response = common::http($job->url . 'api/json', '', array(CURLOPT_USERPWD => $userPWD), $headers = array(), $dataType = 'data', $method = 'POST', $timeout = 30, $httpCode = false, $log = false); + $job = json_decode($response); + } + + $tasks[basename($job->url)] = array(); + if(empty($job->jobs)) continue; + + $tasks[basename($job->url)] = $this->getDepthJobs($job->jobs, $userPWD, $depth + 1); + } + } + return $tasks; } diff --git a/module/jenkins/view/ajaxgetjenkinstasks.html.php b/module/jenkins/view/ajaxgetjenkinstasks.html.php new file mode 100644 index 0000000000..a58535289e --- /dev/null +++ b/module/jenkins/view/ajaxgetjenkinstasks.html.php @@ -0,0 +1,96 @@ + + * @package repo + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
+
+
+
    + $task):?> + + +
  • + +
    + +
    +
      + $task2):?> + +
    • + +
      + +
      +
        + $task3):?> + +
      • + +
        + +
        +
          + $task4):?> + +
        • + +
        • + +
        +
      • + +
      • + +
      • + + +
      +
    • + +
    • + +
    • + + +
    +
  • + +
  • + +
  • + + +
+
+
+
+ diff --git a/module/job/control.php b/module/job/control.php index d62d755756..887a53e845 100644 --- a/module/job/control.php +++ b/module/job/control.php @@ -60,6 +60,10 @@ class job extends control $branch = $this->gitlab->apiGetSingleBranch($job->server, $pipeline->project, $pipeline->reference); if($branch and isset($branch->can_push) and !$branch->can_push) $job->canExec = false; } + elseif($job->engine == 'jenkins') + { + if(strpos($job->pipeline, '/job/') !== false) $job->pipeline = trim(str_replace('/job/', '/', $job->pipeline), '/'); + } } $this->view->title = $this->lang->ci->job . $this->lang->colon . $this->lang->job->browse; @@ -115,7 +119,7 @@ class job extends control } $this->app->loadLang('action'); - $repoList = $this->loadModel('repo')->getList($this->projectID); + $repoList = $this->loadModel('repo')->getList($this->projectID, false); $repoPairs = array(0 => ''); $gitlabRepos = array(0 => ''); $repoTypes = array(); diff --git a/module/job/css/create.css b/module/job/css/create.css index 188dd0855c..5c44ac685f 100644 --- a/module/job/css/create.css +++ b/module/job/css/create.css @@ -2,9 +2,14 @@ .only-pick-time thead th, .only-pick-time tfoot th {color: transparent !important;} .checkbox-primary.checkbox-inline {display: inline-block !important;} .checkbox-primary.checkbox-inline label {padding-left: 5px !important;} +.jktask-label {min-width: 50px; max-width: 300px; border-radius: 0px 4px 4px 0px;} +.input-group-addon {border-radius: 2px 0px 0px 2px !important;} +button.text-right {min-width: 100px; text-align: right;} #server_chosen .chosen-single {border-right: 0px;} #pipelineBox {width: 385px;} #svnDirBox .input-group {width: unset !important;} #jenkinsServerTR .input-group-addon {border-left-width: 0 !important;} +#jenkinsServerTR .dropdown {position: relative;} +#jenkinsServerTR .table-col:first-child {width: 375.5px;} .chosen-container .chosen-drop{z-index: 1100;} /* from c20b7e7a5 */ diff --git a/module/job/js/create.js b/module/job/js/create.js index cd188907e9..395f47d0cb 100644 --- a/module/job/js/create.js +++ b/module/job/js/create.js @@ -18,7 +18,7 @@ $(document).ready(function() $('#frameBox .loading').remove(); $('#frameBox .input-group').append(html); $('#frameBox #frame').chosen(); - + $('#frame').change(); } getFrameSelect(''); @@ -171,23 +171,16 @@ $(document).ready(function() $('#jkServer').change(function() { var jenkinsID = $(this).val(); - $('#jenkinsServerTR #jkTask').remove(); - $('#jenkinsServerTR #jkTask_chosen').remove(); + $('#jenkinsServerTR .dropdown,.input-group-addon').hide(); $('#jenkinsServerTR .input-group').append("
"); - $.getJSON(createLink('jenkins', 'ajaxGetJenkinsTasks', 'jenkinsID=' + jenkinsID), function(tasks) - { - html = "'; - $('#jenkinsServerTR .loading').remove(); - $('#jenkinsServerTR .input-group').append(html); + setJenkinsJob('', ''); - $('#jenkinsServerTR #jkTask').chosen({drop_direction: 'auto'}); - }) + $.get(createLink('jenkins', 'ajaxGetJenkinsTasks', 'jenkinsID=' + jenkinsID), function(tasks) + { + $('#jenkinsServerTR .loading').remove(); + $('#dropMenuTasks').html(tasks); + $('#jenkinsServerTR .dropdown,.input-group-addon').show(); + }); /* There has been a problem with handling the prompt label. */ $('#jkTaskLabel').remove(); @@ -253,3 +246,18 @@ $(document).ready(function() $('#engine').change(); $('#triggerType').change(); }); + +/** + * Set jenkins job. + * + * @param string $name + * @param string $task + * @access public + * @return void + */ +function setJenkinsJob(name, task) +{ + if(name) $('.jktask-label').removeClass('text-right'); + $('#jkTask').val(task); + $('.jktask-label .text').html(name); +} diff --git a/module/job/view/create.html.php b/module/job/view/create.html.php index 13b7ee4f2b..ccdb62f149 100644 --- a/module/job/view/create.html.php +++ b/module/job/view/create.html.php @@ -106,13 +106,17 @@ job->jkHost; ?> - +
job->pipeline;?> - ''), '', "class='form-control chosen'"); ?> +
diff --git a/module/mr/control.php b/module/mr/control.php index 173d7c0261..7d2e34b035 100644 --- a/module/mr/control.php +++ b/module/mr/control.php @@ -34,16 +34,38 @@ class mr extends control $this->app->loadClass('pager', $static = true); $pager = new pager($recTotal, $recPerPage, $pageID); - $repos = $this->loadModel('repo')->getListBySCM(array('Gitlab', 'Gitea', 'Gogs')); - if(empty($repos)) $this->locate($this->repo->createLink('create')); + $repoCount = $this->dao->select('*')->from(TABLE_REPO)->where('deleted')->eq('0') + ->andWhere('SCM')->in(array('Gitlab', 'Gitea', 'Gogs')) + ->andWhere('synced')->eq(1) + ->orderBy('id') + ->count(); + if($repoCount == 0) $this->locate($this->repo->createLink('create')); - $repoID = $this->repo->saveState($repoID, $objectID); + $repoID = $this->loadModel('repo')->saveState($repoID, $objectID); $repo = $this->repo->getRepoByID($repoID); - if(!in_array(strtolower($repo->SCM), $this->config->mr->gitServiceList)) $repo = $repos[0]; + if(!in_array(strtolower($repo->SCM), $this->config->mr->gitServiceList)) + { + $repoID = $this->dao->select('id')->from(TABLE_REPO)->where('deleted')->eq('0')->andWhere('SCM')->in(array('Gitlab', 'Gitea', 'Gogs'))->andWhere('synced')->eq(1)->orderBy('id')->fetch('id'); + $repo = $this->repo->getRepoByID($repoID); + } $this->loadModel('ci')->setMenu($repo->id); - $projects = $this->mr->getAllProjects($repoID, $repo->SCM); - $MRList = $this->mr->getList($mode, $param, $orderBy, $pager, empty($projects) ? false : $projects, $repoID); + $filterProjects = empty($repo->serviceProject) ? array() : array($repo->serviceHost => array($repo->serviceProject => $repo->serviceProject)); + $MRList = $this->mr->getList($mode, $param, $orderBy, $pager, $filterProjects, $repoID); + if($repo->SCM == 'Gitlab') + { + $projectIds = array(); + foreach($MRList as $MR) + { + $projectIds[$MR->sourceProject] = $MR->sourceProject; + $projectIds[$MR->targetProject] = $MR->targetProject; + } + $projects = $this->mr->getGitlabProjects($repo->serviceHost, $projectIds); + } + else + { + $projects = $this->mr->getAllProjects($repoID, $repo->SCM); + } /* Save current URI to session. */ $this->session->set('mrList', $this->app->getURI(true), 'repo'); @@ -87,7 +109,6 @@ class mr extends control $this->view->param = $param; $this->view->repoID = $repoID; $this->view->objectID = $objectID; - $this->view->repos = $repos; $this->view->repo = $repo; $this->view->orderBy = $orderBy; $this->view->openIDList = $openIDList; diff --git a/module/mr/model.php b/module/mr/model.php index 2d06fe1ad9..178d87a02a 100644 --- a/module/mr/model.php +++ b/module/mr/model.php @@ -143,10 +143,11 @@ class mrModel extends model * Get gitlab projects. * * @param int $hostID + * @param array $projectIds * @access public * @return array */ - public function getGitlabProjects($hostID = 0) + public function getGitlabProjects($hostID = 0, $projectIds = array()) { $allProjects = array(); $allGroups = array(); @@ -164,7 +165,19 @@ class mrModel extends model $minProject = min($projectCount->minSource, $projectCount->minTarget); $maxProject = max($projectCount->maxSource, $projectCount->maxTarget); } - $allProjects[$hostID] = $this->gitlab->apiGetProjects($hostID, 'false', $minProject, $maxProject); + + if($projectIds) + { + foreach($projectIds as $projectID) + { + $project = $this->gitlab->apiGetSingleProject($hostID, $projectID); + if(isset($project->id)) $allProjects[$hostID][] = $project; + } + } + else + { + $allProjects[$hostID] = $this->gitlab->apiGetProjects($hostID, 'false', $minProject, $maxProject); + } /* If not an administrator, need to obtain group member information. */ $groupIDList = array(0 => 0); @@ -747,7 +760,7 @@ class mrModel extends model $url = sprintf($this->loadModel('gitea')->getApiRoot($hostID), "/repos/$projectID/pulls"); } - $response = json_decode(commonModel::http($url)); + $response = json_decode(commonModel::http($url, $data = null, $options = array(), $headers = array(), $dataType = 'data', $method = 'POST', $timeout = 30, $httpCode = false, $log = false)); if(empty($response)) $response = array(); if($scm == 'Gitea') { diff --git a/module/repo/control.php b/module/repo/control.php index 5b125ab8e9..32ea458c9f 100644 --- a/module/repo/control.php +++ b/module/repo/control.php @@ -80,7 +80,7 @@ class repo extends control $repoID = $this->repo->saveState(0, $objectID); if($this->viewType !== 'json') $this->commonAction($repoID, $objectID); - $repoList = $this->repo->getList(0, '', $orderBy); + $repoList = $this->repo->getList(0, '', $orderBy, null, true); $sonarRepoList = $this->loadModel('job')->getSonarqubeByRepo(array_keys($repoList)); /* Pager. */ @@ -599,17 +599,48 @@ class repo extends control } /* Refresh repo. */ - if($refresh) $this->repo->updateCommit($repoID, $objectID, $originBranchID); + if($refresh) + { + $this->repo->updateCommit($repoID, $objectID, $originBranchID); - /* Get files info. */ - $infos = $this->repo->getFileCommits($repo, $branchID, $path); - if($this->cookie->repoRefresh) setcookie('repoRefresh', 0, 0, $this->config->webRoot, '', $this->config->cookieSecure, true); + if($repo->SCM == 'Gitlab') $this->repo->checkDeletedBranches($repoID, $branches); + } /* Set logType and revisions. */ $logType = 'dir'; $revisions = $this->repo->getCommits($repo, $path, $revision, $logType, $pager); $lastRevision = current($revisions); + /* Get files info. */ + if($repo->SCM == 'Gitlab') + { + $cacheFile = $this->repo->getCacheFile($repo->id, $path, $branchID); + $cacheRefreshTime = isset($lastRevision->time) ? date('Y-m-d H:i', strtotime($lastRevision->time)) : date('Y-m-d H:i'); + if(!$cacheFile or !file_exists($cacheFile) or filemtime($cacheFile) < strtotime($cacheRefreshTime)) + { + $infos = $this->repo->getFileList($repo, $branchID, $path); + + if($cacheFile) + { + if(!file_exists($cacheFile . '.lock')) + { + touch($cacheFile . '.lock'); + file_put_contents($cacheFile, serialize($infos)); + unlink($cacheFile . '.lock'); + } + } + } + else + { + $infos = unserialize(file_get_contents($cacheFile)); + } + } + else + { + $infos = $this->repo->getFileCommits($repo, $branchID, $path); + } + if($this->cookie->repoRefresh) setcookie('repoRefresh', 0, 0, $this->config->webRoot, '', $this->config->cookieSecure, true); + /* Synchronous commit only in root path. */ if(in_array($repo->SCM, $this->config->repo->gitTypeList) and empty($path) and $infos and empty($revisions)) $this->locate($this->repo->createLink('showSyncCommit', "repoID=$repoID&objectID=$objectID&branch=" . helper::safe64Encode(base64_encode($this->cookie->repoBranch)))); @@ -685,6 +716,8 @@ class repo extends control $this->view->revision = $revision; $this->view->repoID = $repoID; $this->view->objectID = $objectID; + $this->view->entry = $entry; + $this->view->type = $type; $this->view->branchID = $this->cookie->repoBranch; $this->view->entry = urldecode($entry); $this->view->path = urldecode($entry); diff --git a/module/repo/css/log.css b/module/repo/css/log.css index 841e94940e..dce12717c7 100644 --- a/module/repo/css/log.css +++ b/module/repo/css/log.css @@ -1 +1,2 @@ .m-repo-log .btn-back {margin-right: 0; padding-top: 8px;} +#repoPageSize {right: 30px;} diff --git a/module/repo/js/log.js b/module/repo/js/log.js index 45fccf07ca..e403a9a9d5 100644 --- a/module/repo/js/log.js +++ b/module/repo/js/log.js @@ -13,7 +13,7 @@ function processCheckbox() if (checkNum >= 2) { $("input:checkbox[name='revision[]']").each(function(){if($(this).attr('checked') == false) $(this).attr("disabled","disabled")}); - } + } else { $("input:checkbox[name='revision[]']").each(function(){if($(this).attr('checked') == false) $(this).attr("enabled","enabled")}); diff --git a/module/repo/model.php b/module/repo/model.php index 3a9aa88859..c3717e9890 100644 --- a/module/repo/model.php +++ b/module/repo/model.php @@ -107,10 +107,11 @@ class repoModel extends model * @param string $SCM Subversion|Git|Gitlab * @param string $orderBy * @param object $pager + * @param bool $getCodePath * @access public * @return array */ - public function getList($projectID = 0, $SCM = '', $orderBy = 'id_desc', $pager = null) + public function getList($projectID = 0, $SCM = '', $orderBy = 'id_desc', $pager = null, $getCodePath = false) { $repos = $this->dao->select('*')->from(TABLE_REPO) ->where('deleted')->eq('0') @@ -143,7 +144,7 @@ class repoModel extends model } } - if(in_array(strtolower($repo->SCM), $this->config->repo->gitServiceList)) $repo = $this->processGitService($repo); + if(in_array(strtolower($repo->SCM), $this->config->repo->gitServiceList)) $repo = $this->processGitService($repo, $getCodePath); } return $repos; @@ -731,6 +732,8 @@ class repoModel extends model */ public function getCommits($repo, $entry, $revision = 'HEAD', $type = 'dir', $pager = null, $begin = 0, $end = 0) { + if($repo->SCM == 'Gitlab') return $this->loadModel('gitlab')->getCommits($repo, $entry, $revision, $type, $pager, $begin, $end); + $entry = ltrim($entry, '/'); $entry = $repo->prefix . (empty($entry) ? '' : '/' . $entry); @@ -895,10 +898,10 @@ class repoModel extends model */ public function getCacheFile($repoID, $path, $revision) { - $cachePath = $this->app->getCacheRoot() . '/' . 'repo'; + $cachePath = $this->app->getCacheRoot() . '/repo/' . $repoID; if(!is_dir($cachePath)) mkdir($cachePath, 0777, true); if(!is_writable($cachePath)) return false; - return $cachePath . '/' . $repoID . '-' . md5("{$this->cookie->repoBranch}-$path-$revision"); + return $cachePath . '/' . md5("{$this->cookie->repoBranch}-$path-$revision"); } /** @@ -2136,20 +2139,21 @@ class repoModel extends model * Process git service repo. * * @param object $repo + * @param bool $getCodePath * @access public * @return object */ - public function processGitService($repo) + public function processGitService($repo, $getCodePath = true) { $service = $this->loadModel('pipeline')->getByID($repo->serviceHost); if($repo->SCM == 'Gitlab') { - $project = $this->loadModel('gitlab')->apiGetSingleProject($repo->serviceHost, $repo->serviceProject); + if($getCodePath) $project = $this->loadModel('gitlab')->apiGetSingleProject($repo->serviceHost, $repo->serviceProject); $repo->path = $service ? sprintf($this->config->repo->{$service->type}->apiPath, $service->url, $repo->serviceProject) : ''; $repo->client = $service ? $service->url : ''; $repo->password = $service ? $service->token : ''; - $repo->codePath = $project ? $project->web_url : $repo->path; + $repo->codePath = isset($project->web_url) ? $project->web_url : $repo->path; } elseif(in_array($repo->SCM, array('Gitea', 'Gogs'))) { @@ -2368,6 +2372,48 @@ class repoModel extends model return array_merge($folders, $files); } + /** + * Get Repo file list. + * + * @param object $repo + * @param string $branch + * @param string $path + * @access public + * @return array + */ + public function getFileList($repo, $branch, $path = '') + { + $scm = $this->app->loadClass('scm'); + $scm->setEngine($repo); + + $paths = array(); + $files = $scm->engine->tree($path, 0); + foreach($files as $file) + { + $paths[] = $file->path; + } + + $requests = array(); + foreach($paths as $path) + { + $requests[]['url'] = $scm->engine->getCommitsByPath($path, '', '', 1, 1, true); + } + $this->app->loadClass('requests', true); + $commits = requests::request_multiple($requests); + + foreach($files as $key => $file) + { + $files[$key]->kind = $file->type == 'tree' ? 'dir' : 'file'; + + $commit = isset($commits[$key]->body) ? json_decode($commits[$key]->body) : array(); + $files[$key]->revision = isset($commit[0]->id) ? $commit[0]->id : ''; + $files[$key]->comment = isset($commit[0]->title) ? $commit[0]->title : ''; + $files[$key]->account = isset($commit[0]->committer_name) ? $commit[0]->committer_name : ''; + $files[$key]->date = isset($commit[0]->committed_date) ? $commit[0]->committed_date : ''; + } + return $files; + } + /** * Get html for file tree. * @@ -2383,6 +2429,50 @@ class repoModel extends model $allFiles = array(); if(is_null($diffs)) { + if($repo->SCM == 'Gitlab') + { + $cacheFile = $this->getCacheFile($repo->id, 'tree-list', 'tree-list'); + $lastRevision = $this->dao->select('t1.revision')->from(TABLE_REPOHISTORY)->alias('t1') + ->leftJoin(TABLE_REPOBRANCH)->alias('t2')->on('t1.id=t2.revision') + ->where('t1.repo')->eq($repo->id) + ->andWhere('t2.branch')->eq($this->cookie->repoBranch) + ->orderBy('t1.commit desc') + ->fetch('revision'); + + if($cacheFile and file_exists($cacheFile)) $infos = unserialize(file_get_contents($cacheFile)); + if(!$cacheFile or !file_exists($cacheFile) or $infos['revision'] != $lastRevision) + { + $scm = $this->app->loadClass('scm'); + $scm->setEngine($repo); + + $this->app->loadClass('requests', true); + $files = $scm->engine->tree('', 1, true); + + $allFiles = array(); + foreach($files as $file) + { + $allFiles[] = $file->path; + } + $infos = array('revision' => $lastRevision, 'files' => $allFiles); + + if($cacheFile) + { + if(!file_exists($cacheFile . '.lock')) + { + touch($cacheFile . '.lock'); + file_put_contents($cacheFile, serialize($infos)); + unlink($cacheFile . '.lock'); + } + } + } + else + { + $infos = unserialize(file_get_contents($cacheFile)); + $allFiles = $infos['files']; + } + } + else + { if($repo->SCM != 'Subversion' and empty($branch)) $branch = $this->cookie->repoBranch; $files = $this->dao->select('t1.path,t2.time,t1.action')->from(TABLE_REPOFILES)->alias('t1') ->leftJoin(TABLE_REPOHISTORY)->alias('t2')->on('t1.revision=t2.id') @@ -2420,6 +2510,7 @@ class repoModel extends model $allFiles[] = $file->path; } } + } } else { @@ -2834,4 +2925,33 @@ class repoModel extends model } if($repo->SCM == 'Subversion') $this->loadModel('svn')->updateCommit($repo, $commentGroup, false); } + + /** + * Delete the deleted branch. + * + * @param int $repoID + * @param array $latestBranches + * @access public + * @return bool + */ + public function checkDeletedBranches($repoID, $latestBranches) + { + if(empty($latestBranches)) return false; + + $currentBranches = $this->dao->select('branch')->from(TABLE_REPOBRANCH)->where('repo')->eq($repoID)->groupBy('branch')->fetchPairs('branch'); + + $deletedBranches = array_diff($currentBranches, $latestBranches); + foreach($deletedBranches as $deletedBranch) + { + if($deletedBranch == 'master') continue; + + $revisionIds = $this->dao->select('revision')->from(TABLE_REPOBRANCH)->where('repo')->eq($repoID)->andWhere('branch')->eq($deletedBranch)->fetchPairs('revision'); + $fileIds = $this->dao->select('id')->from(TABLE_REPOFILES)->where('revision')->in($revisionIds)->fetchPairs('id'); + + $this->dao->delete()->from(TABLE_REPOHISTORY)->where('id')->in($revisionIds)->exec(); + $this->dao->delete()->from(TABLE_REPOFILES)->where('id')->in($fileIds)->exec(); + $this->dao->delete()->from(TABLE_REPOBRANCH)->where('repo')->eq($repoID)->andWhere('branch')->eq($deletedBranch)->exec(); + } + return true; + } } diff --git a/module/repo/view/:w b/module/repo/view/:w new file mode 100644 index 0000000000..25441d5bb5 --- /dev/null +++ b/module/repo/view/:w @@ -0,0 +1,104 @@ + + + +repo->encodePath($entry) . "&revision=$revision&type=$type");?> + + +
+ +
+ + + + + + SCM != 'Subversion'):?> + + + + + + + + + + + + + SCM != 'Subversion'):?> + + + + + + + + +
repo->revision?>repo->commit?>repo->date?>repo->committer?>repo->comment?>
+
+ + +
+
repo->createLink('revision', "repoID=$repoID&objectID=$objectID&revision=" . $log->revision), substr($log->revision, 0, 10), '', "data-app='{$app->tab}'");?>commit?>time;?>committer;?>comment;?>
+ +
+
+ diff --git a/module/repo/view/log.html.php b/module/repo/view/log.html.php index 290400edb4..6e0ae614a0 100644 --- a/module/repo/view/log.html.php +++ b/module/repo/view/log.html.php @@ -10,6 +10,7 @@ ?> +repo->encodePath($entry) . "&revision=$revision&type=$type");?>