Files
EasySoft-ZenTaoPMS/tools/prepareupdate.php
2023-07-05 17:31:27 +08:00

461 lines
16 KiB
PHP
Executable File

<?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->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' => '旗舰版:');
$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 max version.
*
* @param object $lastMaxRelease
* @access public
* @return array
*/
public function getLastMaxVersion($lastMaxRelease)
{
$releaseParse = explode(' ', $lastMaxRelease->name);
$this->internalZT->lastMaxVersion = str_replace('.stable', '', $releaseParse[1]);
$this->internalZT->lastMaxVersionAB = str_replace('.', '_', $this->internalZT->lastMaxVersion);
}
/**
* Get pms, biz and max 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);
$this->getLastMaxVersion($maxReleases[1]);
return array('pms' => $pmsLatestRelease, 'biz' => $bizLatestRelease, 'max' => $maxLatestRelease);
}
/**
* 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;
`sed -i "s/\/\* Release Date. \*\/$/\/* Release Date. *\/\\n\\\$lang->misc->releaseDate['{$this->internalZT->pmsVersion}'] = '$date';/" ../module/misc/lang/zh-cn.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`;
/* Other lang. */
}
/**
* 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->lastMaxVersionAB}'] = 'Max{$this->internalZT->lastMaxVersion}'; \/\/ max 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`;
}
/**
* 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_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
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;
}
}