465 lines
17 KiB
PHP
465 lines
17 KiB
PHP
<?php
|
||
$p = new prepareUpdate();
|
||
|
||
class prepareUpdate
|
||
{
|
||
public $internalZT;
|
||
public $mysqlConfig;
|
||
|
||
/**
|
||
* Construct.
|
||
*
|
||
* @access public
|
||
* @return void
|
||
*/
|
||
public function __construct()
|
||
{
|
||
$this->initZT();
|
||
$this->initMysql();
|
||
$this->addChangelog();
|
||
$this->changeVersion();
|
||
$this->addReleaseDetail();
|
||
$this->addLastVersion();
|
||
$this->addVersionCorrespondence();
|
||
$this->addConfirmedSql();
|
||
$this->exportStandardSql();
|
||
|
||
$this->checkInstallSql();
|
||
$this->checkLang();
|
||
}
|
||
|
||
/**
|
||
* Init mysql config.
|
||
*
|
||
* @access public
|
||
* @return void
|
||
*/
|
||
public function initMysql()
|
||
{
|
||
$this->mysqlConfig = new stdclass();
|
||
$this->mysqlConfig->account = 'zentao';
|
||
$this->mysqlConfig->password = '123456';
|
||
$this->mysqlConfig->databaseName = 'zentaostandard';
|
||
}
|
||
|
||
/**
|
||
* Init zentao config.
|
||
*
|
||
* @access public
|
||
* @return void
|
||
*/
|
||
public function initZT()
|
||
{
|
||
$this->internalZT = new stdclass();
|
||
$this->internalZT->apiRoot = '';
|
||
$this->internalZT->account = '';
|
||
$this->internalZT->password = '';
|
||
$this->internalZT->token = $this->getZTToken();
|
||
|
||
$this->internalZT->pmsProductID = '';
|
||
$this->internalZT->bizProductID = '';
|
||
$this->internalZT->maxProductID = '';
|
||
$this->internalZT->ipdProductID = '';
|
||
|
||
$this->getLatestVersion();
|
||
}
|
||
|
||
/**
|
||
* Get zentao token.
|
||
*
|
||
* @access public
|
||
* @return void
|
||
*/
|
||
public function getZTToken()
|
||
{
|
||
$tokenUrl = "{$this->internalZT->apiRoot}/tokens";
|
||
$data = array('account' => $this->internalZT->account, 'password' => $this->internalZT->password);
|
||
|
||
$response = $this->http($tokenUrl, $data, array(), array(), 'json');
|
||
$response = json_decode($response);
|
||
|
||
return $response->token;
|
||
}
|
||
|
||
/**
|
||
* Add the changelog of the newest release.
|
||
*
|
||
* @access public
|
||
* @return void
|
||
*/
|
||
public function addChangelog()
|
||
{
|
||
$relatedStoriesAndBugs = $this->getRelatedStoriesAndBugs();
|
||
$oldChangelog = file_get_contents('../doc/CHANGELOG');
|
||
file_put_contents('../doc/CHANGELOG', $relatedStoriesAndBugs . "\n" . $oldChangelog);
|
||
}
|
||
|
||
/**
|
||
* Get stories and bugs of the releases for changelog.
|
||
*
|
||
* @access public
|
||
* @return string
|
||
*/
|
||
public function getRelatedStoriesAndBugs()
|
||
{
|
||
$latestReleases = $this->getLatestRelease();
|
||
$title = array('pms' => '开源版:', 'biz' => '企业版:', 'max' => '旗舰版:', 'ipd' => 'IPD版:');
|
||
|
||
$releaseHeader = date('Y-m-d') . ' ' . $this->internalZT->pmsVersion . "\n";
|
||
$doneStories = "完成的需求\n";
|
||
$fixedBugs = "修复的Bug\n";
|
||
foreach($latestReleases as $product => $release)
|
||
{
|
||
$stories = array_filter(explode(',', trim($release->stories, ',')));
|
||
$bugs = array_filter(explode(',', trim($release->bugs, ',')));
|
||
|
||
if(!empty($stories)) $doneStories .= $title[$product] . "\n";
|
||
if(!empty($bugs)) $fixedBugs .= $title[$product] . "\n";
|
||
foreach($stories as $storyID)
|
||
{
|
||
$storyTitle = $this->getStoryOrBugTitle('story', $storyID);
|
||
$storyTitle = htmlspecialchars_decode($storyTitle);
|
||
$doneStories .= $storyTitle ? $storyID . ' ' . $storyTitle . "\n" : '';
|
||
}
|
||
|
||
foreach($bugs as $bugID)
|
||
{
|
||
$bugTitle = $this->getStoryOrBugTitle('bug', $bugID);
|
||
$bugTitle = htmlspecialchars_decode($bugTitle);
|
||
$fixedBugs .= $bugTitle ? $bugID . ' ' . $bugTitle . "\n" : '';
|
||
}
|
||
}
|
||
|
||
return $releaseHeader . $doneStories . $fixedBugs;
|
||
}
|
||
|
||
/**
|
||
* Get the title of story or bug.
|
||
*
|
||
* @access public
|
||
* @return string
|
||
*/
|
||
public function getStoryOrBugTitle($objectType, $objectID)
|
||
{
|
||
$type = $objectType == 'story' ? 'stories' : 'bugs';
|
||
$storyUrl = "{$this->internalZT->apiRoot}/{$type}/{$objectID}";
|
||
$headers[] = "Token: {$this->internalZT->token}";
|
||
|
||
$response = $this->http($storyUrl, null, array(), $headers, 'json', 'GET');
|
||
$response = json_decode($response);
|
||
|
||
return $response ? $response->title : '';
|
||
}
|
||
|
||
/**
|
||
* Get pms, biz and max latest version.
|
||
*
|
||
* @access public
|
||
* @return void
|
||
*/
|
||
public function getLatestVersion()
|
||
{
|
||
$releases = $this->getLatestRelease();
|
||
foreach($releases as $product => $release)
|
||
{
|
||
$releaseParse = explode(' ', $release->name);
|
||
$this->internalZT->{$product . 'Version'} = str_replace('.stable', '', $releaseParse[1]);
|
||
$this->internalZT->{$product . 'VersionAB'} = str_replace('.', '_', $this->internalZT->{$product . 'Version'});
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Get last ipd version.
|
||
*
|
||
* @param object $lastIPDRelease
|
||
* @access public
|
||
* @return array
|
||
*/
|
||
public function getLastIPDVersion($lastIPDRelease)
|
||
{
|
||
$releaseParse = explode(' ', $lastIPDRelease->name);
|
||
$this->internalZT->lastIPDVersion = str_replace('.stable', '', $releaseParse[1]);
|
||
$this->internalZT->lastIPDVersionAB = str_replace('.', '_', $this->internalZT->lastIPDVersion);
|
||
}
|
||
|
||
/**
|
||
* Get pms, biz, max and ipd latest release.
|
||
*
|
||
* @access public
|
||
* @return array
|
||
*/
|
||
public function getLatestRelease()
|
||
{
|
||
$pmsReleases = $this->getReleases($this->internalZT->pmsProductID);
|
||
$pmsLatestRelease = current($pmsReleases);
|
||
|
||
$bizReleases = $this->getReleases($this->internalZT->bizProductID);
|
||
$bizLatestRelease = current($bizReleases);
|
||
|
||
$maxReleases = $this->getReleases($this->internalZT->maxProductID);
|
||
$maxLatestRelease = current($maxReleases);
|
||
|
||
$ipdReleases = $this->getReleases($this->internalZT->ipdProductID);
|
||
$ipdLatestRelease = current($ipdReleases);
|
||
$this->getLastIPDVersion($ipdReleases[1]);
|
||
|
||
return array('pms' => $pmsLatestRelease, 'biz' => $bizLatestRelease, 'max' => $maxLatestRelease, 'ipd' => $ipdLatestRelease);
|
||
}
|
||
|
||
/**
|
||
* Get releases by api.
|
||
*
|
||
* @param int $productID
|
||
* @access public
|
||
* @return array
|
||
*/
|
||
public function getReleases($productID)
|
||
{
|
||
$releaseUrl = "{$this->internalZT->apiRoot}/products/{$productID}/releases";
|
||
$headers[] = "Token: {$this->internalZT->token}";
|
||
|
||
$response = $this->http($releaseUrl, null, array(), $headers, 'json', 'GET');
|
||
$response = json_decode($response);
|
||
|
||
return $response->releases;
|
||
}
|
||
|
||
/**
|
||
* Update the newest version.
|
||
*
|
||
* @access public
|
||
* @return void
|
||
*/
|
||
public function changeVersion()
|
||
{
|
||
$lastVersion = file_get_contents('../VERSION');
|
||
$lastVersion = trim($lastVersion);
|
||
|
||
$this->internalZT->lastPmsVersion = $lastVersion;
|
||
$this->internalZT->lastPmsVersionAB = str_replace('.', '_', $lastVersion);
|
||
|
||
file_put_contents('../VERSION', $this->internalZT->pmsVersion);
|
||
`sed -i "s/\$config->version = '$lastVersion'/\$config->version = '{$this->internalZT->pmsVersion}'/" ../config/config.php`;
|
||
}
|
||
|
||
/**
|
||
* Add the release's detail.
|
||
*
|
||
* @access public
|
||
* @return void
|
||
*/
|
||
public function addReleaseDetail()
|
||
{
|
||
$date = date('Y-m-d');
|
||
$releases = $this->getLatestRelease();
|
||
|
||
$detail = '';
|
||
foreach($releases as $product => $release) $detail .= $release->desc;
|
||
|
||
foreach(array('de', 'fr', 'en', 'zh-cn') as $lang) `sed -i "s/\/\* Release Date. \*\/$/\/* Release Date. *\/\\n\\\$lang->misc->releaseDate['{$this->internalZT->pmsVersion}'] = '$date';/" ../module/misc/lang/$lang.php`;
|
||
|
||
`sed -i "s/\/\* Release Detail. \*\/$/\/* Release Detail. *\/\\n\\\$lang->misc->feature->all['{$this->internalZT->pmsVersion}'][] = array('title' => '$detail', 'desc' => '');/" ../module/misc/lang/zh-cn.php`;
|
||
}
|
||
|
||
/**
|
||
* Add the last version for update.
|
||
*
|
||
* @access public
|
||
* @return void
|
||
*/
|
||
public function addLastVersion()
|
||
{
|
||
`sed -i "s/ \/\/ pms insert position\.$/\\n\\\$lang->upgrade->fromVersions['{$this->internalZT->pmsVersionAB}'] = '{$this->internalZT->pmsVersion}'; \/\/ pms insert position\./" ../module/upgrade/lang/version.php`;
|
||
`sed -i "s/ \/\/ biz insert position\.$/\\n\\\$lang->upgrade->fromVersions['biz{$this->internalZT->bizVersionAB}'] = 'Biz{$this->internalZT->bizVersion}'; \/\/ biz insert position\./" ../module/upgrade/lang/version.php`;
|
||
`sed -i "s/ \/\/ max insert position\.$/\\n\\\$lang->upgrade->fromVersions['max{$this->internalZT->maxVersionAB}'] = 'Max{$this->internalZT->maxVersion}'; \/\/ max insert position\./" ../module/upgrade/lang/version.php`;
|
||
`sed -i "s/ \/\/ ipd insert position\.$/\\n\\\$lang->upgrade->fromVersions['ipd{$this->internalZT->lastIPDVersionAB}'] = 'Ipd{$this->internalZT->lastIPDVersion}'; \/\/ ipd insert position\./" ../module/upgrade/lang/version.php`;
|
||
}
|
||
|
||
/**
|
||
* Add the version correspondence between open source and business.
|
||
*
|
||
* @access public
|
||
* @return void
|
||
*/
|
||
public function addVersionCorrespondence()
|
||
{
|
||
`sed -i "s/ \/\/ biz insert position\.$/\\n\\\$config->upgrade->bizVersion['biz{$this->internalZT->bizVersionAB}'] = '{$this->internalZT->pmsVersionAB}'; \/\/ biz insert position\./" ../module/upgrade/config.php`;
|
||
`sed -i "s/ \/\/ max insert position\.$/\\n\\\$config->upgrade->maxVersion['max{$this->internalZT->maxVersionAB}'] = '{$this->internalZT->pmsVersionAB}'; \/\/ max insert position\./" ../module/upgrade/config.php`;
|
||
`sed -i "s/ \/\/ ipd insert position\.$/\\n\\\$config->upgrade->ipdVersion['ipd{$this->internalZT->ipdVersionAB}'] = '{$this->internalZT->pmsVersionAB}'; \/\/ ipd insert position\./" ../module/upgrade/config.php`;
|
||
}
|
||
|
||
/**
|
||
* Add the confirm sql for update.
|
||
*
|
||
* @access public
|
||
* @return void
|
||
*/
|
||
public function addConfirmedSql()
|
||
{
|
||
if(file_exists("../db/update{$this->internalZT->lastPmsVersion}.sql"))
|
||
{
|
||
`sed -i "s/ \/\/ confirm insert position\.$/\\n case '{$this->internalZT->lastPmsVersionAB}':\\n \\\$confirmContent .= file_get_contents(\\\$this->getUpgradeFile('{$this->internalZT->lastPmsVersion}')); \/\/ confirm insert position\./" ../module/upgrade/model.php`;
|
||
}
|
||
else
|
||
{
|
||
`sed -i "s/ \/\/ confirm insert position\.$/\\n case '{$this->internalZT->lastPmsVersionAB}': \/\/ confirm insert position\./" ../module/upgrade/model.php`;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Export standard sql.
|
||
*
|
||
* @access public
|
||
* @return void
|
||
*/
|
||
public function exportStandardSql()
|
||
{
|
||
$updateSqlFile = "../db/update{$this->internalZT->lastPmsVersion}.sql";
|
||
if(!file_exists($updateSqlFile))
|
||
{
|
||
`cp ../db/standard/zentao{$this->internalZT->lastPmsVersion}.sql ../db/standard/zentao{$this->internalZT->pmsVersion}.sql`;
|
||
return true;
|
||
}
|
||
|
||
$lastStandardSql = file_get_contents("../db/standard/zentao{$this->internalZT->lastPmsVersion}.sql");
|
||
file_put_contents("/tmp/lastStandard.sql", "SET @@sql_mode='';\n$lastStandardSql");
|
||
|
||
`mysql -u{$this->mysqlConfig->account} -p{$this->mysqlConfig->password} -e "DROP DATABASE IF EXISTS {$this->mysqlConfig->databaseName}"`;
|
||
`mysql -u{$this->mysqlConfig->account} -p{$this->mysqlConfig->password} -e "CREATE DATABASE IF NOT EXISTS {$this->mysqlConfig->databaseName}"`;
|
||
`mysql -u{$this->mysqlConfig->account} -p{$this->mysqlConfig->password} -D {$this->mysqlConfig->databaseName} < /tmp/lastStandard.sql`;
|
||
`mysql -u{$this->mysqlConfig->account} -p{$this->mysqlConfig->password} -D {$this->mysqlConfig->databaseName} < $updateSqlFile`;
|
||
|
||
`mysqldump -u{$this->mysqlConfig->account} -p{$this->mysqlConfig->password} --compact --no-data {$this->mysqlConfig->databaseName} > ../db/standard/zentao{$this->internalZT->pmsVersion}.sql`;
|
||
|
||
$content = file_get_contents("../db/standard/zentao{$this->internalZT->pmsVersion}.sql");
|
||
$content = preg_replace(array("/\/\*[\s\S]*?\*\/;\n/", "/SET (.*?);\n/"), '', $content);
|
||
file_put_contents("../db/standard/zentao{$this->internalZT->pmsVersion}.sql", $content);
|
||
}
|
||
|
||
/**
|
||
* Check whether update sql and install sql are consistent.
|
||
*
|
||
* @access public
|
||
* @return void
|
||
*/
|
||
public function checkInstallSql()
|
||
{
|
||
$updateSqlFile = "../db/update{$this->internalZT->lastPmsVersion}.sql";
|
||
if(!file_exists($updateSqlFile)) return true;
|
||
|
||
$updateSql = file_get_contents($updateSqlFile);
|
||
$sqlList = explode(';', $updateSql);
|
||
$errorSql = '';
|
||
|
||
foreach($sqlList as $sql)
|
||
{
|
||
preg_match("/(CREATE|ALTER) TABLE (.*?)(`(.*?)`)[\s\S]*/", $sql, $matches);
|
||
|
||
if(empty($matches)) continue;
|
||
|
||
$table = $matches[3];
|
||
$updateSql = $matches[0];
|
||
|
||
preg_match("/CREATE TABLE (.*)$table [\s\S]*?;/", file_get_contents('../db/zentao.sql'), $matches);
|
||
$createTableSql = $matches[0];
|
||
|
||
$errorSql .= $table . ":\n";
|
||
|
||
/* Create table sql. */
|
||
if(strpos($updateSql, 'CREATE TABLE') !== false)
|
||
{
|
||
if($updateSql . ';' != $createTableSql) $errorSql .= $updateSql . "\n";
|
||
continue;
|
||
}
|
||
|
||
/* Alter table sql. */
|
||
foreach(explode(',', $sql) as $option)
|
||
{
|
||
$option = preg_replace('/ AFTER `.*`/', '', $option);
|
||
$option = trim($option, ';');
|
||
if(stripos($option, 'ADD ') !== false or stripos($option, 'MODIFY ') !== false)
|
||
{
|
||
preg_match("/(ADD|MODIFY) (COLUMN )*((`(.*?)`) (.*)?)/i", $option, $matches);
|
||
if(strpos($createTableSql, $matches[3]) === false) $errorSql .= $option . "\n";
|
||
}
|
||
if(stripos($option, 'CHANGE ') !== false)
|
||
{
|
||
preg_match("/CHANGE (COLUMN )*(`(.*?)`) ((`(.*?)`) (.*)?)/i", $option, $matches);
|
||
if(strpos($createTableSql, $matches[4]) === false) $errorSql .= $option . "\n";
|
||
}
|
||
if(stripos($option, 'DROP ') !== false)
|
||
{
|
||
preg_match("/DROP (COLUMN )*(`(.*?)`)/i", $option, $matches);
|
||
if(strpos($createTableSql, $matches[2]) !== false) $errorSql .= $option . "\n";
|
||
}
|
||
}
|
||
}
|
||
echo $errorSql;
|
||
}
|
||
|
||
/**
|
||
* Check lang.
|
||
*
|
||
* @access public
|
||
* @return void
|
||
*/
|
||
public function checkLang()
|
||
{
|
||
`php check.php`;
|
||
}
|
||
|
||
/**
|
||
* Http.
|
||
*
|
||
* @param string $url
|
||
* @param string|array $data
|
||
* @param array $options This is option and value pair, like CURLOPT_HEADER => true. Use curl_setopt function to set options.
|
||
* @param array $headers Set request headers.
|
||
* @param string $dataType
|
||
* @param string $method POST|PATCH|PUT
|
||
* @access public
|
||
* @return string
|
||
*/
|
||
public function http($url, $data = null, $options = array(), $headers = array(), $dataType = 'data', $method = 'POST')
|
||
{
|
||
if(!is_array($headers)) $headers = (array)$headers;
|
||
if($dataType == 'json')
|
||
{
|
||
$headers[] = 'Content-Type: application/json;charset=utf-8';
|
||
if(!empty($data)) $data = json_encode($data);
|
||
}
|
||
|
||
$curl = curl_init();
|
||
curl_setopt($curl, CURLOPT_USERAGENT, 'Sae T OAuth2 v0.1');
|
||
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 30);
|
||
curl_setopt($curl, CURLOPT_TIMEOUT, 6000);
|
||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
|
||
curl_setopt($curl, CURLOPT_ENCODING, "");
|
||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
|
||
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
|
||
curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
|
||
curl_setopt($curl, CURLOPT_HEADER, false);
|
||
curl_setopt($curl, CURLINFO_HEADER_OUT, true);
|
||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||
curl_setopt($curl, CURLOPT_URL, $url);
|
||
|
||
if(!empty($data))
|
||
{
|
||
if(is_object($data)) $data = (array) $data;
|
||
if($method == 'POST') curl_setopt($curl, CURLOPT_POST, true);
|
||
if(in_array($method, array('PATCH', 'PUT'))) curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
|
||
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
|
||
}
|
||
|
||
if($options) curl_setopt_array($curl, $options);
|
||
$response = curl_exec($curl);
|
||
$errors = curl_error($curl);
|
||
|
||
curl_close($curl);
|
||
|
||
if($errors) return $errors;
|
||
|
||
return $response;
|
||
}
|
||
}
|