2023-05-16 10:47:08 +08:00

306 lines
9.7 KiB
PHP

<?php
/**
* The model file of sonarqube module of ZenTaoPMS.
*
* @copyright Copyright 2009-2022 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
* @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Yanyi Cao <caoyanyi@easycorp.ltd>
* @package sonarqube
* @version $Id: $
* @link http://www.zentao.net
*/
class sonarqubeModel extends model
{
/**
* Get sonarqube api base url and header by id.
*
* @param int $sonarqubeID
* @access public
* @return array
*/
public function getApiBase($sonarqubeID)
{
$sonarqube = $this->loadModel('pipeline')->getByID($sonarqubeID);
if(!$sonarqube) return array('', array());
$url = rtrim($sonarqube->url, '/') . '/api/%s';
$header[] = 'Authorization: Basic ' . $sonarqube->token;
return array($url, $header);
}
/**
* check sonarqube valid
*
* @param string $host
* @param string $token
* @access public
* @return array
*/
public function apiValidate($host, $token)
{
$url = rtrim($host, '/') . "/api/authentication/validate";
$header = 'Authorization: Basic ' . $token;
$result = json_decode(commonModel::http($url, null, array(), $header));
if(!isset($result->valid) or !$result->valid) return array('password' => array($this->lang->sonarqube->validError));
$url = rtrim($host, '/') . "/api/user_groups/search";
$header = 'Authorization: Basic ' . $token;
$adminer = json_decode(commonModel::http($url, null, array(), $header));
if(empty($adminer) or isset($adminer->errors)) return array('account' => array($this->lang->sonarqube->notAdminer));
return array();
}
/**
* 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 issues of one sonarqube.
*
* @param int $sonarqubeID
* @param string $projectKey
* @access public
* @return array
*/
public function apiGetIssues($sonarqubeID, $projectKey = '')
{
list($apiRoot, $header) = $this->getApiBase($sonarqubeID);
if(!$apiRoot) return array();
$url = sprintf($apiRoot, "issues/search");
$url .= "?ps=500";
if($projectKey) $url .= "&componentKeys={$projectKey}";
$allResults = array();
for($page = 1; true; $page++)
{
$result = json_decode(commonModel::http($url . "&p={$page}", null, array(), $header));
if(!isset($result->issues)) break;
if(!empty($result->issues)) $allResults = array_merge($allResults, $result->issues);
if(count($result->issues) < 500) break;
}
return $allResults;
}
/**
* Get projects of one sonarqube.
*
* @param int $sonarqubeID
* @param string $keyword
* @access public
* @return array
*/
public function apiGetProjects($sonarqubeID, $keyword = '', $projectKey = '')
{
list($apiRoot, $header) = $this->getApiBase($sonarqubeID);
if(!$apiRoot) return array();
$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}", null, array(), $header));
if(!isset($result->components)) break;
if(!empty($result->components)) $allResults = array_merge($allResults, $result->components);
if(count($result->components) < 500) break;
}
return $allResults;
}
/**
* Create a sonarqube project by api.
*
* @param int $sonarqubeID
* @param object $project
* @access public
* @return object
*/
public function apiCreateProject($sonarqubeID, $project)
{
list($apiRoot, $header) = $this->getApiBase($sonarqubeID);
if(!$apiRoot) return false;
$url = sprintf($apiRoot, "projects/create?name=" . urlencode($project->projectName) . "&project=" . urlencode($project->projectKey));
$result = json_decode(commonModel::http($url, null, array(CURLOPT_CUSTOMREQUEST => 'POST'), $header));
return $result;
}
/**
* Delete sonarqube project by api.
*
* @param int $sonarqubeID
* @param int $projectKey
* @access public
* @return bool|object
*/
public function apiDeleteProject($sonarqubeID, $projectKey)
{
list($apiRoot, $header) = $this->getApiBase($sonarqubeID);
if(!$apiRoot) return false;
$url = sprintf($apiRoot, "projects/delete?project=$projectKey");
$result = json_decode(commonModel::http($url, null, array(CURLOPT_CUSTOMREQUEST => 'POST'), $header));
return $result;
}
/**
* Create a sonarqube project.
*
* @param int $sonarqubeID
* @access public
* @return bool
*/
public function createProject($sonarqubeID)
{
$project = fixer::input('post')->get();
$this->dao->insert('sonarqube')->data($project)
->batchCheck($this->config->sonarqube->createproject->requiredFields, 'notempty');
if(dao::isError()) return false;
if(mb_strlen($project->projectName) > 255) dao::$errors['projectName'][] = sprintf($this->lang->sonarqube->lengthError, $this->lang->sonarqube->projectName, 255);
if(mb_strlen($project->projectKey) > 400) dao::$errors['projectKey'][] = sprintf($this->lang->sonarqube->lengthError, $this->lang->sonarqube->projectKey, 400);
if(dao::isError()) return false;
$response = $this->apiCreateProject($sonarqubeID, $project);
if(!empty($response->project->key))
{
$this->loadModel('action')->create('sonarqubeproject', 0, 'created', '', $response->project->name);
return true;
}
return $this->apiErrorHandling($response);
}
/**
* Api error handling.
*
* @param object $response
* @access public
* @return bool
*/
public function apiErrorHandling($response)
{
if(!empty($response->errors))
{
foreach($response->errors as $error)
{
if(isset($error->msg))
{
dao::$errors[] = $this->convertApiError($error->msg);
}
}
return false;
}
if(!$response) dao::$errors[] = false;
return false;
}
/**
* Convert API error.
*
* @param array $message
* @access public
* @return string
*/
public function convertApiError($message)
{
if(is_array($message)) $message = $message[0];
if(!is_string($message)) return $message;
if(!isset($this->lang->sonarqube->apiErrorMap)) return $message;
foreach($this->lang->sonarqube->apiErrorMap as $key => $errorMsg)
{
if(strpos($errorMsg, '/') === 0)
{
$result = preg_match($errorMsg, $message, $matches);
if($result) $errorMessage = sprintf(zget($this->lang->sonarqube->errorLang, $key), $matches[1]);
}
elseif($message == $errorMsg)
{
$errorMessage = zget($this->lang->mr->errorLang, $key, $message);
}
if(isset($errorMessage)) break;
}
return isset($errorMessage) ? $errorMessage : $message;
}
/**
* Get cache file.
*
* @param int $sonarqubeID
* @param string $projectKey
* @access public
* @return string
*/
public function getCacheFile($sonarqubeID, $projectKey)
{
$cachePath = $this->app->getCacheRoot() . '/' . 'sonarqube';
if(!is_dir($cachePath)) mkdir($cachePath, 0777, true);
if(!is_writable($cachePath)) return false;
return $cachePath . '/' . $sonarqubeID . '-' . md5($projectKey);
}
/**
* Get linked products.
*
* @param int $sonarqubeID
* @param string $projectKey
* @access public
* @return string
*/
public function getLinkedProducts($sonarqubeID, $projectKey)
{
return $this->dao->select('t2.product')->from(TABLE_JOB)->alias('t1')
->leftJoin(TABLE_REPO)->alias('t2')->on('t1.repo=t2.id')
->where('t1.frame')->eq('sonarqube')
->andWhere('sonarqubeServer')->eq($sonarqubeID)
->andWhere('projectKey')->eq($projectKey)
->fetch('product');
}
}