diff --git a/administrator/components/com_patchtester/PatchTester/Controller/ResetController.php b/administrator/components/com_patchtester/PatchTester/Controller/ResetController.php index c0b2fda..074c35f 100644 --- a/administrator/components/com_patchtester/PatchTester/Controller/ResetController.php +++ b/administrator/components/com_patchtester/PatchTester/Controller/ResetController.php @@ -13,7 +13,6 @@ use Joomla\CMS\Filesystem\Folder; use Joomla\CMS\Language\Text; use Joomla\CMS\Router\Route; use Joomla\Filesystem\File; -use PatchTester\Helper; use PatchTester\Model\PullModel; use PatchTester\Model\PullsModel; use PatchTester\Model\TestsModel; @@ -42,25 +41,10 @@ class ResetController extends AbstractController $pullsModel = new PullsModel($this->context, null, Factory::getDbo()); $testsModel = new TestsModel(null, Factory::getDbo()); - // Get the CIServer Registry - $ciSettings = Helper::initializeCISettings(); - - // Get PatchChain as array, remove any EOL set by php - $patchChainPath = $ciSettings->get('folder.backups') . '/' . $ciSettings->get('zip.chain.name'); - $patchChain = array_reverse(json_decode(file_get_contents($patchChainPath))); - // Check the applied patches in the database first - $appliedPatches = $testsModel->getAppliedPatches(); + $appliedPatches = $pullModel->getPatchesDividedInProcs(); - if (count($patchChain) && count($appliedPatches)) - { - // Get only the pull_id and remove all occurrences with patchChain - $appliedPatches = array_map(function($patch) { return $patch->id; }, $appliedPatches); - $patchChain = array_map(function($patch) { return $patch->id; }, $patchChain); - $appliedPatches = array_diff($appliedPatches, $patchChain); - } - - if (count($appliedPatches)) + if (count($appliedPatches[0])) { $revertErrored = false; @@ -69,7 +53,7 @@ class ResetController extends AbstractController { try { - $pullModel->revertWithGitHub($patch); + $pullModel->revertWithGitHub($patch->id); } catch (\RuntimeException $e) { @@ -78,16 +62,16 @@ class ResetController extends AbstractController } } - if (count($patchChain)) + if (count($appliedPatches[1])) { $revertErrored = false; // Let's try to cleanly revert all applied patches with ci - foreach ($patchChain as $patch) + foreach ($appliedPatches as $patch) { try { - $pullModel->revertWithCIServer($patch); + $pullModel->revertWithCIServer($patch->id); } catch (\RuntimeException $e) { diff --git a/administrator/components/com_patchtester/PatchTester/Model/PullModel.php b/administrator/components/com_patchtester/PatchTester/Model/PullModel.php index 04b97ad..cb3b832 100644 --- a/administrator/components/com_patchtester/PatchTester/Model/PullModel.php +++ b/administrator/components/com_patchtester/PatchTester/Model/PullModel.php @@ -208,7 +208,6 @@ class PullModel extends AbstractModel $tempPath = $ciSettings->get('folder.temp') . "/$id"; $backupsPath = $ciSettings->get('folder.backups') . "/$id"; - $patchChainPath = $ciSettings->get('folder.backups') . '/' . $ciSettings->get('zip.chain.name'); $delLogPath = $tempPath . '/' . $ciSettings->get('zip.log.name'); $zipPath = $tempPath . '/' . $ciSettings->get('zip.name'); @@ -319,17 +318,7 @@ class PullModel extends AbstractModel $lastInserted = $this->saveAppliedPatch($id, $files, $sha); // Write or create patch chain for correct order of patching - if (!file_exists($patchChainPath) || filesize($patchChainPath) === 0) - { - File::write($patchChainPath, json_encode([["id" => $lastInserted, "pull_id" => $id]])); - } - else - { - // Remove any from php set EOL in log file, add id and rewrite file - $patchChain = json_decode(file_get_contents($patchChainPath)); - $patchChain[] = ["id" => $lastInserted, "pull_id" => $id]; - File::write($patchChainPath, json_encode($patchChain)); - } + $this->appendPatchChain($lastInserted, $id); // Change the media version $version = new Version; @@ -626,18 +615,16 @@ class PullModel extends AbstractModel $testRecord = $this->getTestRecord($id); // Get PatchChain as array, remove any EOL set by php - $patchChainPath = $ciSettings->get('folder.backups') . '/' . $ciSettings->get('zip.chain.name'); - $patchChain = array_reverse(json_decode(file_get_contents($patchChainPath))); + $patchChain = $this->getLastChain(); // Allow only reverts in order of the patch chain - if ($patchChain[0]->id != $id) + if ($patchChain[0]->insert_id != $id) { throw new \RuntimeException(Text::sprintf('COM_PATCHTESTER_NOT_IN_ORDER_OF_PATCHCHAIN', $patchChain[0]->pull_id)); } else { - array_shift($patchChain); - File::write($patchChainPath, json_encode(array_reverse($patchChain))); + $this->removeLastChain($patchChain[0]->insert_id); } // We don't want to restore files from an older version @@ -867,4 +854,112 @@ class PullModel extends AbstractModel ->where('id = ' . (int) $id) )->loadObject(); } + + /** + * Retrieves a list of patches in chain + * + * @return mixed + * + * @since 3.0 + */ + private function getPatchChain() + { + $db = $this->getDb(); + + $db->setQuery( + $db->getQuery(true) + ->select('*') + ->from($db->quoteName('#__patchtester_chain')) + ->order('id DESC') + ); + + return $db->loadObjectList('pull_id'); + } + + /** + * Returns the last value of the ci patch chain + * + * @return stdClass $chain last chain of the table + * + * @since 3.0.0 + */ + private function getLastChain() + { + $db = $this->getDb(); + + return $db->setQuery( + $db->getQuery(true) + ->select('*') + ->from('#__patchtester_chain') + ->order('id DESC'), 0, 1 + )->loadObject(); + } + + /** + * Returns a two dimensional array with applied patches + * by the github or ci procedure + * + * @return array two-dimensional array with github patches + * and ci patches + * + * @since 3.0.0 + */ + public function getPatchesDividedInProcs() + { + $db = $this->getDb(); + + $appliedByGit = $db->setQuery( + $db->getQuery(true) + ->select('pulls.id, pulls.pull_id') + ->from('#__patchtester_chain chain') + ->leftJoin('#__patchtester_pulls pulls', 'chain.id != pulls.id') + )->loadObject(); + + $appliedByCI = $this->getPatchChain(); + + return [$appliedByGit, $appliedByCI]; + } + + /** + * Adds a value to the patch chain in the database + * + * @param integer $insertId ID of the patch in the database + * @param integer $pullId ID of the pull request + * + * @return integer $insertId last inserted element + * + * @since 3.0.0 + */ + private function appendPatchChain($insertId, $pullId) + { + $record = (object) array( + 'insert_id' => $insertId, + 'pull_id' => $pullId, + ); + + $db = $this->getDb(); + + $db->insertObject('#__patchtester_chain', $record); + return $db->insertid(); + } + + /** + * Removes the last value of the chain + * + * @param integer $insertId ID of the patch in the database + * + * @return void + * + * @since 3.0.0 + */ + private function removeLastChain($insertId) + { + $db = $this->getDb(); + + $db->setQuery( + $db->getQuery(true) + ->delete('#__patchtester_chain') + ->where('insert_id = ' . (int) $insertId) + )->execute(); + } } diff --git a/administrator/components/com_patchtester/install/sql/mysql/install.sql b/administrator/components/com_patchtester/install/sql/mysql/install.sql index 2210654..a76d520 100644 --- a/administrator/components/com_patchtester/install/sql/mysql/install.sql +++ b/administrator/components/com_patchtester/install/sql/mysql/install.sql @@ -19,3 +19,10 @@ CREATE TABLE IF NOT EXISTS `#__patchtester_tests` ( `applied_version` varchar(25) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS `#__patchtester_chain` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `insert_id` int(11) NOT NULL + `pull_id` int(11) NOT NULL + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_unicode_ci; diff --git a/administrator/components/com_patchtester/install/sql/mysql/uninstall.sql b/administrator/components/com_patchtester/install/sql/mysql/uninstall.sql index 3c1bf05..8f9a6b6 100644 --- a/administrator/components/com_patchtester/install/sql/mysql/uninstall.sql +++ b/administrator/components/com_patchtester/install/sql/mysql/uninstall.sql @@ -1,2 +1,3 @@ DROP TABLE IF EXISTS `#__patchtester_pulls`; DROP TABLE IF EXISTS `#__patchtester_tests`; +DROP TABLE IF EXISTS `#__patchtester_chain`; diff --git a/administrator/components/com_patchtester/install/sql/postgresql/install.sql b/administrator/components/com_patchtester/install/sql/postgresql/install.sql index 45c96ad..f000ca0 100644 --- a/administrator/components/com_patchtester/install/sql/postgresql/install.sql +++ b/administrator/components/com_patchtester/install/sql/postgresql/install.sql @@ -19,3 +19,10 @@ CREATE TABLE IF NOT EXISTS "#__patchtester_tests" ( "applied_version" character varying(25) NOT NULL, PRIMARY KEY ("id") ); + +CREATE TABLE IF NOT EXISTS "#__patchtester_chain" ( + "id" serial NOT NULL, + "insert_id" bigint NOT NULL, + "pull_id" bigint NOT NULL + PRIMARY KEY (`id`) +); diff --git a/administrator/components/com_patchtester/install/sql/postgresql/uninstall.sql b/administrator/components/com_patchtester/install/sql/postgresql/uninstall.sql index 9fcc3f6..a972c22 100644 --- a/administrator/components/com_patchtester/install/sql/postgresql/uninstall.sql +++ b/administrator/components/com_patchtester/install/sql/postgresql/uninstall.sql @@ -1,2 +1,3 @@ DROP TABLE IF EXISTS "#__patchtester_pulls"; DROP TABLE IF EXISTS "#__patchtester_tests"; +DROP TABLE IF EXISTS "#__patchtester_chain"; diff --git a/administrator/components/com_patchtester/install/sql/sqlsrv/install.sql b/administrator/components/com_patchtester/install/sql/sqlsrv/install.sql index ae89443..a6d5998 100644 --- a/administrator/components/com_patchtester/install/sql/sqlsrv/install.sql +++ b/administrator/components/com_patchtester/install/sql/sqlsrv/install.sql @@ -25,3 +25,13 @@ CREATE TABLE [#__patchtester_tests]( [id] ASC ) WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ); + +CREATE TABLE [#__patchtester_chain] ( + [id] [bigint] IDENTITY(1,1) NOT NULL, + [insert_id] [bigint] NOT NULL + [pull_id] [bigint] NOT NULL + CONSTRAINT [PK_#__patchtester_chain] PRIMARY KEY CLUSTERED +( + [id] ASC +) WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) +); diff --git a/administrator/components/com_patchtester/install/sql/sqlsrv/uninstall.sql b/administrator/components/com_patchtester/install/sql/sqlsrv/uninstall.sql index f396275..53c9b4e 100644 --- a/administrator/components/com_patchtester/install/sql/sqlsrv/uninstall.sql +++ b/administrator/components/com_patchtester/install/sql/sqlsrv/uninstall.sql @@ -1,2 +1,3 @@ DROP TABLE [#__patchtester_pulls]; DROP TABLE [#__patchtester_tests]; +DROP TABLE [#__patchtester_chain]; diff --git a/administrator/components/com_patchtester/install/sql/updates/mysql/4.0.0.sql b/administrator/components/com_patchtester/install/sql/updates/mysql/4.0.0.sql new file mode 100644 index 0000000..a92d4e8 --- /dev/null +++ b/administrator/components/com_patchtester/install/sql/updates/mysql/4.0.0.sql @@ -0,0 +1,6 @@ +CREATE TABLE IF NOT EXISTS `#__patchtester_chain` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `insert_id` int(11) NOT NULL + `pull_id` int(11) NOT NULL + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_unicode_ci; \ No newline at end of file diff --git a/administrator/components/com_patchtester/install/sql/updates/postgresql/4.0.0.sql b/administrator/components/com_patchtester/install/sql/updates/postgresql/4.0.0.sql new file mode 100644 index 0000000..83a2e6c --- /dev/null +++ b/administrator/components/com_patchtester/install/sql/updates/postgresql/4.0.0.sql @@ -0,0 +1,6 @@ +CREATE TABLE IF NOT EXISTS "#__patchtester_chain" ( + "id" serial NOT NULL, + "insert_id" bigint NOT NULL, + "pull_id" bigint NOT NULL + PRIMARY KEY (`id`) +); diff --git a/administrator/components/com_patchtester/install/sql/updates/sqlsrv/4.0.0.sql b/administrator/components/com_patchtester/install/sql/updates/sqlsrv/4.0.0.sql new file mode 100644 index 0000000..35049c7 --- /dev/null +++ b/administrator/components/com_patchtester/install/sql/updates/sqlsrv/4.0.0.sql @@ -0,0 +1,9 @@ +CREATE TABLE [#__patchtester_chain] ( + [id] [bigint] IDENTITY(1,1) NOT NULL, + [insert_id] [bigint] NOT NULL + [pull_id] [bigint] NOT NULL + CONSTRAINT [PK_#__patchtester_chain] PRIMARY KEY CLUSTERED +( + [id] ASC +) WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) +);