* Finish task #48094.

This commit is contained in:
liyuchun
2022-01-25 14:19:24 +08:00
parent 461940c671
commit 2b71ad28de
10 changed files with 208 additions and 6 deletions

View File

@@ -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.
*

View File

@@ -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();
}

View File

@@ -1,3 +1,4 @@
.c-id {width: 60px;}
.c-name {width: 200px;}
.c-product {width: 400px;}
.c-actions-7 {width: 210px;}

View File

@@ -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');
?>

View File

@@ -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';

View File

@@ -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.
*

View File

@@ -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';

View File

@@ -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';

View File

@@ -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;

View 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;?>