* Finish task #48094.
This commit is contained in:
@@ -97,6 +97,21 @@ class compileModel extends model
|
||||
return $this->dao->select('*')->from(TABLE_COMPILE)->where('job')->eq($jobID)->andWhere('status')->ne('')->orderBy('createdDate_desc')->limit(1)->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get success jobs by job id list.
|
||||
*
|
||||
* @param array $jobIDList
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getSuccessJobs($jobIDList)
|
||||
{
|
||||
return $this->dao->select('job')->from(TABLE_COMPILE)
|
||||
->where('job')->in($jobIDList)
|
||||
->andWhere('status')->eq('success')
|
||||
->fetchPairs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get build url.
|
||||
*
|
||||
|
||||
@@ -91,6 +91,15 @@ class repo extends control
|
||||
$recTotal = count($repoList);
|
||||
$pager = new pager($recTotal, $recPerPage, $pageID);
|
||||
$repoList = array_chunk($repoList, $pager->recPerPage);
|
||||
$repoList = empty($repoList) ? $repoList : $repoList[$pageID - 1];
|
||||
|
||||
/* Get success jobs of sonarqube.*/
|
||||
$jobIDList = array();
|
||||
foreach($repoList as $repo)
|
||||
{
|
||||
if(isset($sonarRepoList[$repo->id])) $jobIDList[] = $sonarRepoList[$repo->id]->id;
|
||||
}
|
||||
$successJobs = $this->loadModel('compile')->getSuccessJobs($jobIDList);
|
||||
|
||||
$this->view->title = $this->lang->repo->common . $this->lang->colon . $this->lang->repo->browse;
|
||||
$this->view->position[] = $this->lang->repo->common;
|
||||
@@ -99,9 +108,10 @@ class repo extends control
|
||||
$this->view->orderBy = $orderBy;
|
||||
$this->view->objectID = $objectID;
|
||||
$this->view->pager = $pager;
|
||||
$this->view->repoList = empty($repoList) ? $repoList: $repoList[$pageID - 1];;
|
||||
$this->view->repoList = $repoList;
|
||||
$this->view->products = $this->loadModel('product')->getPairs();
|
||||
$this->view->sonarRepoList = $sonarRepoList;
|
||||
$this->view->successJobs = $successJobs;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
.c-id {width: 60px;}
|
||||
.c-name {width: 200px;}
|
||||
.c-product {width: 400px;}
|
||||
.c-actions-7 {width: 210px;}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<th class='c-name text-left'><?php common::printOrderLink('name', $orderBy, $vars, $lang->repo->name); ?></th>
|
||||
<th class='c-product text-left'><?php common::printOrderLink('product', $orderBy, $vars, $lang->repo->product); ?></th>
|
||||
<th class='text-left'><?php echo $lang->repo->path; ?></th>
|
||||
<th class='c-actions-6'><?php echo $lang->actions; ?></th>
|
||||
<th class='c-actions-7'><?php echo $lang->actions; ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -63,6 +63,7 @@
|
||||
{
|
||||
$jobID = $sonarRepoList[$repo->id]->id;
|
||||
common::printIcon('sonarqube', 'execJob', "jobID=$jobID", '', 'list', 'sonarqube', 'hiddenwin');
|
||||
if(in_array($jobID, $successJobs)) common::printIcon('sonarqube', 'reportView', "jobID=$jobID", '', 'list', 'audit', '', 'iframe', true);
|
||||
}
|
||||
common::printIcon('repo', 'delete', "repoID=$repo->id&objectID=$objectID", '', 'list', 'trash', 'hiddenwin');
|
||||
?>
|
||||
|
||||
@@ -6,3 +6,8 @@ $config->sonarqube->create->requiredFields = 'name,url,account,password';
|
||||
|
||||
$config->sonarqube->edit = new stdclass();
|
||||
$config->sonarqube->edit->requiredFields = 'name,url,account,password';
|
||||
|
||||
$config->sonarqube->projectStatusClass = array();
|
||||
$config->sonarqube->projectStatusClass['OK'] = 'success';
|
||||
$config->sonarqube->projectStatusClass['WARN'] = 'warning';
|
||||
$config->sonarqube->projectStatusClass['ERROR'] = 'danger';
|
||||
|
||||
@@ -50,6 +50,46 @@ class sonarqube extends control
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show sonarqube report.
|
||||
*
|
||||
* @param int $jobID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function reportView($jobID)
|
||||
{
|
||||
$job = $this->loadModel('job')->getByID($jobID);
|
||||
$qualitygate = $this->sonarqube->apiGetQualitygate($job->sonarqubeServer, $job->projectKey);
|
||||
$report = $this->sonarqube->apiGetReport($job->sonarqubeServer, $job->projectKey);
|
||||
$measures = array();
|
||||
if(isset($report->component->measures))
|
||||
{
|
||||
foreach($report->component->measures as $measure)
|
||||
{
|
||||
if(in_array($measure->metric, array('security_hotspots_reviewed', 'coverage', 'duplicated_lines_density')))
|
||||
{
|
||||
$measures[$measure->metric] = $measure->value . '%';
|
||||
}
|
||||
else
|
||||
{
|
||||
$measures[$measure->metric] = $measure->value;
|
||||
if($measure->value > 1000) $measures[$measure->metric] = round($measure->value / 1000, 1) . 'K';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$projectName = $job->projectKey;
|
||||
$projects = $this->sonarqube->apiGetProjects($job->sonarqubeServer, '', $job->projectKey);
|
||||
if(isset($projects[0]->name)) $projectName = $projects[0]->name;
|
||||
|
||||
$this->view->measures = $measures;
|
||||
$this->view->qualitygate = $qualitygate;
|
||||
$this->view->projectName = $projectName;
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax get project select.
|
||||
*
|
||||
|
||||
@@ -13,6 +13,7 @@ $lang->sonarqube->deleteProject = "Delete SonarQube Project";
|
||||
$lang->sonarqube->placeholderSearch = 'Project name';
|
||||
$lang->sonarqube->execJob = "Exec SonarQube Job";
|
||||
$lang->sonarqube->desc = 'Description';
|
||||
$lang->sonarqube->reportView = "SonarQube Report";
|
||||
|
||||
$lang->sonarqube->id = 'ID';
|
||||
$lang->sonarqube->name = "Server Name";
|
||||
@@ -37,7 +38,22 @@ $lang->sonarqube->validError = 'SonarQube user authority authenticatio
|
||||
$lang->sonarqube->hostError = "Invalid SonarQube service address.";
|
||||
$lang->sonarqube->confirmDelete = 'Do you want to delete this SonarQube server?';
|
||||
$lang->sonarqube->confirmDeleteProject = 'Do you want to delete this SonarQube project?';
|
||||
$lang->sonarqube->noReport = "No Reprot";
|
||||
|
||||
$lang->sonarqube->projectKey = 'Project Key';
|
||||
$lang->sonarqube->projectName = 'Project Name';
|
||||
$lang->sonarqube->projectlastAnalysis = 'Last analysis time';
|
||||
|
||||
$lang->sonarqube->reprot = new stdclass();
|
||||
$lang->sonarqube->reprot->bugs = 'Bugs';
|
||||
$lang->sonarqube->reprot->vulnerabilities = 'Vulnerabilities';
|
||||
$lang->sonarqube->reprot->security_hotspots_reviewed = 'Hotspots Reviewed';
|
||||
$lang->sonarqube->reprot->code_smells = 'Code Smells';
|
||||
$lang->sonarqube->reprot->coverage = 'Coverage';
|
||||
$lang->sonarqube->reprot->duplicated_lines_density = 'Duplications';
|
||||
$lang->sonarqube->reprot->ncloc = 'Lines';
|
||||
|
||||
$lang->sonarqube->qualitygateList = array();
|
||||
$lang->sonarqube->qualitygateList['OK'] = 'Passed';
|
||||
$lang->sonarqube->qualitygateList['WARN'] = 'Warning';
|
||||
$lang->sonarqube->qualitygateList['ERROR'] = 'Failed';
|
||||
|
||||
@@ -12,6 +12,8 @@ $lang->sonarqube->createProject = "创建SonarQube项目";
|
||||
$lang->sonarqube->deleteProject = "删除SonarQube项目";
|
||||
$lang->sonarqube->placeholderSearch = '请输入项目名称';
|
||||
$lang->sonarqube->execJob = "执行SonarQube任务";
|
||||
$lang->sonarqube->desc = '描述';
|
||||
$lang->sonarqube->reportView = "SonarQube报告";
|
||||
|
||||
$lang->sonarqube->id = 'ID';
|
||||
$lang->sonarqube->name = "服务器名称";
|
||||
@@ -37,7 +39,22 @@ $lang->sonarqube->validError = "SonarQube 用户权限认证失败!"
|
||||
$lang->sonarqube->hostError = "无效的SonarQube服务地址。";
|
||||
$lang->sonarqube->confirmDelete = '确认删除该SonarQube吗?';
|
||||
$lang->sonarqube->confirmDeleteProject = '确认删除该SonarQube项目吗?';
|
||||
$lang->sonarqube->noReport = "暂无报告";
|
||||
|
||||
$lang->sonarqube->projectKey = '项目标识';
|
||||
$lang->sonarqube->projectName = '项目名称';
|
||||
$lang->sonarqube->projectlastAnalysis = '最后执行时间';
|
||||
|
||||
$lang->sonarqube->report = new stdclass();
|
||||
$lang->sonarqube->report->bugs = 'Bugs';
|
||||
$lang->sonarqube->report->vulnerabilities = '弱点';
|
||||
$lang->sonarqube->report->security_hotspots_reviewed = '复审热点';
|
||||
$lang->sonarqube->report->code_smells = '异味';
|
||||
$lang->sonarqube->report->coverage = '覆盖率';
|
||||
$lang->sonarqube->report->duplicated_lines_density = '重复率';
|
||||
$lang->sonarqube->report->ncloc = '行数';
|
||||
|
||||
$lang->sonarqube->qualitygateList = array();
|
||||
$lang->sonarqube->qualitygateList['OK'] = 'Passed';
|
||||
$lang->sonarqube->qualitygateList['WARN'] = 'Warning';
|
||||
$lang->sonarqube->qualitygateList['ERROR'] = 'Failed';
|
||||
|
||||
@@ -22,7 +22,7 @@ class sonarqubeModel extends model
|
||||
public function getApiBase($sonarqubeID)
|
||||
{
|
||||
$sonarqube = $this->loadModel('pipeline')->getByID($sonarqubeID);
|
||||
if(!$sonarqube) return array('', array());
|
||||
if(!$sonarqube) return array('', array());
|
||||
|
||||
$url = rtrim($sonarqube->url, '/') . '/api/%s';
|
||||
$header[] = 'Authorization: Basic ' . $sonarqube->token;
|
||||
@@ -45,6 +45,42 @@ class sonarqubeModel extends model
|
||||
return json_decode(commonModel::http($url, null, array(), $header));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sonarqube report.
|
||||
*
|
||||
* @param int $sonarqubeID
|
||||
* @param stirng $projectKey
|
||||
* @param string $metricKeys
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function apiGetReport($sonarqubeID, $projectKey, $metricKeys = '')
|
||||
{
|
||||
list($apiRoot, $header) = $this->getApiBase($sonarqubeID);
|
||||
if(!$apiRoot) return array();
|
||||
|
||||
if(!$metricKeys) $metricKeys = 'bugs,coverage,vulnerabilities,duplicated_lines_density,code_smells,ncloc,security_hotspots_reviewed';
|
||||
$url = sprintf($apiRoot, "measures/component?component={$projectKey}&metricKeys={$metricKeys}");
|
||||
return json_decode(commonModel::http($url, null, array(), $header));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sonarqube qualitygate by project.
|
||||
*
|
||||
* @param int $sonarqubeID
|
||||
* @param string $projectKey
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function apiGetQualitygate($sonarqubeID, $projectKey)
|
||||
{
|
||||
list($apiRoot, $header) = $this->getApiBase($sonarqubeID);
|
||||
if(!$apiRoot) return array();
|
||||
|
||||
$url = sprintf($apiRoot, "qualitygates/project_status?projectKey={$projectKey}");
|
||||
return json_decode(commonModel::http($url, null, array(), $header));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get projects of one sonarqube.
|
||||
*
|
||||
@@ -53,17 +89,21 @@ class sonarqubeModel extends model
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function apiGetProjects($sonarqubeID, $keyword = '')
|
||||
public function apiGetProjects($sonarqubeID, $keyword = '', $projectKey = '')
|
||||
{
|
||||
list($apiRoot, $header) = $this->getApiBase($sonarqubeID);
|
||||
if(!$apiRoot) return array();
|
||||
|
||||
$url = sprintf($apiRoot, "projects/search");
|
||||
$url = sprintf($apiRoot, "projects/search");
|
||||
$url .= "?ps=500";
|
||||
if($keyword) $url .= "&q={$keyword}";
|
||||
if($projectKey) $url .= "&projects={$projectKey}";
|
||||
|
||||
$allResults = array();
|
||||
for($page = 1; true; $page++)
|
||||
{
|
||||
$result = json_decode(commonModel::http($url. "?p={$page}&ps=500" . ($keyword ? "&q={$keyword}" : ''), null, array(), $header));
|
||||
$url .= "&p={$page}";
|
||||
$result = json_decode(commonModel::http($url, null, array(), $header));
|
||||
if(!isset($result->components)) break;
|
||||
if(!empty($result->components)) $allResults = array_merge($allResults, $result->components);
|
||||
if(count($result->components) < 500) break;
|
||||
|
||||
57
module/sonarqube/view/reportview.html.php
Normal file
57
module/sonarqube/view/reportview.html.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
/**
|
||||
* The reprot file of sonarqubemodule of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
||||
* @author Yuchun Li <liyuchun@easycorp.ltd>
|
||||
* @package sonarqube
|
||||
* @version $Id: reprotview.html.php 935 2022-01-25 10:52:24Z liyuchun@easycorp.ltd $
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<div id='mainContent' class='main-content'>
|
||||
<?php if(empty($measures)): ?>
|
||||
<div class='empty-tip'><?php echo $lang->sonarqube->noReport;?></div>
|
||||
<?php else:?>
|
||||
<div class="main-header">
|
||||
<div class="page-title">
|
||||
<span class='text' title="<?php echo $projectName;?>">
|
||||
<h4>
|
||||
<?php echo $projectName;?>
|
||||
<?php if(!empty($qualitygate->projectStatus->status) and $qualitygate->projectStatus->status != 'NONE'):?>
|
||||
<span class="label label-badge label-<?php echo zget($config->sonarqube->projectStatusClass, $qualitygate->projectStatus->status);?>">
|
||||
<?php echo zget($lang->sonarqube->qualitygateList, $qualitygate->projectStatus->status);?>
|
||||
</span>
|
||||
<?php endif;?>
|
||||
</h4>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<table class="table table-data">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php echo $lang->sonarqube->report->bugs;?></th>
|
||||
<th><?php echo $lang->sonarqube->report->vulnerabilities;?></th>
|
||||
<th><?php echo $lang->sonarqube->report->security_hotspots_reviewed;?></th>
|
||||
<th><?php echo $lang->sonarqube->report->code_smells;?></th>
|
||||
<th><?php echo $lang->sonarqube->report->coverage;?></th>
|
||||
<th><?php echo $lang->sonarqube->report->duplicated_lines_density;?></th>
|
||||
<th><?php echo $lang->sonarqube->report->ncloc;?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><?php echo $measures['bugs']->value;?></td>
|
||||
<td><?php echo $measures['vulnerabilities']->value;?></td>
|
||||
<td><?php echo $measures['security_hotspots_reviewed']->value;?></td>
|
||||
<td><?php echo $measures['code_smells']->value;?></td>
|
||||
<td><?php echo $measures['coverage']->value;?></td>
|
||||
<td><?php echo $measures['duplicated_lines_density']->value;?></td>
|
||||
<td><?php echo $measures['ncloc']->value;?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
Reference in New Issue
Block a user