Files
EasySoft-ZenTaoPMS/misc/prepareupdate.php
2024-01-05 15:14:46 +08:00

465 lines
17 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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;
}
}