diff --git a/db/update12.2.sql b/db/update12.2.sql index 90fdfb7c3e..ba9caa25a9 100644 --- a/db/update12.2.sql +++ b/db/update12.2.sql @@ -1,2 +1,7 @@ ALTER TABLE `zt_job` ADD `frame` varchar(20) COLLATE 'utf8_general_ci' NOT NULL AFTER `repo`; ALTER TABLE `zt_compile` ADD `testtask` mediumint unsigned NULL AFTER `atTime`; +ALTER TABLE `zt_case` ADD `auto` varchar(10) COLLATE 'utf8_general_ci' NOT NULL DEFAULT 'no' AFTER `type`; +ALTER TABLE `zt_case` ADD `frame` varchar(10) COLLATE 'utf8_general_ci' NOT NULL AFTER `auto`; +ALTER TABLE `zt_testresult` ADD `job` mediumint unsigned NOT NULL AFTER `version`; +ALTER TABLE `zt_testresult` ADD `compile` mediumint unsigned NOT NULL AFTER `job`; +ALTER TABLE `zt_job` ADD `product` mediumint(8) unsigned NOT NULL AFTER `repo`; diff --git a/module/ci/control.php b/module/ci/control.php index a1ebca1b13..25bf374df0 100644 --- a/module/ci/control.php +++ b/module/ci/control.php @@ -76,4 +76,84 @@ class ci extends control echo 'success'; } } + + /** + * Commit result from ztf or unit. + * + * @access public + * @return void + */ + public function commitResult() + { + $post = file_get_contents('php://input'); + $post = json_decode($post); + + $testType = $post->TestType; + $productID = $post->ProductId; + $taskID = $post->TaskId; + $zentaoData = $post->ZentaoData; + + parse_str($zentaoData, $params); + $this->loadModel('testtask'); + $compileID = zget($params, 'compile', 0); + $jobID = 0; + if($compileID) + { + $compile = $this->dao->select('t1.*, t2.jkJob,t2,product,t2.frame,t3.name as jenkinsName,t3.url,t3.account,t3.token,t3.password')->from(TABLE_COMPILE)->alias('t1') + ->leftJoin(TABLE_JOB)->alias('t2')->on('t1.job=t2.id') + ->leftJoin(TABLE_JENKINS)->alias('t3')->on('t2.jkHost=t3.id') + ->where('t1.id')->eq($compileID) + ->fetch(); + + $jobID = $compile->job; + if(empty($productID)) $productID = $compile->product; + if($compile->status != 'success' and $compile->status != 'fail' and $compile->status != 'create_fail' and $compile->status != 'timeout') + { + $this->loadModel('compile')->checkStatus($compile); + } + + $this->dao->update(TABLE_COMPILE)->set('testtask')->eq($taskID)->where('id')->eq($compile->id)->exec(); + } + + if(!empty($taskID)) + { + $testtask = $this->testtask->getById($taskID); + $productID = $testtask->product; + } + else + { + $lastProject = $this->dao->select('t1.*')->from(TABLE_PROJECTPRODUCT)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project=t2.id') + ->where('t1.product')->eq($productID) + ->andWhere('t2.deleted')->eq(0) + ->orderBy('project desc') + ->limit(1) + ->fetch('project'); + + $testtask = new stdclass(); + $testtask->product = $productID; + $testtask->name = sprintf($this->lang->testtask->unitTitleTemplate, date('Y-m-d H:i:s')); + $testtask->owner = $this->app->user->account; + $testtask->project = $lastProject; + $testtask->build = 'trunk'; + $testtask->begin = date('Y-m-d'); + $testtask->end = date('Y-m-d', time() + 24 * 3600); + $testtask->status = 'done'; + + $this->dao->insert(TABLE_TESTTASK)->data($testtask)->exec(); + $taskID = $this->dao->lastInsertId(); + $this->loadModel('action')->create('testtask', $taskID, 'opened'); + } + + if($testType == 'unit') + { + $data = $this->testtask->buildDataFromUnit($post->UnitCaseResults, $productID, $jobID, $compileID); + } + elseif($testType == 'ztf') + { + $data = $this->testtask->buildDataFromZtf($post->ZtfCaseResults, $productID, $jobID, $compileID); + } + + $taskID = $this->testtask->saveUnit($taskID, $data['suites'], $data['cases'], $data['results'], $data['suiteNames'], $data['caseTitles']); + } } diff --git a/module/ci/model.php b/module/ci/model.php index ed93df153d..21f380eb1a 100644 --- a/module/ci/model.php +++ b/module/ci/model.php @@ -42,60 +42,69 @@ class ciModel extends model ->andWhere('t1.createdDate')->gt(date(DT_DATETIME1, strtotime("-1 day"))) ->fetchAll(); - foreach($compiles as $compile) + foreach($compiles as $compile) $this->checkStatus($compile); + } + + /** + * Check status. + * + * @param object $compile + * @access public + * @return void + */ + public function checkStatus($compile) + { + $jenkinsServer = $compile->url; + $jenkinsUser = $compile->account; + $jenkinsPassword = $compile->token ? $compile->token : base64_decode($compile->password); + + $jenkinsAuth = '://' . $jenkinsUser . ':' . $jenkinsPassword . '@'; + $jenkinsServer = str_replace('://', $jenkinsAuth, $jenkinsServer); + $queueUrl = sprintf('%s/queue/item/%s/api/json', $jenkinsServer, $compile->queue); + + $response = common::http($queueUrl); + if(strripos($response, "404") > -1) { - $jenkinsServer = $compile->url; - $jenkinsUser = $compile->account; - $jenkinsPassword = $compile->token ? $compile->token : base64_decode($compile->password); - - $jenkinsAuth = '://' . $jenkinsUser . ':' . $jenkinsPassword . '@'; - $jenkinsServer = str_replace('://', $jenkinsAuth, $jenkinsServer); - $queueUrl = sprintf('%s/queue/item/%s/api/json', $jenkinsServer, $compile->queue); - - $response = common::http($queueUrl); - if(strripos($response, "404") > -1) + $infoUrl = sprintf("%s/job/%s/api/xml?tree=builds[id,number,result,queueId]&xpath=//build[queueId=%s]", $jenkinsServer, $compile->jkJob, $compile->queue); + $response = common::http($infoUrl); + if($response) { - $infoUrl = sprintf("%s/job/%s/api/xml?tree=builds[id,number,result,queueId]&xpath=//build[queueId=%s]", $jenkinsServer, $compile->jkJob, $compile->queue); - $response = common::http($infoUrl); - if($response) + $buildInfo = simplexml_load_string($response); + $buildNumber = strtolower($buildInfo->number); + $result = strtolower($buildInfo->result); + $this->updateBuildStatus($compile, $result); + + $logUrl = sprintf('%s/job/%s/%s/consoleText', $jenkinsServer, $compile->jkJob, $buildNumber); + $response = common::http($logUrl); + $this->dao->update(TABLE_COMPILE)->set('logs')->eq($response)->where('id')->eq($compile->id)->exec(); + } + } + else + { + $queueInfo = json_decode($response); + if(!empty($queueInfo->executable)) + { + $buildUrl = $queueInfo->executable->url . 'api/json?pretty=true'; + $buildUrl = str_replace('://', $jenkinsAuth, $buildUrl); + + $response = common::http($buildUrl); + $buildInfo = json_decode($response); + + if($buildInfo->building) { - $buildInfo = simplexml_load_string($response); - $buildNumber = strtolower($buildInfo->number); - $result = strtolower($buildInfo->result); + $this->updateBuildStatus($compile, 'building'); + } + else + { + $result = strtolower($buildInfo->result); $this->updateBuildStatus($compile, $result); - $logUrl = sprintf('%s/job/%s/%s/consoleText', $jenkinsServer, $compile->jkJob, $buildNumber); + $logUrl = $buildInfo->url . 'logText/progressiveText/api/json'; + $logUrl = str_replace('://', $jenkinsAuth, $logUrl); $response = common::http($logUrl); $this->dao->update(TABLE_COMPILE)->set('logs')->eq($response)->where('id')->eq($compile->id)->exec(); } } - else - { - $queueInfo = json_decode($response); - if(!empty($queueInfo->executable)) - { - $buildUrl = $queueInfo->executable->url . 'api/json?pretty=true'; - $buildUrl = str_replace('://', $jenkinsAuth, $buildUrl); - - $response = common::http($buildUrl); - $buildInfo = json_decode($response); - - if($buildInfo->building) - { - $this->updateBuildStatus($compile, 'building'); - } - else - { - $result = strtolower($buildInfo->result); - $this->updateBuildStatus($compile, $result); - - $logUrl = $buildInfo->url . 'logText/progressiveText/api/json'; - $logUrl = str_replace('://', $jenkinsAuth, $logUrl); - $response = common::http($logUrl); - $this->dao->update(TABLE_COMPILE)->set('logs')->eq($response)->where('id')->eq($compile->id)->exec(); - } - } - } } } diff --git a/module/common/model.php b/module/common/model.php index d7e3093493..eac38ee074 100644 --- a/module/common/model.php +++ b/module/common/model.php @@ -162,6 +162,7 @@ class commonModel extends model if($module == 'sso' and $method == 'gettodolist') return true; if($module == 'block' and $method == 'main' and isset($_GET['hash'])) return true; if($module == 'file' and $method == 'read') return true; + if($module == 'ci' and $method == 'commitresult') return true; if($this->loadModel('user')->isLogon() or ($this->app->company->guest and $this->app->user->account == 'guest')) { diff --git a/module/compile/model.php b/module/compile/model.php index 665b40afbc..9afbc234ad 100644 --- a/module/compile/model.php +++ b/module/compile/model.php @@ -118,6 +118,7 @@ class compileModel extends model $tagData = new stdclass(); $tagData->PARAM_TAG = $compile->tag; + $tagData->PARAM_ZENTAODATA = "compile={$compile->id}"; $buildUrl = $this->getBuildUrl($job); $build = new stdclass(); diff --git a/module/job/control.php b/module/job/control.php index cf2fe17c49..b0be413315 100644 --- a/module/job/control.php +++ b/module/job/control.php @@ -84,6 +84,7 @@ class job extends control } $this->view->repoPairs = $repoPairs; $this->view->repoTypes = $repoTypes; + $this->view->products = array(0 => '') + $this->loadModel('product')->getPairs(); $this->view->jkHostList = $this->loadModel('jenkins')->getPairs(); $this->display(); @@ -127,6 +128,7 @@ class job extends control $this->view->repoTypes = $repoTypes; $this->view->repoType = zget($repoTypes, $job->repo, 'Git'); $this->view->job = $job; + $this->view->products = array(0 => '') + $this->loadModel('product')->getPairs(); $this->view->jkHostList = $this->loadModel('jenkins')->getPairs(); $this->view->jkJobs = $this->jenkins->getTasks($job->jkHost); diff --git a/module/job/lang/zh-cn.php b/module/job/lang/zh-cn.php index 22c2408771..f63de649fb 100644 --- a/module/job/lang/zh-cn.php +++ b/module/job/lang/zh-cn.php @@ -12,6 +12,7 @@ $lang->job->buildTag = '打标签'; $lang->job->id = 'ID'; $lang->job->name = '名称'; $lang->job->repo = '代码库'; +$lang->job->product = '关联产品'; $lang->job->svnDir = 'SVN监控路径'; $lang->job->jenkins = 'Jenkins'; $lang->job->jkHost = 'Jenkins服务器'; diff --git a/module/job/model.php b/module/job/model.php index 2a35eb2736..8c4c41b114 100644 --- a/module/job/model.php +++ b/module/job/model.php @@ -265,13 +265,19 @@ class jobModel extends model $build->atTime = $job->atTime; } - $build->queue = $this->loadModel('ci')->sendRequest($buildUrl, $data); - $build->status = $build->queue ? 'created' : 'create_fail'; $build->createdBy = $this->app->user->account; $build->createdDate = $now; $build->updateDate = $now; $this->dao->insert(TABLE_COMPILE)->data($build)->exec(); - $this->dao->update(TABLE_JOB)->set('lastExec')->eq($now)->set('lastStatus')->eq($build->status)->where('id')->eq($job->id)->exec(); + $compileID = $this->dao->lastInsertId(); + + $data->PARAM_ZENTAODATA = "compile={$compileID}"; + $compile = new stdclass(); + $compile->queue = $this->loadModel('ci')->sendRequest($buildUrl, $data); + $compile->status = $compile->queue ? 'created' : 'create_fail'; + $this->dao->update(TABLE_COMPILE)->data($compile)->where('id')->eq($compileID)->exec(); + + $this->dao->update(TABLE_JOB)->set('lastExec')->eq($now)->set('lastStatus')->eq($compile->status)->where('id')->eq($job->id)->exec(); return $build->status; } diff --git a/module/job/view/create.html.php b/module/job/view/create.html.php index d5fdb26b50..f25dd6dd54 100644 --- a/module/job/view/create.html.php +++ b/module/job/view/create.html.php @@ -34,6 +34,10 @@ job->repo; ?> + + job->product; ?> + + job->frame; ?> job->frameList, '', "class='form-control chosen'"); ?> diff --git a/module/job/view/edit.html.php b/module/job/view/edit.html.php index a19da86983..fbc5a36da6 100644 --- a/module/job/view/edit.html.php +++ b/module/job/view/edit.html.php @@ -36,6 +36,10 @@ repo, "class='form-control chosen'");?> + + job->product; ?> + product, "class='form-control chosen'"); ?> + job->frame; ?> job->frameList, $job->frame, "class='form-control chosen'"); ?> diff --git a/module/testtask/lang/zh-cn.php b/module/testtask/lang/zh-cn.php index 489811a16b..a1b54ac3e0 100644 --- a/module/testtask/lang/zh-cn.php +++ b/module/testtask/lang/zh-cn.php @@ -118,6 +118,7 @@ $lang->testtask->noTesttask = '暂时没有测试单'; $lang->testtask->checkLinked = '请检查测试单的产品是否与项目相关联'; $lang->testtask->noImportData = '导入的XML没有解析出数据。'; $lang->testtask->unitXMLFormat = '请选择Junit XML 格式的文件。'; +$lang->testtask->unitTitleTemplate = "%s 单元测试"; $lang->testtask->assignedToMe = '指派给我'; $lang->testtask->allCases = '所有用例'; diff --git a/module/testtask/model.php b/module/testtask/model.php index 0164a7bcc8..d6fc90d34e 100644 --- a/module/testtask/model.php +++ b/module/testtask/model.php @@ -1570,6 +1570,8 @@ class testtaskModel extends model $case->openedBy = $this->app->user->account; $case->openedDate = $now; $case->version = 1; + $case->auto = 'unit'; + $case->frame = 'junit'; $attributes = $matchNode->attributes(); foreach($nameFields as $field) @@ -1606,7 +1608,7 @@ class testtaskModel extends model $case->lastRunDate = $now; $case->lastRunResult = $result->caseResult; - $titles[$suiteIndex][] = $case->title; + $caseTitles[$suiteIndex][] = $case->title; $cases[$suiteIndex][$caseIndex] = $case; $results[$suiteIndex][$caseIndex] = $result; } @@ -1617,6 +1619,23 @@ class testtaskModel extends model unlink($fileName); if(dao::isError()) return false; + return $this->saveUnit($testtaskID, $suites, $cases, $results, $suiteNames, $caseTitles); + } + + /** + * Save unit. + * + * @param int $testtaskID + * @param array $suites + * @param array $cases + * @param array $results + * @param array $suiteNames + * @param array $caseTitles + * @access public + * @return int + */ + public function saveUnit($testtaskID, $suites, $cases, $results, $suiteNames = array(), $caseTitles = array()) + { /* Import cases and link task and insert result. */ $this->loadModel('action'); $existSuites = $this->dao->select('*')->from(TABLE_TESTSUITE)->where('name')->in($suiteNames)->andWhere('product')->eq($productID)->andWhere('type')->eq('unit')->andWhere('deleted')->eq(0)->fetchPairs('name', 'id'); @@ -1654,7 +1673,12 @@ class testtaskModel extends model foreach($cases[$suiteIndex] as $i => $case) { - if(!isset($existCases[$case->title])) + if(isset($case->id)) + { + $caseID = $case->id; + $this->dao->update(TABLE_CASE)->data($case)->where('id')->eq($caseID)->exec(); + } + elseif(!isset($existCases[$case->title])) { $this->dao->insert(TABLE_CASE)->data($case)->exec(); $caseID = $this->dao->lastInsertID(); @@ -1696,4 +1720,134 @@ class testtaskModel extends model return $testtaskID; } + + public function buildDataFromUnit($caseResults, $productID, $jobID, $compileID) + { + $now = helper::now(); + $cases = array(); + $results = array(); + $suites = array(); + $caseTitles = array(); + $suiteNames = array(); + $suiteIndex = 0; + foreach($caseResults as $caseIndex => $caseResult) + { + $suite = ''; + if(isset($caseResult->TestSuite) and !isset($suiteNames[$suite->name])) + { + $suite = new stdclass(); + $suite->product = $productID; + $suite->name = $caseResult->TestSuite; + $suite->type = 'unit'; + $suite->addedBy = $this->app->user->account; + $suite->addedDate = $now; + + $suiteNames[$suite->name] = $suite->name; + $suiteIndex ++; + } + if(!isset($suites[$suiteIndex])) $suites[$suiteIndex] = $suite; + + $case = new stdclass(); + $case->product = $productID; + $case->title = $caseResult->TestSuite . ' ' . $caseResult->Title; + $case->pri = 3; + $case->type = 'unit'; + $case->stage = 'unittest'; + $case->status = 'normal'; + $case->openedBy = $this->app->user->account; + $case->openedDate = $now; + $case->version = 1; + $case->auto = 'unit'; + $case->frame = $caseResult->TestFrame; + + $result = new stdclass(); + $result->case = 0; + $result->version = 1; + $result->caseResult = 'pass'; + $result->lastRunner = $this->app->user->account; + $result->job = $jobID; + $result->compile = $compileID; + $result->date = $now; + $result->stepResults[0]['result'] = 'pass'; + $result->stepResults[0]['real'] = ''; + if(!empty($caseResult->Failure)) + { + $result->caseResult = 'fail'; + $result->stepResults[0]['result'] = 'fail'; + $result->stepResults[0]['real'] = $caseResult->Failure->Desc; + } + $result->stepResults = serialize($result->stepResults); + $case->lastRunner = $this->app->user->account; + $case->lastRunDate = $now; + $case->lastRunResult = $result->caseResult; + + $caseTitles[$suiteIndex][] = $case->title; + $cases[$suiteIndex][$caseIndex] = $case; + $results[$suiteIndex][$caseIndex] = $result; + } + + return array('suites' => $suites, 'cases' => $cases, 'results' => $results, 'suiteNames' => $suiteNames, 'caseTitles' => $caseTitles); + } + + public function buildDataFromZtf($caseResults, $productID, $jobID, $compileID) + { + $now = helper::now(); + $cases = array(); + $results = array(); + $suites = array(); + $caseTitles = array(); + $suiteNames = array(); + $suiteIndex = 0; + foreach($caseResults as $caseIndex => $caseResult) + { + $suite = ''; + if(!isset($suites[$suiteIndex])) $suites[$suiteIndex] = $suite; + + $case = new stdclass(); + $case->product = $productID; + $case->title = $caseResult->Title; + $case->pri = 3; + $case->type = 'unit'; + $case->stage = 'unittest'; + $case->status = 'normal'; + $case->openedBy = $this->app->user->account; + $case->openedDate = $now; + $case->version = 1; + $case->auto = 'ztf'; + $case->frame = $caseResult->TestFrame; + + $result = new stdclass(); + $result->case = 0; + $result->version = 1; + $result->caseResult = 'pass'; + $result->lastRunner = $this->app->user->account; + $result->job = $jobID; + $result->compile = $compileID; + $result->date = $now; + $result->stepResults[0]['result'] = 'pass'; + $result->stepResults[0]['real'] = ''; + if(!empty($caseResult->Steps)) + { + $result->stepResults = array(); + $stepStatus = 'pass'; + foreach($caseResult->Steps as $i => $step) + { + $result->stepResults[$i]['result'] = $step->Status ? 'pass' : 'fail'; + $result->stepResults[$i]['real'] = $step->Status ? '' : $step->CheckPoints[0]->Actual; + if(!$step->Status) $stepStatus = 'fail'; + } + $result->caseResult = $stepStatus; + } + $result->stepResults = serialize($result->stepResults); + $case->lastRunner = $this->app->user->account; + $case->lastRunDate = $now; + $case->lastRunResult = $result->caseResult; + + $caseTitles[$suiteIndex][] = $case->title; + $cases[$suiteIndex][$caseIndex] = $case; + $results[$suiteIndex][$caseIndex] = $result; + } + + return array('suites' => $suites, 'cases' => $cases, 'results' => $results, 'suiteNames' => $suiteNames, 'caseTitles' => $caseTitles); + } } diff --git a/module/testtask/view/importunit.html.php b/module/testtask/view/importunit.html.php index 370b666e18..32541c14fb 100644 --- a/module/testtask/view/importunit.html.php +++ b/module/testtask/view/importunit.html.php @@ -71,7 +71,7 @@ testtask->name;?> - + testtask->unitTitleTemplate, date('Y-m-d H:i:s')), "class='form-control'");?> testtask->desc;?>